1 | /* Various declarations for language-independent diagnostics subroutines. |
2 | Copyright (C) 2000-2024 Free Software Foundation, Inc. |
3 | Contributed by Gabriel Dos Reis <gdr@codesourcery.com> |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #ifndef GCC_DIAGNOSTIC_H |
22 | #define GCC_DIAGNOSTIC_H |
23 | |
24 | #include "rich-location.h" |
25 | #include "pretty-print.h" |
26 | #include "diagnostic-core.h" |
27 | |
28 | namespace text_art |
29 | { |
30 | class theme; |
31 | } // namespace text_art |
32 | |
33 | /* An enum for controlling what units to use for the column number |
34 | when diagnostics are output, used by the -fdiagnostics-column-unit option. |
35 | Tabs will be expanded or not according to the value of -ftabstop. The origin |
36 | (default 1) is controlled by -fdiagnostics-column-origin. */ |
37 | |
38 | enum diagnostics_column_unit |
39 | { |
40 | /* The default from GCC 11 onwards: display columns. */ |
41 | DIAGNOSTICS_COLUMN_UNIT_DISPLAY, |
42 | |
43 | /* The behavior in GCC 10 and earlier: simple bytes. */ |
44 | DIAGNOSTICS_COLUMN_UNIT_BYTE |
45 | }; |
46 | |
47 | /* An enum for controlling how to print non-ASCII characters/bytes when |
48 | a diagnostic suggests escaping the source code on output. */ |
49 | |
50 | enum diagnostics_escape_format |
51 | { |
52 | /* Escape non-ASCII Unicode characters in the form <U+XXXX> and |
53 | non-UTF-8 bytes in the form <XX>. */ |
54 | DIAGNOSTICS_ESCAPE_FORMAT_UNICODE, |
55 | |
56 | /* Escape non-ASCII bytes in the form <XX> (thus showing the underlying |
57 | encoding of non-ASCII Unicode characters). */ |
58 | DIAGNOSTICS_ESCAPE_FORMAT_BYTES |
59 | }; |
60 | |
61 | /* Enum for overriding the standard output format. */ |
62 | |
63 | enum diagnostics_output_format |
64 | { |
65 | /* The default: textual output. */ |
66 | DIAGNOSTICS_OUTPUT_FORMAT_TEXT, |
67 | |
68 | /* JSON-based output, to stderr. */ |
69 | DIAGNOSTICS_OUTPUT_FORMAT_JSON_STDERR, |
70 | |
71 | /* JSON-based output, to a file. */ |
72 | DIAGNOSTICS_OUTPUT_FORMAT_JSON_FILE, |
73 | |
74 | /* SARIF-based output, to stderr. */ |
75 | DIAGNOSTICS_OUTPUT_FORMAT_SARIF_STDERR, |
76 | |
77 | /* SARIF-based output, to a file. */ |
78 | DIAGNOSTICS_OUTPUT_FORMAT_SARIF_FILE |
79 | }; |
80 | |
81 | /* An enum for controlling how diagnostic_paths should be printed. */ |
82 | enum diagnostic_path_format |
83 | { |
84 | /* Don't print diagnostic_paths. */ |
85 | DPF_NONE, |
86 | |
87 | /* Print diagnostic_paths by emitting a separate "note" for every event |
88 | in the path. */ |
89 | DPF_SEPARATE_EVENTS, |
90 | |
91 | /* Print diagnostic_paths by consolidating events together where they |
92 | are close enough, and printing such runs of events with multiple |
93 | calls to diagnostic_show_locus, showing the individual events in |
94 | each run via labels in the source. */ |
95 | DPF_INLINE_EVENTS |
96 | }; |
97 | |
98 | /* An enum for capturing values of GCC_EXTRA_DIAGNOSTIC_OUTPUT, |
99 | and for -fdiagnostics-parseable-fixits. */ |
100 | |
101 | enum |
102 | { |
103 | /* No extra output, or an unrecognized value. */ |
104 | , |
105 | |
106 | /* Emit fix-it hints using the "fixits-v1" format, equivalent to |
107 | -fdiagnostics-parseable-fixits. */ |
108 | , |
109 | |
110 | /* Emit fix-it hints using the "fixits-v2" format. */ |
111 | |
112 | }; |
113 | |
114 | /* Values for -fdiagnostics-text-art-charset=. */ |
115 | |
116 | enum diagnostic_text_art_charset |
117 | { |
118 | /* No text art diagrams shall be emitted. */ |
119 | DIAGNOSTICS_TEXT_ART_CHARSET_NONE, |
120 | |
121 | /* Use pure ASCII for text art diagrams. */ |
122 | DIAGNOSTICS_TEXT_ART_CHARSET_ASCII, |
123 | |
124 | /* Use ASCII + conservative use of other unicode characters |
125 | in text art diagrams. */ |
126 | DIAGNOSTICS_TEXT_ART_CHARSET_UNICODE, |
127 | |
128 | /* Use Emoji. */ |
129 | DIAGNOSTICS_TEXT_ART_CHARSET_EMOJI |
130 | }; |
131 | |
132 | /* A diagnostic is described by the MESSAGE to send, the FILE and LINE of |
133 | its context and its KIND (ice, error, warning, note, ...) See complete |
134 | list in diagnostic.def. */ |
135 | struct diagnostic_info |
136 | { |
137 | diagnostic_info () |
138 | : message (), richloc (), metadata (), x_data (), kind (), option_index (), |
139 | m_iinfo () |
140 | { } |
141 | |
142 | /* Text to be formatted. */ |
143 | text_info message; |
144 | |
145 | /* The location at which the diagnostic is to be reported. */ |
146 | rich_location *richloc; |
147 | |
148 | /* An optional bundle of metadata associated with the diagnostic |
149 | (or NULL). */ |
150 | const diagnostic_metadata *metadata; |
151 | |
152 | /* Auxiliary data for client. */ |
153 | void *x_data; |
154 | /* The kind of diagnostic it is about. */ |
155 | diagnostic_t kind; |
156 | /* Which OPT_* directly controls this diagnostic. */ |
157 | int option_index; |
158 | |
159 | /* Inlining context containing locations for each call site along |
160 | the inlining stack. */ |
161 | struct inlining_info |
162 | { |
163 | /* Locations along the inlining stack. */ |
164 | auto_vec<location_t, 8> m_ilocs; |
165 | /* The abstract origin of the location. */ |
166 | void *m_ao; |
167 | /* Set if every M_ILOCS element is in a system header. */ |
168 | bool m_allsyslocs; |
169 | } m_iinfo; |
170 | }; |
171 | |
172 | /* Forward declarations. */ |
173 | typedef void (*diagnostic_starter_fn) (diagnostic_context *, |
174 | const diagnostic_info *); |
175 | |
176 | typedef void (*diagnostic_start_span_fn) (diagnostic_context *, |
177 | expanded_location); |
178 | |
179 | typedef void (*diagnostic_finalizer_fn) (diagnostic_context *, |
180 | const diagnostic_info *, |
181 | diagnostic_t); |
182 | |
183 | typedef int (*diagnostic_option_enabled_cb) (int, unsigned, void *); |
184 | typedef char *(*diagnostic_make_option_name_cb) (const diagnostic_context *, |
185 | int, |
186 | diagnostic_t, |
187 | diagnostic_t); |
188 | typedef char *(*diagnostic_make_option_url_cb) (const diagnostic_context *, |
189 | int, |
190 | unsigned); |
191 | |
192 | class edit_context; |
193 | namespace json { class value; } |
194 | class diagnostic_client_data_hooks; |
195 | class logical_location; |
196 | class diagnostic_diagram; |
197 | |
198 | /* Abstract base class for a particular output format for diagnostics; |
199 | each value of -fdiagnostics-output-format= will have its own |
200 | implementation. */ |
201 | |
202 | class diagnostic_output_format |
203 | { |
204 | public: |
205 | virtual ~diagnostic_output_format () {} |
206 | |
207 | virtual void on_begin_group () = 0; |
208 | virtual void on_end_group () = 0; |
209 | virtual void on_begin_diagnostic (const diagnostic_info &) = 0; |
210 | virtual void on_end_diagnostic (const diagnostic_info &, |
211 | diagnostic_t orig_diag_kind) = 0; |
212 | virtual void on_diagram (const diagnostic_diagram &diagram) = 0; |
213 | virtual bool machine_readable_stderr_p () const = 0; |
214 | |
215 | protected: |
216 | diagnostic_output_format (diagnostic_context &context) |
217 | : m_context (context) |
218 | {} |
219 | |
220 | diagnostic_context &m_context; |
221 | }; |
222 | |
223 | /* Subclass of diagnostic_output_format for classic text-based output |
224 | to stderr. |
225 | |
226 | Uses diagnostic_context.m_text_callbacks to provide client-specific |
227 | textual output (e.g. include paths, macro expansions, etc). */ |
228 | |
229 | class diagnostic_text_output_format : public diagnostic_output_format |
230 | { |
231 | public: |
232 | diagnostic_text_output_format (diagnostic_context &context) |
233 | : diagnostic_output_format (context) |
234 | {} |
235 | ~diagnostic_text_output_format (); |
236 | void on_begin_group () override {} |
237 | void on_end_group () override {} |
238 | void on_begin_diagnostic (const diagnostic_info &) override; |
239 | void on_end_diagnostic (const diagnostic_info &, |
240 | diagnostic_t orig_diag_kind) override; |
241 | void on_diagram (const diagnostic_diagram &diagram) override; |
242 | bool machine_readable_stderr_p () const final override |
243 | { |
244 | return false; |
245 | } |
246 | }; |
247 | |
248 | /* A stack of sets of classifications: each entry in the stack is |
249 | a mapping from option index to diagnostic severity that can be changed |
250 | via pragmas. The stack can be pushed and popped. */ |
251 | |
252 | class diagnostic_option_classifier |
253 | { |
254 | public: |
255 | void init (int n_opts); |
256 | void fini (); |
257 | |
258 | /* Save all diagnostic classifications in a stack. */ |
259 | void push (); |
260 | |
261 | /* Restore the topmost classification set off the stack. If the stack |
262 | is empty, revert to the state based on command line parameters. */ |
263 | void pop (location_t where); |
264 | |
265 | bool option_unspecified_p (int opt) const |
266 | { |
267 | return get_current_override (opt) == DK_UNSPECIFIED; |
268 | } |
269 | |
270 | diagnostic_t get_current_override (int opt) const |
271 | { |
272 | gcc_assert (opt < m_n_opts); |
273 | return m_classify_diagnostic[opt]; |
274 | } |
275 | |
276 | diagnostic_t |
277 | classify_diagnostic (const diagnostic_context *context, |
278 | int option_index, |
279 | diagnostic_t new_kind, |
280 | location_t where); |
281 | |
282 | diagnostic_t |
283 | update_effective_level_from_pragmas (diagnostic_info *diagnostic) const; |
284 | |
285 | private: |
286 | /* Each time a diagnostic's classification is changed with a pragma, |
287 | we record the change and the location of the change in an array of |
288 | these structs. */ |
289 | struct diagnostic_classification_change_t |
290 | { |
291 | location_t location; |
292 | int option; |
293 | diagnostic_t kind; |
294 | }; |
295 | |
296 | int m_n_opts; |
297 | |
298 | /* For each option index that can be passed to warning() et al |
299 | (OPT_* from options.h when using this code with the core GCC |
300 | options), this array may contain a new kind that the diagnostic |
301 | should be changed to before reporting, or DK_UNSPECIFIED to leave |
302 | it as the reported kind, or DK_IGNORED to not report it at |
303 | all. */ |
304 | diagnostic_t *m_classify_diagnostic; |
305 | |
306 | /* History of all changes to the classifications above. This list |
307 | is stored in location-order, so we can search it, either |
308 | binary-wise or end-to-front, to find the most recent |
309 | classification for a given diagnostic, given the location of the |
310 | diagnostic. */ |
311 | diagnostic_classification_change_t *m_classification_history; |
312 | |
313 | /* The size of the above array. */ |
314 | int m_n_classification_history; |
315 | |
316 | /* For pragma push/pop. */ |
317 | int *m_push_list; |
318 | int m_n_push; |
319 | }; |
320 | |
321 | /* A bundle of options relating to printing the user's source code |
322 | (potentially with a margin, underlining, labels, etc). */ |
323 | |
324 | struct diagnostic_source_printing_options |
325 | { |
326 | /* True if we should print the source line with a caret indicating |
327 | the location. |
328 | Corresponds to -fdiagnostics-show-caret. */ |
329 | bool enabled; |
330 | |
331 | /* Maximum width of the source line printed. */ |
332 | int max_width; |
333 | |
334 | /* Character used at the caret when printing source locations. */ |
335 | char caret_chars[rich_location::STATICALLY_ALLOCATED_RANGES]; |
336 | |
337 | /* When printing source code, should the characters at carets and ranges |
338 | be colorized? (assuming colorization is on at all). |
339 | This should be true for frontends that generate range information |
340 | (so that the ranges of code are colorized), |
341 | and false for frontends that merely specify points within the |
342 | source code (to avoid e.g. colorizing just the first character in |
343 | a token, which would look strange). */ |
344 | bool colorize_source_p; |
345 | |
346 | /* When printing source code, should labelled ranges be printed? |
347 | Corresponds to -fdiagnostics-show-labels. */ |
348 | bool show_labels_p; |
349 | |
350 | /* When printing source code, should there be a left-hand margin |
351 | showing line numbers? |
352 | Corresponds to -fdiagnostics-show-line-numbers. */ |
353 | bool show_line_numbers_p; |
354 | |
355 | /* If printing source code, what should the minimum width of the margin |
356 | be? Line numbers will be right-aligned, and padded to this width. |
357 | Corresponds to -fdiagnostics-minimum-margin-width=VALUE. */ |
358 | int min_margin_width; |
359 | |
360 | /* Usable by plugins; if true, print a debugging ruler above the |
361 | source output. */ |
362 | bool show_ruler_p; |
363 | }; |
364 | |
365 | /* This data structure bundles altogether any information relevant to |
366 | the context of a diagnostic message. */ |
367 | class diagnostic_context |
368 | { |
369 | public: |
370 | /* Give access to m_text_callbacks. */ |
371 | friend diagnostic_starter_fn & |
372 | diagnostic_starter (diagnostic_context *context); |
373 | friend diagnostic_start_span_fn & |
374 | diagnostic_start_span (diagnostic_context *context); |
375 | friend diagnostic_finalizer_fn & |
376 | diagnostic_finalizer (diagnostic_context *context); |
377 | |
378 | typedef void (*ice_handler_callback_t) (diagnostic_context *); |
379 | typedef void (*set_locations_callback_t) (diagnostic_context *, |
380 | diagnostic_info *); |
381 | |
382 | void initialize (int n_opts); |
383 | void color_init (int value); |
384 | void urls_init (int value); |
385 | |
386 | void finish (); |
387 | |
388 | void set_set_locations_callback (set_locations_callback_t cb) |
389 | { |
390 | m_set_locations_cb = cb; |
391 | } |
392 | |
393 | void |
394 | initialize_input_context (diagnostic_input_charset_callback ccb, |
395 | bool should_skip_bom); |
396 | |
397 | void begin_group (); |
398 | void end_group (); |
399 | |
400 | bool warning_enabled_at (location_t loc, int opt); |
401 | |
402 | bool option_unspecified_p (int opt) const |
403 | { |
404 | return m_option_classifier.option_unspecified_p (opt); |
405 | } |
406 | |
407 | bool report_diagnostic (diagnostic_info *); |
408 | |
409 | void report_current_module (location_t where); |
410 | |
411 | void check_max_errors (bool flush); |
412 | void action_after_output (diagnostic_t diag_kind); |
413 | |
414 | diagnostic_t |
415 | classify_diagnostic (int option_index, |
416 | diagnostic_t new_kind, |
417 | location_t where) |
418 | { |
419 | return m_option_classifier.classify_diagnostic (context: this, |
420 | option_index, |
421 | new_kind, |
422 | where); |
423 | } |
424 | |
425 | void push_diagnostics (location_t where ATTRIBUTE_UNUSED) |
426 | { |
427 | m_option_classifier.push (); |
428 | } |
429 | void pop_diagnostics (location_t where) |
430 | { |
431 | m_option_classifier.pop (where); |
432 | } |
433 | |
434 | void maybe_show_locus (const rich_location &richloc, |
435 | diagnostic_t diagnostic_kind, |
436 | pretty_printer *pp); |
437 | |
438 | void emit_diagram (const diagnostic_diagram &diagram); |
439 | |
440 | const diagnostic_output_format *get_output_format () const |
441 | { |
442 | return m_output_format; |
443 | } |
444 | |
445 | /* Various setters for use by option-handling logic. */ |
446 | void set_output_format (diagnostic_output_format *output_format); |
447 | void set_text_art_charset (enum diagnostic_text_art_charset charset); |
448 | void set_client_data_hooks (diagnostic_client_data_hooks *hooks); |
449 | void set_urlifier (urlifier *); |
450 | void create_edit_context (); |
451 | void set_warning_as_error_requested (bool val) |
452 | { |
453 | m_warning_as_error_requested = val; |
454 | } |
455 | void set_report_bug (bool val) { m_report_bug = val; } |
456 | void (enum diagnostics_extra_output_kind kind) |
457 | { |
458 | m_extra_output_kind = kind; |
459 | } |
460 | void set_show_cwe (bool val) { m_show_cwe = val; } |
461 | void set_show_rules (bool val) { m_show_rules = val; } |
462 | void set_path_format (enum diagnostic_path_format val) |
463 | { |
464 | m_path_format = val; |
465 | } |
466 | void set_show_path_depths (bool val) { m_show_path_depths = val; } |
467 | void set_show_option_requested (bool val) { m_show_option_requested = val; } |
468 | void set_max_errors (int val) { m_max_errors = val; } |
469 | void set_escape_format (enum diagnostics_escape_format val) |
470 | { |
471 | m_escape_format = val; |
472 | } |
473 | void set_ice_handler_callback (ice_handler_callback_t cb) |
474 | { |
475 | m_ice_handler_cb = cb; |
476 | } |
477 | |
478 | /* Various accessors. */ |
479 | bool warning_as_error_requested_p () const |
480 | { |
481 | return m_warning_as_error_requested; |
482 | } |
483 | bool show_path_depths_p () const { return m_show_path_depths; } |
484 | enum diagnostic_path_format get_path_format () const { return m_path_format; } |
485 | enum diagnostics_escape_format get_escape_format () const |
486 | { |
487 | return m_escape_format; |
488 | } |
489 | |
490 | file_cache & |
491 | get_file_cache () const |
492 | { |
493 | gcc_assert (m_file_cache); |
494 | return *m_file_cache; |
495 | } |
496 | |
497 | edit_context *get_edit_context () const |
498 | { |
499 | return m_edit_context_ptr; |
500 | } |
501 | const diagnostic_client_data_hooks *get_client_data_hooks () |
502 | { |
503 | return m_client_data_hooks; |
504 | } |
505 | text_art::theme *get_diagram_theme () const { return m_diagrams.m_theme; } |
506 | |
507 | int converted_column (expanded_location s) const; |
508 | |
509 | int &diagnostic_count (diagnostic_t kind) |
510 | { |
511 | return m_diagnostic_count[kind]; |
512 | } |
513 | |
514 | /* Option-related member functions. */ |
515 | inline bool option_enabled_p (int option_index) const |
516 | { |
517 | if (!m_option_callbacks.m_option_enabled_cb) |
518 | return true; |
519 | return m_option_callbacks.m_option_enabled_cb |
520 | (option_index, |
521 | m_option_callbacks.m_lang_mask, |
522 | m_option_callbacks.m_option_state); |
523 | } |
524 | |
525 | inline char *make_option_name (int option_index, |
526 | diagnostic_t orig_diag_kind, |
527 | diagnostic_t diag_kind) const |
528 | { |
529 | if (!m_option_callbacks.m_make_option_name_cb) |
530 | return nullptr; |
531 | return m_option_callbacks.m_make_option_name_cb (this, option_index, |
532 | orig_diag_kind, |
533 | diag_kind); |
534 | } |
535 | |
536 | inline char *make_option_url (int option_index) const |
537 | { |
538 | if (!m_option_callbacks.m_make_option_url_cb) |
539 | return nullptr; |
540 | return m_option_callbacks.m_make_option_url_cb (this, option_index, |
541 | get_lang_mask ()); |
542 | } |
543 | |
544 | void |
545 | set_option_hooks (diagnostic_option_enabled_cb option_enabled_cb, |
546 | void *option_state, |
547 | diagnostic_make_option_name_cb make_option_name_cb, |
548 | diagnostic_make_option_url_cb make_option_url_cb, |
549 | unsigned lang_mask); |
550 | |
551 | unsigned get_lang_mask () const |
552 | { |
553 | return m_option_callbacks.m_lang_mask; |
554 | } |
555 | |
556 | label_text get_location_text (const expanded_location &s) const; |
557 | |
558 | private: |
559 | bool includes_seen_p (const line_map_ordinary *map); |
560 | |
561 | void print_any_cwe (const diagnostic_info &diagnostic); |
562 | void print_any_rules (const diagnostic_info &diagnostic); |
563 | void print_option_information (const diagnostic_info &diagnostic, |
564 | diagnostic_t orig_diag_kind); |
565 | |
566 | void show_any_path (const diagnostic_info &diagnostic); |
567 | |
568 | void error_recursion () ATTRIBUTE_NORETURN; |
569 | |
570 | bool diagnostic_enabled (diagnostic_info *diagnostic); |
571 | |
572 | void get_any_inlining_info (diagnostic_info *diagnostic); |
573 | |
574 | void show_locus (const rich_location &richloc, |
575 | diagnostic_t diagnostic_kind, |
576 | pretty_printer *pp); |
577 | |
578 | /* Data members. |
579 | Ideally, all of these would be private and have "m_" prefixes. */ |
580 | |
581 | public: |
582 | /* Where most of the diagnostic formatting work is done. */ |
583 | pretty_printer *printer; |
584 | |
585 | private: |
586 | /* Cache of source code. */ |
587 | file_cache *m_file_cache; |
588 | |
589 | /* The number of times we have issued diagnostics. */ |
590 | int m_diagnostic_count[DK_LAST_DIAGNOSTIC_KIND]; |
591 | |
592 | /* True if it has been requested that warnings be treated as errors. */ |
593 | bool m_warning_as_error_requested; |
594 | |
595 | /* The number of option indexes that can be passed to warning() et |
596 | al. */ |
597 | int m_n_opts; |
598 | |
599 | /* The stack of sets of overridden diagnostic option severities. */ |
600 | diagnostic_option_classifier m_option_classifier; |
601 | |
602 | /* True if we should print any CWE identifiers associated with |
603 | diagnostics. */ |
604 | bool m_show_cwe; |
605 | |
606 | /* True if we should print any rules associated with diagnostics. */ |
607 | bool m_show_rules; |
608 | |
609 | /* How should diagnostic_path objects be printed. */ |
610 | enum diagnostic_path_format m_path_format; |
611 | |
612 | /* True if we should print stack depths when printing diagnostic paths. */ |
613 | bool m_show_path_depths; |
614 | |
615 | /* True if we should print the command line option which controls |
616 | each diagnostic, if known. */ |
617 | bool m_show_option_requested; |
618 | |
619 | public: |
620 | /* True if we should raise a SIGABRT on errors. */ |
621 | bool m_abort_on_error; |
622 | |
623 | /* True if we should show the column number on diagnostics. */ |
624 | bool m_show_column; |
625 | |
626 | /* True if pedwarns are errors. */ |
627 | bool m_pedantic_errors; |
628 | |
629 | /* True if permerrors are warnings. */ |
630 | bool m_permissive; |
631 | |
632 | /* The index of the option to associate with turning permerrors into |
633 | warnings. */ |
634 | int m_opt_permissive; |
635 | |
636 | /* True if errors are fatal. */ |
637 | bool m_fatal_errors; |
638 | |
639 | /* True if all warnings should be disabled. */ |
640 | bool m_inhibit_warnings; |
641 | |
642 | /* True if warnings should be given in system headers. */ |
643 | bool ; |
644 | |
645 | private: |
646 | /* Maximum number of errors to report. */ |
647 | int m_max_errors; |
648 | |
649 | /* Client-supplied callbacks for use in text output. */ |
650 | struct { |
651 | /* This function is called before any message is printed out. It is |
652 | responsible for preparing message prefix and such. For example, it |
653 | might say: |
654 | In file included from "/usr/local/include/curses.h:5: |
655 | from "/home/gdr/src/nifty_printer.h:56: |
656 | ... |
657 | */ |
658 | diagnostic_starter_fn m_begin_diagnostic; |
659 | |
660 | /* This function is called by diagnostic_show_locus in between |
661 | disjoint spans of source code, so that the context can print |
662 | something to indicate that a new span of source code has begun. */ |
663 | diagnostic_start_span_fn m_start_span; |
664 | |
665 | /* This function is called after the diagnostic message is printed. */ |
666 | diagnostic_finalizer_fn m_end_diagnostic; |
667 | } m_text_callbacks; |
668 | |
669 | public: |
670 | /* Client hook to report an internal error. */ |
671 | void (*m_internal_error) (diagnostic_context *, const char *, va_list *); |
672 | |
673 | private: |
674 | /* Client-supplied callbacks for working with options. */ |
675 | struct { |
676 | /* Client hook to say whether the option controlling a diagnostic is |
677 | enabled. Returns nonzero if enabled, zero if disabled. */ |
678 | diagnostic_option_enabled_cb m_option_enabled_cb; |
679 | |
680 | /* Client information to pass as second argument to |
681 | m_option_enabled_cb. */ |
682 | void *m_option_state; |
683 | |
684 | /* Client hook to return the name of an option that controls a |
685 | diagnostic. Returns malloced memory. The first diagnostic_t |
686 | argument is the kind of diagnostic before any reclassification |
687 | (of warnings as errors, etc.); the second is the kind after any |
688 | reclassification. May return NULL if no name is to be printed. |
689 | May be passed 0 as well as the index of a particular option. */ |
690 | diagnostic_make_option_name_cb m_make_option_name_cb; |
691 | |
692 | /* Client hook to return a URL describing the option that controls |
693 | a diagnostic. Returns malloced memory. May return NULL if no URL |
694 | is available. May be passed 0 as well as the index of a |
695 | particular option. */ |
696 | diagnostic_make_option_url_cb m_make_option_url_cb; |
697 | |
698 | /* A copy of lang_hooks.option_lang_mask (). */ |
699 | unsigned m_lang_mask; |
700 | } m_option_callbacks; |
701 | |
702 | /* An optional hook for adding URLs to quoted text strings in |
703 | diagnostics. Only used for the main diagnostic message. */ |
704 | urlifier *m_urlifier; |
705 | |
706 | public: |
707 | void (*m_print_path) (diagnostic_context *, const diagnostic_path *); |
708 | json::value *(*m_make_json_for_path) (diagnostic_context *, |
709 | const diagnostic_path *); |
710 | |
711 | /* Auxiliary data for client. */ |
712 | void *m_client_aux_data; |
713 | |
714 | /* Used to detect that the last caret was printed at the same location. */ |
715 | location_t m_last_location; |
716 | |
717 | private: |
718 | /* Used to detect when the input file stack has changed since last |
719 | described. */ |
720 | const line_map_ordinary *m_last_module; |
721 | |
722 | int m_lock; |
723 | |
724 | public: |
725 | bool m_inhibit_notes_p; |
726 | |
727 | diagnostic_source_printing_options m_source_printing; |
728 | |
729 | private: |
730 | /* True if -freport-bug option is used. */ |
731 | bool m_report_bug; |
732 | |
733 | /* Used to specify additional diagnostic output to be emitted after the |
734 | rest of the diagnostic. This is for implementing |
735 | -fdiagnostics-parseable-fixits and GCC_EXTRA_DIAGNOSTIC_OUTPUT. */ |
736 | enum diagnostics_extra_output_kind ; |
737 | |
738 | public: |
739 | /* What units to use when outputting the column number. */ |
740 | enum diagnostics_column_unit m_column_unit; |
741 | |
742 | /* The origin for the column number (1-based or 0-based typically). */ |
743 | int m_column_origin; |
744 | |
745 | /* The size of the tabstop for tab expansion. */ |
746 | int m_tabstop; |
747 | |
748 | private: |
749 | /* How should non-ASCII/non-printable bytes be escaped when |
750 | a diagnostic suggests escaping the source code on output. */ |
751 | enum diagnostics_escape_format m_escape_format; |
752 | |
753 | /* If non-NULL, an edit_context to which fix-it hints should be |
754 | applied, for generating patches. */ |
755 | edit_context *m_edit_context_ptr; |
756 | |
757 | /* Fields relating to diagnostic groups. */ |
758 | struct { |
759 | /* How many diagnostic_group instances are currently alive. */ |
760 | int m_nesting_depth; |
761 | |
762 | /* How many diagnostics have been emitted since the bottommost |
763 | diagnostic_group was pushed. */ |
764 | int m_emission_count; |
765 | } m_diagnostic_groups; |
766 | |
767 | /* How to output diagnostics (text vs a structured format such as JSON). |
768 | Must be non-NULL; owned by context. */ |
769 | diagnostic_output_format *m_output_format; |
770 | |
771 | /* Callback to set the locations of call sites along the inlining |
772 | stack corresponding to a diagnostic location. Needed to traverse |
773 | the BLOCK_SUPERCONTEXT() chain hanging off the LOCATION_BLOCK() |
774 | of a diagnostic's location. */ |
775 | set_locations_callback_t m_set_locations_cb; |
776 | |
777 | /* Optional callback for attempting to handle ICEs gracefully. */ |
778 | ice_handler_callback_t m_ice_handler_cb; |
779 | |
780 | /* Include files that diagnostic_report_current_module has already listed the |
781 | include path for. */ |
782 | hash_set<location_t, false, location_hash> *m_includes_seen; |
783 | |
784 | /* A bundle of hooks for providing data to the context about its client |
785 | e.g. version information, plugins, etc. |
786 | Used by SARIF output to give metadata about the client that's |
787 | producing diagnostics. */ |
788 | diagnostic_client_data_hooks *m_client_data_hooks; |
789 | |
790 | /* Support for diagrams. */ |
791 | struct |
792 | { |
793 | /* Theme to use when generating diagrams. |
794 | Can be NULL (if text art is disabled). */ |
795 | text_art::theme *m_theme; |
796 | |
797 | } m_diagrams; |
798 | }; |
799 | |
800 | inline void |
801 | diagnostic_inhibit_notes (diagnostic_context * context) |
802 | { |
803 | context->m_inhibit_notes_p = true; |
804 | } |
805 | |
806 | |
807 | /* Client supplied function to announce a diagnostic |
808 | (for text-based diagnostic output). */ |
809 | inline diagnostic_starter_fn & |
810 | diagnostic_starter (diagnostic_context *context) |
811 | { |
812 | return context->m_text_callbacks.m_begin_diagnostic; |
813 | } |
814 | |
815 | /* Client supplied function called between disjoint spans of source code, |
816 | so that the context can print |
817 | something to indicate that a new span of source code has begun. */ |
818 | inline diagnostic_start_span_fn & |
819 | diagnostic_start_span (diagnostic_context *context) |
820 | { |
821 | return context->m_text_callbacks.m_start_span; |
822 | } |
823 | |
824 | /* Client supplied function called after a diagnostic message is |
825 | displayed (for text-based diagnostic output). */ |
826 | inline diagnostic_finalizer_fn & |
827 | diagnostic_finalizer (diagnostic_context *context) |
828 | { |
829 | return context->m_text_callbacks.m_end_diagnostic; |
830 | } |
831 | |
832 | /* Extension hooks for client. */ |
833 | #define diagnostic_context_auxiliary_data(DC) (DC)->m_client_aux_data |
834 | #define diagnostic_info_auxiliary_data(DI) (DI)->x_data |
835 | |
836 | /* Same as pp_format_decoder. Works on 'diagnostic_context *'. */ |
837 | #define diagnostic_format_decoder(DC) ((DC)->printer->format_decoder) |
838 | |
839 | /* Same as output_prefixing_rule. Works on 'diagnostic_context *'. */ |
840 | #define diagnostic_prefixing_rule(DC) ((DC)->printer->wrapping.rule) |
841 | |
842 | /* Raise SIGABRT on any diagnostic of severity DK_ERROR or higher. */ |
843 | inline void |
844 | diagnostic_abort_on_error (diagnostic_context *context) |
845 | { |
846 | context->m_abort_on_error = true; |
847 | } |
848 | |
849 | /* This diagnostic_context is used by front-ends that directly output |
850 | diagnostic messages without going through `error', `warning', |
851 | and similar functions. */ |
852 | extern diagnostic_context *global_dc; |
853 | |
854 | /* Returns whether the diagnostic framework has been intialized already and is |
855 | ready for use. */ |
856 | inline bool |
857 | diagnostic_ready_p () |
858 | { |
859 | return global_dc->printer != nullptr; |
860 | } |
861 | |
862 | /* The number of errors that have been issued so far. Ideally, these |
863 | would take a diagnostic_context as an argument. */ |
864 | #define errorcount global_dc->diagnostic_count (DK_ERROR) |
865 | /* Similarly, but for warnings. */ |
866 | #define warningcount global_dc->diagnostic_count (DK_WARNING) |
867 | /* Similarly, but for warnings promoted to errors. */ |
868 | #define werrorcount global_dc->diagnostic_count (DK_WERROR) |
869 | /* Similarly, but for sorrys. */ |
870 | #define sorrycount global_dc->diagnostic_count (DK_SORRY) |
871 | |
872 | /* Returns nonzero if warnings should be emitted. */ |
873 | #define diagnostic_report_warnings_p(DC, LOC) \ |
874 | (!(DC)->m_inhibit_warnings \ |
875 | && !(in_system_header_at (LOC) && !(DC)->m_warn_system_headers)) |
876 | |
877 | /* Override the option index to be used for reporting a |
878 | diagnostic. */ |
879 | |
880 | inline void |
881 | diagnostic_override_option_index (diagnostic_info *info, int optidx) |
882 | { |
883 | info->option_index = optidx; |
884 | } |
885 | |
886 | /* Diagnostic related functions. */ |
887 | |
888 | inline void |
889 | diagnostic_initialize (diagnostic_context *context, int n_opts) |
890 | { |
891 | context->initialize (n_opts); |
892 | } |
893 | |
894 | inline void |
895 | diagnostic_color_init (diagnostic_context *context, int value = -1) |
896 | { |
897 | context->color_init (value); |
898 | } |
899 | |
900 | inline void |
901 | diagnostic_urls_init (diagnostic_context *context, int value = -1) |
902 | { |
903 | context->urls_init (value); |
904 | } |
905 | |
906 | inline void |
907 | diagnostic_finish (diagnostic_context *context) |
908 | { |
909 | context->finish (); |
910 | } |
911 | |
912 | inline void |
913 | diagnostic_report_current_module (diagnostic_context *context, |
914 | location_t where) |
915 | { |
916 | context->report_current_module (where); |
917 | } |
918 | |
919 | inline void |
920 | diagnostic_show_locus (diagnostic_context *context, |
921 | rich_location *richloc, |
922 | diagnostic_t diagnostic_kind, |
923 | pretty_printer *pp = nullptr) |
924 | { |
925 | gcc_assert (richloc); |
926 | context->maybe_show_locus (richloc: *richloc, diagnostic_kind, pp); |
927 | } |
928 | |
929 | /* Because we read source files a second time after the frontend did it the |
930 | first time, we need to know how the frontend handled things like character |
931 | set conversion and UTF-8 BOM stripping, in order to make everything |
932 | consistent. This function needs to be called by each frontend that requires |
933 | non-default behavior, to inform the diagnostics infrastructure how input is |
934 | to be processed. The default behavior is to do no conversion and not to |
935 | strip a UTF-8 BOM. |
936 | |
937 | The callback should return the input charset to be used to convert the given |
938 | file's contents to UTF-8, or it should return NULL if no conversion is needed |
939 | for this file. SHOULD_SKIP_BOM only applies in case no conversion was |
940 | performed, and if true, it will cause a UTF-8 BOM to be skipped at the |
941 | beginning of the file. (In case a conversion was performed, the BOM is |
942 | rather skipped as part of the conversion process.) */ |
943 | |
944 | inline void |
945 | diagnostic_initialize_input_context (diagnostic_context *context, |
946 | diagnostic_input_charset_callback ccb, |
947 | bool should_skip_bom) |
948 | { |
949 | context->initialize_input_context (ccb, should_skip_bom); |
950 | } |
951 | |
952 | /* Force diagnostics controlled by OPTIDX to be kind KIND. */ |
953 | inline diagnostic_t |
954 | diagnostic_classify_diagnostic (diagnostic_context *context, |
955 | int optidx, |
956 | diagnostic_t kind, |
957 | location_t where) |
958 | { |
959 | return context->classify_diagnostic (option_index: optidx, new_kind: kind, where); |
960 | } |
961 | |
962 | inline void |
963 | diagnostic_push_diagnostics (diagnostic_context *context, |
964 | location_t where) |
965 | { |
966 | context->push_diagnostics (where); |
967 | } |
968 | inline void |
969 | diagnostic_pop_diagnostics (diagnostic_context *context, |
970 | location_t where) |
971 | { |
972 | context->pop_diagnostics (where); |
973 | } |
974 | |
975 | /* Report a diagnostic message (an error or a warning) as specified by |
976 | DC. This function is *the* subroutine in terms of which front-ends |
977 | should implement their specific diagnostic handling modules. The |
978 | front-end independent format specifiers are exactly those described |
979 | in the documentation of output_format. |
980 | Return true if a diagnostic was printed, false otherwise. */ |
981 | |
982 | inline bool |
983 | diagnostic_report_diagnostic (diagnostic_context *context, |
984 | diagnostic_info *diagnostic) |
985 | { |
986 | return context->report_diagnostic (diagnostic); |
987 | } |
988 | |
989 | #ifdef ATTRIBUTE_GCC_DIAG |
990 | extern void diagnostic_set_info (diagnostic_info *, const char *, va_list *, |
991 | rich_location *, diagnostic_t) ATTRIBUTE_GCC_DIAG(2,0); |
992 | extern void diagnostic_set_info_translated (diagnostic_info *, const char *, |
993 | va_list *, rich_location *, |
994 | diagnostic_t) |
995 | ATTRIBUTE_GCC_DIAG(2,0); |
996 | extern void diagnostic_append_note (diagnostic_context *, location_t, |
997 | const char *, ...) ATTRIBUTE_GCC_DIAG(3,4); |
998 | #endif |
999 | extern char *diagnostic_build_prefix (diagnostic_context *, const diagnostic_info *); |
1000 | void default_diagnostic_starter (diagnostic_context *, const diagnostic_info *); |
1001 | void default_diagnostic_start_span_fn (diagnostic_context *, |
1002 | expanded_location); |
1003 | void default_diagnostic_finalizer (diagnostic_context *, |
1004 | const diagnostic_info *, |
1005 | diagnostic_t); |
1006 | void diagnostic_set_caret_max_width (diagnostic_context *context, int value); |
1007 | |
1008 | inline void |
1009 | diagnostic_action_after_output (diagnostic_context *context, |
1010 | diagnostic_t diag_kind) |
1011 | { |
1012 | context->action_after_output (diag_kind); |
1013 | } |
1014 | |
1015 | inline void |
1016 | diagnostic_check_max_errors (diagnostic_context *context, bool flush = false) |
1017 | { |
1018 | context->check_max_errors (flush); |
1019 | } |
1020 | |
1021 | int get_terminal_width (void); |
1022 | |
1023 | /* Return the location associated to this diagnostic. Parameter WHICH |
1024 | specifies which location. By default, expand the first one. */ |
1025 | |
1026 | inline location_t |
1027 | diagnostic_location (const diagnostic_info * diagnostic, int which = 0) |
1028 | { |
1029 | return diagnostic->message.get_location (index_of_location: which); |
1030 | } |
1031 | |
1032 | /* Return the number of locations to be printed in DIAGNOSTIC. */ |
1033 | |
1034 | inline unsigned int |
1035 | diagnostic_num_locations (const diagnostic_info * diagnostic) |
1036 | { |
1037 | return diagnostic->message.m_richloc->get_num_locations (); |
1038 | } |
1039 | |
1040 | /* Expand the location of this diagnostic. Use this function for |
1041 | consistency. Parameter WHICH specifies which location. By default, |
1042 | expand the first one. */ |
1043 | |
1044 | inline expanded_location |
1045 | diagnostic_expand_location (const diagnostic_info * diagnostic, int which = 0) |
1046 | { |
1047 | return diagnostic->richloc->get_expanded_location (idx: which); |
1048 | } |
1049 | |
1050 | /* This is somehow the right-side margin of a caret line, that is, we |
1051 | print at least these many characters after the position pointed at |
1052 | by the caret. */ |
1053 | const int CARET_LINE_MARGIN = 10; |
1054 | |
1055 | /* Return true if the two locations can be represented within the same |
1056 | caret line. This is used to build a prefix and also to determine |
1057 | whether to print one or two caret lines. */ |
1058 | |
1059 | inline bool |
1060 | diagnostic_same_line (const diagnostic_context *context, |
1061 | expanded_location s1, expanded_location s2) |
1062 | { |
1063 | return (s2.column && s1.line == s2.line |
1064 | && (context->m_source_printing.max_width - CARET_LINE_MARGIN |
1065 | > abs (x: s1.column - s2.column))); |
1066 | } |
1067 | |
1068 | extern const char *diagnostic_get_color_for_kind (diagnostic_t kind); |
1069 | |
1070 | /* Pure text formatting support functions. */ |
1071 | extern char *file_name_as_prefix (diagnostic_context *, const char *); |
1072 | |
1073 | extern char *build_message_string (const char *, ...) ATTRIBUTE_PRINTF_1; |
1074 | |
1075 | extern void diagnostic_output_format_init (diagnostic_context *, |
1076 | const char *base_file_name, |
1077 | enum diagnostics_output_format, |
1078 | bool json_formatting); |
1079 | extern void diagnostic_output_format_init_json_stderr (diagnostic_context *context, |
1080 | bool formatted); |
1081 | extern void diagnostic_output_format_init_json_file (diagnostic_context *context, |
1082 | bool formatted, |
1083 | const char *base_file_name); |
1084 | extern void diagnostic_output_format_init_sarif_stderr (diagnostic_context *context, |
1085 | bool formatted); |
1086 | extern void diagnostic_output_format_init_sarif_file (diagnostic_context *context, |
1087 | bool formatted, |
1088 | const char *base_file_name); |
1089 | extern void diagnostic_output_format_init_sarif_stream (diagnostic_context *context, |
1090 | bool formatted, |
1091 | FILE *stream); |
1092 | |
1093 | /* Compute the number of digits in the decimal representation of an integer. */ |
1094 | extern int num_digits (int); |
1095 | |
1096 | extern json::value *json_from_expanded_location (diagnostic_context *context, |
1097 | location_t loc); |
1098 | |
1099 | inline bool |
1100 | warning_enabled_at (location_t loc, int opt) |
1101 | { |
1102 | return global_dc->warning_enabled_at (loc, opt); |
1103 | } |
1104 | |
1105 | inline bool |
1106 | option_unspecified_p (int opt) |
1107 | { |
1108 | return global_dc->option_unspecified_p (opt); |
1109 | } |
1110 | |
1111 | extern char *get_cwe_url (int cwe); |
1112 | |
1113 | #endif /* ! GCC_DIAGNOSTIC_H */ |
1114 | |