libcpp, c, middle-end: Optimize initializers using #embed in C
[official-gcc.git] / gcc / diagnostic-format-text.cc
blob0d58d5fb082dca0060476f1fc8a0a744fe373840
1 /* Classic text-based output of diagnostics.
2 Copyright (C) 1999-2024 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 "text-art/theme.h"
37 /* Disable warnings about quoting issues in the pp_xxx calls below
38 that (intentionally) don't follow GCC diagnostic conventions. */
39 #if __GNUC__ >= 10
40 # pragma GCC diagnostic push
41 # pragma GCC diagnostic ignored "-Wformat-diag"
42 #endif
44 /* class diagnostic_text_output_format : public diagnostic_output_format. */
46 diagnostic_text_output_format::~diagnostic_text_output_format ()
48 /* Some of the errors may actually have been warnings. */
49 if (m_context.diagnostic_count (DK_WERROR))
51 pretty_printer *pp = get_printer ();
52 /* -Werror was given. */
53 if (m_context.warning_as_error_requested_p ())
54 pp_verbatim (pp,
55 _("%s: all warnings being treated as errors"),
56 progname);
57 /* At least one -Werror= was given. */
58 else
59 pp_verbatim (pp,
60 _("%s: some warnings being treated as errors"),
61 progname);
62 pp_newline_and_flush (pp);
65 if (m_includes_seen)
67 delete m_includes_seen;
68 m_includes_seen = nullptr;
72 /* Implementation of diagnostic_output_format::on_report_diagnostic vfunc
73 for GCC's standard textual output. */
75 void
76 diagnostic_text_output_format::
77 on_report_diagnostic (const diagnostic_info &diagnostic,
78 diagnostic_t orig_diag_kind)
80 pretty_printer *pp = get_printer ();
82 (*diagnostic_text_starter (&m_context)) (*this, &diagnostic);
84 pp_output_formatted_text (pp, m_context.get_urlifier ());
86 if (m_context.m_show_cwe)
87 print_any_cwe (diagnostic);
89 if (m_context.m_show_rules)
90 print_any_rules (diagnostic);
92 if (m_context.m_show_option_requested)
93 print_option_information (diagnostic, orig_diag_kind);
95 (*diagnostic_text_finalizer (&m_context)) (*this,
96 &diagnostic,
97 orig_diag_kind);
100 void
101 diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
103 pretty_printer *const pp = get_printer ();
105 char *saved_prefix = pp_take_prefix (pp);
106 pp_set_prefix (pp, NULL);
107 /* Use a newline before and after and a two-space indent
108 to make the diagram stand out a little from the wall of text. */
109 pp_newline (pp);
110 diagram.get_canvas ().print_to_pp (pp, " ");
111 pp_newline (pp);
112 pp_set_prefix (pp, saved_prefix);
113 pp_flush (pp);
116 void
117 diagnostic_text_output_format::
118 after_diagnostic (const diagnostic_info &diagnostic)
120 if (const diagnostic_path *path = diagnostic.richloc->get_path ())
121 print_path (*path);
124 /* Return a malloc'd string describing a location and the severity of the
125 diagnostic, e.g. "foo.c:42:10: error: ". The caller is responsible for
126 freeing the memory. */
127 char *
128 diagnostic_text_output_format::
129 build_prefix (const diagnostic_info &diagnostic) const
131 gcc_assert (diagnostic.kind < DK_LAST_DIAGNOSTIC_KIND);
133 const char *text = _(get_diagnostic_kind_text (diagnostic.kind));
134 const char *text_cs = "", *text_ce = "";
135 pretty_printer *pp = get_printer ();
137 if (const char *color_name = diagnostic_get_color_for_kind (diagnostic.kind))
139 text_cs = colorize_start (pp_show_color (pp), color_name);
140 text_ce = colorize_stop (pp_show_color (pp));
143 const expanded_location s = diagnostic_expand_location (&diagnostic);
144 label_text location_text = get_location_text (s);
146 char *result = build_message_string ("%s %s%s%s", location_text.get (),
147 text_cs, text, text_ce);
148 return result;
151 /* Same as build_prefix, but only the source FILE is given. */
152 char *
153 diagnostic_text_output_format::file_name_as_prefix (const char *f) const
155 pretty_printer *const pp = get_printer ();
156 const char *locus_cs
157 = colorize_start (pp_show_color (pp), "locus");
158 const char *locus_ce = colorize_stop (pp_show_color (pp));
159 return build_message_string ("%s%s:%s ", locus_cs, f, locus_ce);
162 /* Add a purely textual note with text GMSGID and with LOCATION. */
164 void
165 diagnostic_text_output_format::append_note (location_t location,
166 const char * gmsgid, ...)
168 diagnostic_context *context = &get_context ();
170 diagnostic_info diagnostic;
171 va_list ap;
172 rich_location richloc (line_table, location);
174 va_start (ap, gmsgid);
175 diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
176 if (context->m_inhibit_notes_p)
178 va_end (ap);
179 return;
181 pretty_printer *pp = get_printer ();
182 char *saved_prefix = pp_take_prefix (pp);
183 pp_set_prefix (pp, build_prefix (diagnostic));
184 pp_format (pp, &diagnostic.message);
185 pp_output_formatted_text (pp);
186 pp_destroy_prefix (pp);
187 pp_set_prefix (pp, saved_prefix);
188 pp_newline (pp);
189 diagnostic_show_locus (context, &richloc, DK_NOTE, pp);
190 va_end (ap);
193 /* If DIAGNOSTIC has a CWE identifier, print it.
195 For example, if the diagnostic metadata associates it with CWE-119,
196 " [CWE-119]" will be printed, suitably colorized, and with a URL of a
197 description of the security issue. */
199 void
200 diagnostic_text_output_format::print_any_cwe (const diagnostic_info &diagnostic)
202 if (diagnostic.metadata == NULL)
203 return;
205 int cwe = diagnostic.metadata->get_cwe ();
206 if (cwe)
208 pretty_printer * const pp = get_printer ();
209 char *saved_prefix = pp_take_prefix (pp);
210 pp_string (pp, " [");
211 const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
212 pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
213 if (pp->supports_urls_p ())
215 char *cwe_url = get_cwe_url (cwe);
216 pp_begin_url (pp, cwe_url);
217 free (cwe_url);
219 pp_printf (pp, "CWE-%i", cwe);
220 pp_set_prefix (pp, saved_prefix);
221 if (pp->supports_urls_p ())
222 pp_end_url (pp);
223 pp_string (pp, colorize_stop (pp_show_color (pp)));
224 pp_character (pp, ']');
228 /* If DIAGNOSTIC has any rules associated with it, print them.
230 For example, if the diagnostic metadata associates it with a rule
231 named "STR34-C", then " [STR34-C]" will be printed, suitably colorized,
232 with any URL provided by the rule. */
234 void
235 diagnostic_text_output_format::
236 print_any_rules (const diagnostic_info &diagnostic)
238 if (diagnostic.metadata == NULL)
239 return;
241 for (unsigned idx = 0; idx < diagnostic.metadata->get_num_rules (); idx++)
243 const diagnostic_metadata::rule &rule
244 = diagnostic.metadata->get_rule (idx);
245 if (char *desc = rule.make_description ())
247 pretty_printer * const pp = get_printer ();
248 char *saved_prefix = pp_take_prefix (pp);
249 pp_string (pp, " [");
250 const char *kind_color
251 = diagnostic_get_color_for_kind (diagnostic.kind);
252 pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
253 char *url = NULL;
254 if (pp->supports_urls_p ())
256 url = rule.make_url ();
257 if (url)
258 pp_begin_url (pp, url);
260 pp_string (pp, desc);
261 pp_set_prefix (pp, saved_prefix);
262 if (pp->supports_urls_p ())
263 if (url)
264 pp_end_url (pp);
265 free (url);
266 pp_string (pp, colorize_stop (pp_show_color (pp)));
267 pp_character (pp, ']');
268 free (desc);
273 /* Print any metadata about the option used to control DIAGNOSTIC to CONTEXT's
274 printer, e.g. " [-Werror=uninitialized]".
275 Subroutine of diagnostic_context::report_diagnostic. */
277 void
278 diagnostic_text_output_format::
279 print_option_information (const diagnostic_info &diagnostic,
280 diagnostic_t orig_diag_kind)
282 if (char *option_text
283 = m_context.make_option_name (diagnostic.option_id,
284 orig_diag_kind, diagnostic.kind))
286 char *option_url = nullptr;
287 pretty_printer * const pp = get_printer ();
288 if (pp->supports_urls_p ())
289 option_url = m_context.make_option_url (diagnostic.option_id);
290 pp_string (pp, " [");
291 const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
292 pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
293 if (option_url)
294 pp_begin_url (pp, option_url);
295 pp_string (pp, option_text);
296 if (option_url)
298 pp_end_url (pp);
299 free (option_url);
301 pp_string (pp, colorize_stop (pp_show_color (pp)));
302 pp_character (pp, ']');
303 free (option_text);
307 /* Only dump the "In file included from..." stack once for each file. */
309 bool
310 diagnostic_text_output_format::includes_seen_p (const line_map_ordinary *map)
312 /* No include path for main. */
313 if (MAIN_FILE_P (map))
314 return true;
316 /* Always identify C++ modules, at least for now. */
317 auto probe = map;
318 if (linemap_check_ordinary (map)->reason == LC_RENAME)
319 /* The module source file shows up as LC_RENAME inside LC_MODULE. */
320 probe = linemap_included_from_linemap (line_table, map);
321 if (MAP_MODULE_P (probe))
322 return false;
324 if (!m_includes_seen)
325 m_includes_seen = new hash_set<location_t, false, location_hash>;
327 /* Hash the location of the #include directive to better handle files
328 that are included multiple times with different macros defined. */
329 return m_includes_seen->add (linemap_included_from (map));
332 label_text
333 diagnostic_text_output_format::
334 get_location_text (const expanded_location &s) const
336 diagnostic_column_policy column_policy (get_context ());
337 return column_policy.get_location_text (s,
338 show_column_p (),
339 pp_show_color (get_printer ()));
342 /* Helpers for writing lang-specific starters/finalizers for text output. */
344 /* Return a formatted line and column ':%line:%column'. Elided if
345 line == 0 or col < 0. (A column of 0 may be valid due to the
346 -fdiagnostics-column-origin option.)
347 The result is a statically allocated buffer. */
349 const char *
350 maybe_line_and_column (int line, int col)
352 static char result[32];
354 if (line)
356 size_t l
357 = snprintf (result, sizeof (result),
358 col >= 0 ? ":%d:%d" : ":%d", line, col);
359 gcc_checking_assert (l < sizeof (result));
361 else
362 result[0] = 0;
363 return result;
366 void
367 diagnostic_text_output_format::report_current_module (location_t where)
369 pretty_printer *pp = get_printer ();
370 const line_map_ordinary *map = NULL;
372 if (pp_needs_newline (pp))
374 pp_newline (pp);
375 pp_needs_newline (pp) = false;
378 if (where <= BUILTINS_LOCATION)
379 return;
381 linemap_resolve_location (line_table, where,
382 LRK_MACRO_DEFINITION_LOCATION,
383 &map);
385 if (map && m_last_module != map)
387 m_last_module = map;
388 if (!includes_seen_p (map))
390 bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
391 expanded_location s = {};
394 where = linemap_included_from (map);
395 map = linemap_included_from_linemap (line_table, map);
396 bool is_module = MAP_MODULE_P (map);
397 s.file = LINEMAP_FILE (map);
398 s.line = SOURCE_LINE (map, where);
399 int col = -1;
400 if (first && show_column_p ())
402 s.column = SOURCE_COLUMN (map, where);
403 col = get_column_policy ().converted_column (s);
405 const char *line_col = maybe_line_and_column (s.line, col);
406 static const char *const msgs[] =
408 NULL,
409 N_(" from"),
410 N_("In file included from"), /* 2 */
411 N_(" included from"),
412 N_("In module"), /* 4 */
413 N_("of module"),
414 N_("In module imported at"), /* 6 */
415 N_("imported at"),
418 unsigned index = (was_module ? 6 : is_module ? 4
419 : need_inc ? 2 : 0) + !first;
421 pp_verbatim (pp, "%s%s %r%s%s%R",
422 first ? "" : was_module ? ", " : ",\n",
423 _(msgs[index]),
424 "locus", s.file, line_col);
425 first = false, need_inc = was_module, was_module = is_module;
427 while (!includes_seen_p (map));
428 pp_verbatim (pp, ":");
429 pp_newline (pp);
434 void
435 default_diagnostic_text_starter (diagnostic_text_output_format &text_output,
436 const diagnostic_info *diagnostic)
438 text_output.report_current_module (diagnostic_location (diagnostic));
439 pretty_printer *const pp = text_output.get_printer ();
440 pp_set_prefix (pp, text_output.build_prefix (*diagnostic));
443 void
444 default_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
445 const diagnostic_info *diagnostic,
446 diagnostic_t)
448 pretty_printer *const pp = text_output.get_printer ();
449 char *saved_prefix = pp_take_prefix (pp);
450 pp_set_prefix (pp, NULL);
451 pp_newline (pp);
452 diagnostic_show_locus (&text_output.get_context (),
453 diagnostic->richloc, diagnostic->kind, pp);
454 pp_set_prefix (pp, saved_prefix);
455 pp_flush (pp);
458 #if __GNUC__ >= 10
459 # pragma GCC diagnostic pop
460 #endif