OpenMP: Update documentation of metadirective implementation status.
[gcc.git] / gcc / diagnostic-format-text.cc
blob9273973baaf176065ff6a194a572443acaa9e28c
1 /* Classic text-based output of diagnostics.
2 Copyright (C) 1999-2025 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
16 You should have received a copy of the GNU General Public License
17 along with GCC; see the file COPYING3. If not see
18 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #define INCLUDE_VECTOR
23 #include "system.h"
24 #include "coretypes.h"
25 #include "version.h"
26 #include "intl.h"
27 #include "diagnostic.h"
28 #include "diagnostic-color.h"
29 #include "diagnostic-url.h"
30 #include "diagnostic-metadata.h"
31 #include "diagnostic-path.h"
32 #include "diagnostic-client-data-hooks.h"
33 #include "diagnostic-diagram.h"
34 #include "diagnostic-format-text.h"
35 #include "diagnostic-buffer.h"
36 #include "text-art/theme.h"
37 #include "make-unique.h"
39 /* Disable warnings about quoting issues in the pp_xxx calls below
40 that (intentionally) don't follow GCC diagnostic conventions. */
41 #if __GNUC__ >= 10
42 # pragma GCC diagnostic push
43 # pragma GCC diagnostic ignored "-Wformat-diag"
44 #endif
46 /* Concrete buffering implementation subclass for JSON output. */
48 class diagnostic_text_format_buffer : public diagnostic_per_format_buffer
50 public:
51 friend class diagnostic_text_output_format;
53 diagnostic_text_format_buffer (diagnostic_output_format &format);
55 void dump (FILE *out, int indent) const final override;
57 bool empty_p () const final override;
58 void move_to (diagnostic_per_format_buffer &dest) final override;
59 void clear () final override;
60 void flush () final override;
62 private:
63 diagnostic_output_format &m_format;
64 output_buffer m_output_buffer;
67 /* class diagnostic_text_format_buffer : public diagnostic_per_format_buffer. */
69 diagnostic_text_format_buffer::
70 diagnostic_text_format_buffer (diagnostic_output_format &format)
71 : m_format (format)
73 m_output_buffer.m_flush_p = false;
76 void
77 diagnostic_text_format_buffer::dump (FILE *out, int indent) const
79 fprintf (out, "%*sdiagnostic_text_format_buffer:\n", indent, "");
80 m_output_buffer.dump (out, indent + 2);
83 bool
84 diagnostic_text_format_buffer::empty_p () const
86 return output_buffer_last_position_in_text (&m_output_buffer) == nullptr;
89 void
90 diagnostic_text_format_buffer::move_to (diagnostic_per_format_buffer &base_dest)
92 diagnostic_text_format_buffer &dest
93 = static_cast<diagnostic_text_format_buffer &> (base_dest);
94 const char *str = output_buffer_formatted_text (&m_output_buffer);
95 output_buffer_append_r (&dest.m_output_buffer, str, strlen (str));
97 obstack_free (m_output_buffer.m_obstack,
98 obstack_base (m_output_buffer.m_obstack));
99 m_output_buffer.m_line_length = 0;
102 void
103 diagnostic_text_format_buffer::clear ()
105 pretty_printer *const pp = m_format.get_printer ();
106 output_buffer *const old_output_buffer = pp_buffer (pp);
108 pp_buffer (pp) = &m_output_buffer;
110 pp_clear_output_area (pp);
111 gcc_assert (empty_p ());
113 pp_buffer (pp) = old_output_buffer;
116 void
117 diagnostic_text_format_buffer::flush ()
119 pretty_printer *const pp = m_format.get_printer ();
120 output_buffer *const old_output_buffer = pp_buffer (pp);
122 pp_buffer (pp) = &m_output_buffer;
124 pp_really_flush (pp);
125 gcc_assert (empty_p ());
127 pp_buffer (pp) = old_output_buffer;
130 /* class diagnostic_text_output_format : public diagnostic_output_format. */
132 diagnostic_text_output_format::~diagnostic_text_output_format ()
134 /* Some of the errors may actually have been warnings. */
135 if (m_context.diagnostic_count (DK_WERROR))
137 pretty_printer *pp = get_printer ();
138 /* -Werror was given. */
139 if (m_context.warning_as_error_requested_p ())
140 pp_verbatim (pp,
141 _("%s: all warnings being treated as errors"),
142 progname);
143 /* At least one -Werror= was given. */
144 else
145 pp_verbatim (pp,
146 _("%s: some warnings being treated as errors"),
147 progname);
148 pp_newline_and_flush (pp);
151 if (m_includes_seen)
153 delete m_includes_seen;
154 m_includes_seen = nullptr;
158 void
159 diagnostic_text_output_format::dump (FILE *out, int indent) const
161 fprintf (out, "%*sdiagnostic_text_output_format\n", indent, "");
162 fprintf (out, "%*sm_follows_reference_printer: %s\n",
163 indent, "",
164 m_follows_reference_printer ? "true" : "false");
165 diagnostic_output_format::dump (out, indent);
166 fprintf (out, "%*ssaved_output_buffer:\n", indent + 2, "");
167 if (m_saved_output_buffer)
168 m_saved_output_buffer->dump (out, indent + 4);
169 else
170 fprintf (out, "%*s(none):\n", indent + 4, "");
173 void
174 diagnostic_text_output_format::set_buffer (diagnostic_per_format_buffer *base)
176 diagnostic_text_format_buffer * const buffer
177 = static_cast<diagnostic_text_format_buffer *> (base);
179 pretty_printer *const pp = get_printer ();
181 if (!m_saved_output_buffer)
182 m_saved_output_buffer = pp_buffer (pp);
184 if (buffer)
185 pp_buffer (pp) = &buffer->m_output_buffer;
186 else
188 gcc_assert (m_saved_output_buffer);
189 pp_buffer (pp) = m_saved_output_buffer;
193 std::unique_ptr<diagnostic_per_format_buffer>
194 diagnostic_text_output_format::make_per_format_buffer ()
196 return ::make_unique<diagnostic_text_format_buffer> (*this);
199 /* Implementation of diagnostic_output_format::on_report_diagnostic vfunc
200 for GCC's standard textual output. */
202 void
203 diagnostic_text_output_format::
204 on_report_diagnostic (const diagnostic_info &diagnostic,
205 diagnostic_t orig_diag_kind)
207 pretty_printer *pp = get_printer ();
209 (*diagnostic_text_starter (&m_context)) (*this, &diagnostic);
211 pp_output_formatted_text (pp, m_context.get_urlifier ());
213 if (m_context.m_show_cwe)
214 print_any_cwe (diagnostic);
216 if (m_context.m_show_rules)
217 print_any_rules (diagnostic);
219 if (m_context.m_show_option_requested)
220 print_option_information (diagnostic, orig_diag_kind);
222 /* If we're showing nested diagnostics, then print the location
223 on a new line, indented. */
224 if (m_show_nesting && m_show_locations_in_nesting)
226 const int nesting_level = get_context ().get_diagnostic_nesting_level ();
227 if (nesting_level > 0)
229 location_t loc = diagnostic_location (&diagnostic);
230 pp_set_prefix (pp, nullptr);
231 char *indent_prefix = build_indent_prefix (false);
232 /* Only print changes of location. */
233 if (loc != get_context ().m_last_location
234 && loc > BUILTINS_LOCATION)
236 const expanded_location s
237 = diagnostic_expand_location (&diagnostic);
238 label_text location_text = get_location_text (s);
239 pp_newline (pp);
240 pp_printf (pp, "%s%s", indent_prefix, location_text.get ());
242 pp_set_prefix (pp, indent_prefix);
246 (*diagnostic_text_finalizer (&m_context)) (*this,
247 &diagnostic,
248 orig_diag_kind);
250 if (m_show_nesting && m_show_locations_in_nesting)
251 get_context ().m_last_location = diagnostic_location (&diagnostic);
254 void
255 diagnostic_text_output_format::on_report_verbatim (text_info &text)
257 pp_format_verbatim (get_printer (), &text);
258 pp_newline_and_flush (get_printer ());
261 void
262 diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
264 pretty_printer *const pp = get_printer ();
266 char *saved_prefix = pp_take_prefix (pp);
267 pp_set_prefix (pp, NULL);
268 /* Use a newline before and after and a two-space indent
269 to make the diagram stand out a little from the wall of text. */
270 pp_newline (pp);
271 diagram.get_canvas ().print_to_pp (pp, " ");
272 pp_newline (pp);
273 pp_set_prefix (pp, saved_prefix);
274 pp_flush (pp);
277 void
278 diagnostic_text_output_format::
279 after_diagnostic (const diagnostic_info &diagnostic)
281 if (const diagnostic_path *path = diagnostic.richloc->get_path ())
282 print_path (*path);
285 /* Return a malloc'd string describing a location and the severity of the
286 diagnostic, e.g. "foo.c:42:10: error: ".
288 If m_show_nesting, then the above will be preceded by indentation to show
289 the level, and a bullet point.
291 The caller is responsible for freeing the memory. */
292 char *
293 diagnostic_text_output_format::
294 build_prefix (const diagnostic_info &diagnostic) const
296 gcc_assert (diagnostic.kind < DK_LAST_DIAGNOSTIC_KIND);
298 const char *text = _(get_diagnostic_kind_text (diagnostic.kind));
299 const char *text_cs = "", *text_ce = "";
300 pretty_printer *pp = get_printer ();
302 if (const char *color_name = diagnostic_get_color_for_kind (diagnostic.kind))
304 text_cs = colorize_start (pp_show_color (pp), color_name);
305 text_ce = colorize_stop (pp_show_color (pp));
308 const int nesting_level = get_context ().get_diagnostic_nesting_level ();
309 if (m_show_nesting && nesting_level > 0)
311 char *indent_prefix = build_indent_prefix (true);
313 /* Reduce verbosity of nested diagnostics by not printing "note: "
314 all the time. */
315 if (diagnostic.kind == DK_NOTE)
316 return indent_prefix;
318 char *result = build_message_string ("%s%s%s%s", indent_prefix,
319 text_cs, text, text_ce);
320 free (indent_prefix);
321 return result;
323 else
325 const expanded_location s = diagnostic_expand_location (&diagnostic);
326 label_text location_text = get_location_text (s);
327 return build_message_string ("%s %s%s%s", location_text.get (),
328 text_cs, text, text_ce);
332 /* Same as build_prefix, but only the source FILE is given. */
333 char *
334 diagnostic_text_output_format::file_name_as_prefix (const char *f) const
336 pretty_printer *const pp = get_printer ();
337 const char *locus_cs
338 = colorize_start (pp_show_color (pp), "locus");
339 const char *locus_ce = colorize_stop (pp_show_color (pp));
340 return build_message_string ("%s%s:%s ", locus_cs, f, locus_ce);
343 /* Get the unicode code point for bullet points when showing
344 nested diagnostics. */
346 static unsigned
347 get_bullet_point_unichar (bool unicode)
349 if (unicode)
350 return 0x2022; /* U+2022: Bullet */
351 else
352 return '*';
355 /* Return true if DC's theme supports unicode characters. */
357 static bool
358 use_unicode_p (const diagnostic_context &dc)
360 if (text_art::theme *theme = dc.get_diagram_theme ())
361 return theme->unicode_p ();
362 else
363 return false;
366 /* Get the unicode code point for bullet points when showing
367 nested diagnostics. */
369 static unsigned
370 get_bullet_point_unichar (diagnostic_context &dc)
372 return get_bullet_point_unichar (use_unicode_p (dc));
375 /* Return a malloc'd string for use as a prefix to show indentation.
376 If m_show_nesting is false, or we're at the top-level, then the
377 result will be the empty string.
379 If m_show_nesting, then the result will contain indentation to show
380 the nesting level, then either a bullet point (if WITH_BULLET is true),
381 or a space.
383 The caller is responsible for freeing the memory. */
385 char *
386 diagnostic_text_output_format::build_indent_prefix (bool with_bullet) const
388 if (!m_show_nesting)
389 return xstrdup ("");
391 const int nesting_level = get_context ().get_diagnostic_nesting_level ();
392 if (nesting_level == 0)
393 return xstrdup ("");
395 pretty_printer pp;
396 for (int i = 0; i < nesting_level; i++)
397 pp_string (&pp, " ");
398 if (with_bullet)
399 pp_unicode_character (&pp, get_bullet_point_unichar (get_context ()));
400 else
401 pp_space (&pp);
402 pp_space (&pp);
403 if (m_show_nesting_levels)
404 pp_printf (&pp, "(level %i):", nesting_level);
405 return xstrdup (pp_formatted_text (&pp));
408 /* Add a purely textual note with text GMSGID and with LOCATION. */
410 void
411 diagnostic_text_output_format::append_note (location_t location,
412 const char * gmsgid, ...)
414 diagnostic_context *context = &get_context ();
416 diagnostic_info diagnostic;
417 va_list ap;
418 rich_location richloc (line_table, location);
420 va_start (ap, gmsgid);
421 diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
422 if (context->m_inhibit_notes_p)
424 va_end (ap);
425 return;
427 pretty_printer *pp = get_printer ();
428 char *saved_prefix = pp_take_prefix (pp);
429 pp_set_prefix (pp, build_prefix (diagnostic));
430 pp_format (pp, &diagnostic.message);
431 pp_output_formatted_text (pp);
432 pp_destroy_prefix (pp);
433 pp_set_prefix (pp, saved_prefix);
434 pp_newline (pp);
435 diagnostic_show_locus (context, get_source_printing_options (),
436 &richloc, DK_NOTE, pp);
437 va_end (ap);
440 bool
441 diagnostic_text_output_format::follows_reference_printer_p () const
443 return m_follows_reference_printer;
446 void
447 diagnostic_text_output_format::
448 update_printer ()
450 pretty_printer *copy_from_pp
451 = (m_follows_reference_printer
452 ? get_context ().get_reference_printer ()
453 : m_printer.get ());
454 const bool show_color = pp_show_color (copy_from_pp);
455 const diagnostic_url_format url_format = copy_from_pp->get_url_format ();
457 m_printer = get_context ().clone_printer ();
459 pp_show_color (m_printer.get ()) = show_color;
460 m_printer->set_url_format (url_format);
461 // ...etc
463 m_source_printing = get_context ().m_source_printing;
466 /* If DIAGNOSTIC has a CWE identifier, print it.
468 For example, if the diagnostic metadata associates it with CWE-119,
469 " [CWE-119]" will be printed, suitably colorized, and with a URL of a
470 description of the security issue. */
472 void
473 diagnostic_text_output_format::print_any_cwe (const diagnostic_info &diagnostic)
475 if (diagnostic.metadata == NULL)
476 return;
478 int cwe = diagnostic.metadata->get_cwe ();
479 if (cwe)
481 pretty_printer * const pp = get_printer ();
482 char *saved_prefix = pp_take_prefix (pp);
483 pp_string (pp, " [");
484 const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
485 pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
486 if (pp->supports_urls_p ())
488 char *cwe_url = get_cwe_url (cwe);
489 pp_begin_url (pp, cwe_url);
490 free (cwe_url);
492 pp_printf (pp, "CWE-%i", cwe);
493 pp_set_prefix (pp, saved_prefix);
494 if (pp->supports_urls_p ())
495 pp_end_url (pp);
496 pp_string (pp, colorize_stop (pp_show_color (pp)));
497 pp_character (pp, ']');
501 /* If DIAGNOSTIC has any rules associated with it, print them.
503 For example, if the diagnostic metadata associates it with a rule
504 named "STR34-C", then " [STR34-C]" will be printed, suitably colorized,
505 with any URL provided by the rule. */
507 void
508 diagnostic_text_output_format::
509 print_any_rules (const diagnostic_info &diagnostic)
511 if (diagnostic.metadata == NULL)
512 return;
514 for (unsigned idx = 0; idx < diagnostic.metadata->get_num_rules (); idx++)
516 const diagnostic_metadata::rule &rule
517 = diagnostic.metadata->get_rule (idx);
518 if (char *desc = rule.make_description ())
520 pretty_printer * const pp = get_printer ();
521 char *saved_prefix = pp_take_prefix (pp);
522 pp_string (pp, " [");
523 const char *kind_color
524 = diagnostic_get_color_for_kind (diagnostic.kind);
525 pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
526 char *url = NULL;
527 if (pp->supports_urls_p ())
529 url = rule.make_url ();
530 if (url)
531 pp_begin_url (pp, url);
533 pp_string (pp, desc);
534 pp_set_prefix (pp, saved_prefix);
535 if (pp->supports_urls_p ())
536 if (url)
537 pp_end_url (pp);
538 free (url);
539 pp_string (pp, colorize_stop (pp_show_color (pp)));
540 pp_character (pp, ']');
541 free (desc);
546 /* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
547 printer, e.g. " [-Werror=uninitialized]".
548 Subroutine of diagnostic_context::report_diagnostic. */
550 void
551 diagnostic_text_output_format::
552 print_option_information (const diagnostic_info &diagnostic,
553 diagnostic_t orig_diag_kind)
555 if (char *option_text
556 = m_context.make_option_name (diagnostic.option_id,
557 orig_diag_kind, diagnostic.kind))
559 char *option_url = nullptr;
560 pretty_printer * const pp = get_printer ();
561 if (pp->supports_urls_p ())
562 option_url = m_context.make_option_url (diagnostic.option_id);
563 pp_string (pp, " [");
564 const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
565 pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
566 if (option_url)
567 pp_begin_url (pp, option_url);
568 pp_string (pp, option_text);
569 if (option_url)
571 pp_end_url (pp);
572 free (option_url);
574 pp_string (pp, colorize_stop (pp_show_color (pp)));
575 pp_character (pp, ']');
576 free (option_text);
580 /* Only dump the "In file included from..." stack once for each file. */
582 bool
583 diagnostic_text_output_format::includes_seen_p (const line_map_ordinary *map)
585 /* No include path for main. */
586 if (MAIN_FILE_P (map))
587 return true;
589 /* Always identify C++ modules, at least for now. */
590 auto probe = map;
591 if (linemap_check_ordinary (map)->reason == LC_RENAME)
592 /* The module source file shows up as LC_RENAME inside LC_MODULE. */
593 probe = linemap_included_from_linemap (line_table, map);
594 if (MAP_MODULE_P (probe))
595 return false;
597 if (!m_includes_seen)
598 m_includes_seen = new hash_set<location_t, false, location_hash>;
600 /* Hash the location of the #include directive to better handle files
601 that are included multiple times with different macros defined. */
602 return m_includes_seen->add (linemap_included_from (map));
605 label_text
606 diagnostic_text_output_format::
607 get_location_text (const expanded_location &s) const
609 diagnostic_column_policy column_policy (get_context ());
610 return column_policy.get_location_text (s,
611 show_column_p (),
612 pp_show_color (get_printer ()));
615 /* Helpers for writing lang-specific starters/finalizers for text output. */
617 /* Return a formatted line and column ':%line:%column'. Elided if
618 line == 0 or col < 0. (A column of 0 may be valid due to the
619 -fdiagnostics-column-origin option.)
620 The result is a statically allocated buffer. */
622 const char *
623 maybe_line_and_column (int line, int col)
625 static char result[32];
627 if (line)
629 size_t l
630 = snprintf (result, sizeof (result),
631 col >= 0 ? ":%d:%d" : ":%d", line, col);
632 gcc_checking_assert (l < sizeof (result));
634 else
635 result[0] = 0;
636 return result;
639 void
640 diagnostic_text_output_format::report_current_module (location_t where)
642 pretty_printer *pp = get_printer ();
643 const line_map_ordinary *map = NULL;
645 if (pp_needs_newline (pp))
647 pp_newline (pp);
648 pp_needs_newline (pp) = false;
651 if (where <= BUILTINS_LOCATION)
652 return;
654 linemap_resolve_location (line_table, where,
655 LRK_MACRO_DEFINITION_LOCATION,
656 &map);
658 if (map && m_last_module != map)
660 m_last_module = map;
661 if (!includes_seen_p (map))
663 bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
664 expanded_location s = {};
667 where = linemap_included_from (map);
668 map = linemap_included_from_linemap (line_table, map);
669 bool is_module = MAP_MODULE_P (map);
670 s.file = LINEMAP_FILE (map);
671 s.line = SOURCE_LINE (map, where);
672 int col = -1;
673 if (first && show_column_p ())
675 s.column = SOURCE_COLUMN (map, where);
676 col = get_column_policy ().converted_column (s);
678 const char *line_col = maybe_line_and_column (s.line, col);
679 static const char *const msgs[] =
681 NULL,
682 N_(" from"),
683 N_("In file included from"), /* 2 */
684 N_(" included from"),
685 N_("In module"), /* 4 */
686 N_("of module"),
687 N_("In module imported at"), /* 6 */
688 N_("imported at"),
691 unsigned index = (was_module ? 6 : is_module ? 4
692 : need_inc ? 2 : 0) + !first;
694 pp_verbatim (pp, "%s%s %r%s%s%R",
695 first ? "" : was_module ? ", " : ",\n",
696 _(msgs[index]),
697 "locus", s.file, line_col);
698 first = false, need_inc = was_module, was_module = is_module;
700 while (!includes_seen_p (map));
701 pp_verbatim (pp, ":");
702 pp_newline (pp);
707 void
708 default_diagnostic_text_starter (diagnostic_text_output_format &text_output,
709 const diagnostic_info *diagnostic)
711 text_output.report_current_module (diagnostic_location (diagnostic));
712 pretty_printer *const pp = text_output.get_printer ();
713 pp_set_prefix (pp, text_output.build_prefix (*diagnostic));
716 void
717 default_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
718 const diagnostic_info *diagnostic,
719 diagnostic_t)
721 pretty_printer *const pp = text_output.get_printer ();
722 char *saved_prefix = pp_take_prefix (pp);
723 pp_set_prefix (pp, NULL);
724 pp_newline (pp);
725 diagnostic_show_locus (&text_output.get_context (),
726 text_output.get_source_printing_options (),
727 diagnostic->richloc, diagnostic->kind, pp);
728 pp_set_prefix (pp, saved_prefix);
729 pp_flush (pp);
732 #if __GNUC__ >= 10
733 # pragma GCC diagnostic pop
734 #endif