Branch data Line data Source code
1 : : /* Classic text-based output of diagnostics.
2 : : Copyright (C) 1999-2024 Free Software Foundation, Inc.
3 : :
4 : : This file is part of GCC.
5 : :
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.
10 : :
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.
15 : :
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/>. */
19 : :
20 : :
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"
38 : :
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
45 : :
46 : : /* Concrete buffering implementation subclass for JSON output. */
47 : :
48 : : class diagnostic_text_format_buffer : public diagnostic_per_format_buffer
49 : : {
50 : : public:
51 : : friend class diagnostic_text_output_format;
52 : :
53 : : diagnostic_text_format_buffer (diagnostic_output_format &format);
54 : :
55 : : void dump (FILE *out, int indent) const final override;
56 : :
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;
61 : :
62 : : private:
63 : : diagnostic_output_format &m_format;
64 : : output_buffer m_output_buffer;
65 : : };
66 : :
67 : : /* class diagnostic_text_format_buffer : public diagnostic_per_format_buffer. */
68 : :
69 : 95350 : diagnostic_text_format_buffer::
70 : 95350 : diagnostic_text_format_buffer (diagnostic_output_format &format)
71 : 95350 : : m_format (format)
72 : : {
73 : 95350 : m_output_buffer.m_flush_p = false;
74 : 95350 : }
75 : :
76 : : void
77 : 0 : diagnostic_text_format_buffer::dump (FILE *out, int indent) const
78 : : {
79 : 0 : fprintf (out, "%*sdiagnostic_text_format_buffer:\n", indent, "");
80 : 0 : m_output_buffer.dump (out, indent + 2);
81 : 0 : }
82 : :
83 : : bool
84 : 7697074 : diagnostic_text_format_buffer::empty_p () const
85 : : {
86 : 7697074 : return output_buffer_last_position_in_text (&m_output_buffer) == nullptr;
87 : : }
88 : :
89 : : void
90 : 21892 : diagnostic_text_format_buffer::move_to (diagnostic_per_format_buffer &base_dest)
91 : : {
92 : 21892 : diagnostic_text_format_buffer &dest
93 : : = static_cast<diagnostic_text_format_buffer &> (base_dest);
94 : 21892 : const char *str = output_buffer_formatted_text (&m_output_buffer);
95 : 21892 : output_buffer_append_r (&dest.m_output_buffer, str, strlen (str));
96 : :
97 : 21892 : obstack_free (m_output_buffer.m_obstack,
98 : : obstack_base (m_output_buffer.m_obstack));
99 : 21892 : m_output_buffer.m_line_length = 0;
100 : 21892 : }
101 : :
102 : : void
103 : 4630209 : diagnostic_text_format_buffer::clear ()
104 : : {
105 : 4630209 : pretty_printer *const pp = m_format.get_printer ();
106 : 4630209 : output_buffer *const old_output_buffer = pp_buffer (pp);
107 : :
108 : 4630209 : pp_buffer (pp) = &m_output_buffer;
109 : :
110 : 4630209 : pp_clear_output_area (pp);
111 : 4630209 : gcc_assert (empty_p ());
112 : :
113 : 4630209 : pp_buffer (pp) = old_output_buffer;
114 : 4630209 : }
115 : :
116 : : void
117 : 6944 : diagnostic_text_format_buffer::flush ()
118 : : {
119 : 6944 : pretty_printer *const pp = m_format.get_printer ();
120 : 6944 : output_buffer *const old_output_buffer = pp_buffer (pp);
121 : :
122 : 6944 : pp_buffer (pp) = &m_output_buffer;
123 : :
124 : 6944 : pp_really_flush (pp);
125 : 6944 : gcc_assert (empty_p ());
126 : :
127 : 6944 : pp_buffer (pp) = old_output_buffer;
128 : 6944 : }
129 : :
130 : : /* class diagnostic_text_output_format : public diagnostic_output_format. */
131 : :
132 : 600988 : diagnostic_text_output_format::~diagnostic_text_output_format ()
133 : : {
134 : : /* Some of the errors may actually have been warnings. */
135 : 301826 : if (m_context.diagnostic_count (DK_WERROR))
136 : : {
137 : 192 : pretty_printer *pp = get_printer ();
138 : : /* -Werror was given. */
139 : 192 : if (m_context.warning_as_error_requested_p ())
140 : 75 : pp_verbatim (pp,
141 : 75 : _("%s: all warnings being treated as errors"),
142 : : progname);
143 : : /* At least one -Werror= was given. */
144 : : else
145 : 117 : pp_verbatim (pp,
146 : 117 : _("%s: some warnings being treated as errors"),
147 : : progname);
148 : 192 : pp_newline_and_flush (pp);
149 : : }
150 : :
151 : 301826 : if (m_includes_seen)
152 : : {
153 : 981 : delete m_includes_seen;
154 : 981 : m_includes_seen = nullptr;
155 : : }
156 : 600988 : }
157 : :
158 : : void
159 : 0 : diagnostic_text_output_format::dump (FILE *out, int indent) const
160 : : {
161 : 0 : fprintf (out, "%*sdiagnostic_text_output_format\n", indent, "");
162 : 0 : fprintf (out, "%*sm_follows_reference_printer: %s\n",
163 : : indent, "",
164 : 0 : m_follows_reference_printer ? "true" : "false");
165 : 0 : diagnostic_output_format::dump (out, indent);
166 : 0 : fprintf (out, "%*ssaved_output_buffer:\n", indent + 2, "");
167 : 0 : if (m_saved_output_buffer)
168 : 0 : m_saved_output_buffer->dump (out, indent + 4);
169 : : else
170 : 0 : fprintf (out, "%*s(none):\n", indent + 4, "");
171 : 0 : }
172 : :
173 : : void
174 : 2596989 : diagnostic_text_output_format::set_buffer (diagnostic_per_format_buffer *base)
175 : : {
176 : 2596989 : diagnostic_text_format_buffer * const buffer
177 : : = static_cast<diagnostic_text_format_buffer *> (base);
178 : :
179 : 2596989 : pretty_printer *const pp = get_printer ();
180 : :
181 : 2596989 : if (!m_saved_output_buffer)
182 : 298849 : m_saved_output_buffer = pp_buffer (pp);
183 : :
184 : 2596989 : if (buffer)
185 : 1149070 : pp_buffer (pp) = &buffer->m_output_buffer;
186 : : else
187 : : {
188 : 1447919 : gcc_assert (m_saved_output_buffer);
189 : 1447919 : pp_buffer (pp) = m_saved_output_buffer;
190 : : }
191 : 2596989 : }
192 : :
193 : : std::unique_ptr<diagnostic_per_format_buffer>
194 : 95350 : diagnostic_text_output_format::make_per_format_buffer ()
195 : : {
196 : 95350 : return ::make_unique<diagnostic_text_format_buffer> (*this);
197 : : }
198 : :
199 : : /* Implementation of diagnostic_output_format::on_report_diagnostic vfunc
200 : : for GCC's standard textual output. */
201 : :
202 : : void
203 : 1469650 : diagnostic_text_output_format::
204 : : on_report_diagnostic (const diagnostic_info &diagnostic,
205 : : diagnostic_t orig_diag_kind)
206 : : {
207 : 1469650 : pretty_printer *pp = get_printer ();
208 : :
209 : 1469650 : (*diagnostic_text_starter (&m_context)) (*this, &diagnostic);
210 : :
211 : 1469650 : pp_output_formatted_text (pp, m_context.get_urlifier ());
212 : :
213 : 1469650 : if (m_context.m_show_cwe)
214 : 1468439 : print_any_cwe (diagnostic);
215 : :
216 : 1469650 : if (m_context.m_show_rules)
217 : 1468439 : print_any_rules (diagnostic);
218 : :
219 : 1469650 : if (m_context.m_show_option_requested)
220 : 1468439 : print_option_information (diagnostic, orig_diag_kind);
221 : :
222 : : /* If we're showing nested diagnostics, then print the location
223 : : on a new line, indented. */
224 : 1469650 : if (m_show_nesting && m_show_locations_in_nesting)
225 : : {
226 : 39 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
227 : 39 : if (nesting_level > 0)
228 : : {
229 : 36 : location_t loc = diagnostic_location (&diagnostic);
230 : 36 : pp_set_prefix (pp, nullptr);
231 : 36 : char *indent_prefix = build_indent_prefix (false);
232 : : /* Only print changes of location. */
233 : 36 : if (loc != get_context ().m_last_location
234 : 36 : && loc > BUILTINS_LOCATION)
235 : : {
236 : 0 : const expanded_location s
237 : 0 : = diagnostic_expand_location (&diagnostic);
238 : 0 : label_text location_text = get_location_text (s);
239 : 0 : pp_newline (pp);
240 : 0 : pp_printf (pp, "%s%s", indent_prefix, location_text.get ());
241 : 0 : }
242 : 36 : pp_set_prefix (pp, indent_prefix);
243 : : }
244 : : }
245 : :
246 : 1469650 : (*diagnostic_text_finalizer (&m_context)) (*this,
247 : : &diagnostic,
248 : : orig_diag_kind);
249 : :
250 : 1469649 : if (m_show_nesting && m_show_locations_in_nesting)
251 : 39 : get_context ().m_last_location = diagnostic_location (&diagnostic);
252 : 1469649 : }
253 : :
254 : : void
255 : 0 : diagnostic_text_output_format::on_report_verbatim (text_info &text)
256 : : {
257 : 0 : pp_format_verbatim (get_printer (), &text);
258 : 0 : pp_newline_and_flush (get_printer ());
259 : 0 : }
260 : :
261 : : void
262 : 80 : diagnostic_text_output_format::on_diagram (const diagnostic_diagram &diagram)
263 : : {
264 : 80 : pretty_printer *const pp = get_printer ();
265 : :
266 : 80 : char *saved_prefix = pp_take_prefix (pp);
267 : 80 : 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 : 80 : pp_newline (pp);
271 : 80 : diagram.get_canvas ().print_to_pp (pp, " ");
272 : 80 : pp_newline (pp);
273 : 80 : pp_set_prefix (pp, saved_prefix);
274 : 80 : pp_flush (pp);
275 : 80 : }
276 : :
277 : : void
278 : 319913 : diagnostic_text_output_format::
279 : : after_diagnostic (const diagnostic_info &diagnostic)
280 : : {
281 : 319913 : if (const diagnostic_path *path = diagnostic.richloc->get_path ())
282 : 3775 : print_path (*path);
283 : 319913 : }
284 : :
285 : : /* Return a malloc'd string describing a location and the severity of the
286 : : diagnostic, e.g. "foo.c:42:10: error: ".
287 : :
288 : : If m_show_nesting, then the above will be preceded by indentation to show
289 : : the level, and a bullet point.
290 : :
291 : : The caller is responsible for freeing the memory. */
292 : : char *
293 : 320633 : diagnostic_text_output_format::
294 : : build_prefix (const diagnostic_info &diagnostic) const
295 : : {
296 : 320633 : gcc_assert (diagnostic.kind < DK_LAST_DIAGNOSTIC_KIND);
297 : :
298 : 320633 : const char *text = _(get_diagnostic_kind_text (diagnostic.kind));
299 : 320633 : const char *text_cs = "", *text_ce = "";
300 : 320633 : pretty_printer *pp = get_printer ();
301 : :
302 : 320633 : if (const char *color_name = diagnostic_get_color_for_kind (diagnostic.kind))
303 : : {
304 : 320633 : text_cs = colorize_start (pp_show_color (pp), color_name);
305 : 320633 : text_ce = colorize_stop (pp_show_color (pp));
306 : : }
307 : :
308 : 320633 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
309 : 320633 : if (m_show_nesting && nesting_level > 0)
310 : : {
311 : 138 : char *indent_prefix = build_indent_prefix (true);
312 : :
313 : : /* Reduce verbosity of nested diagnostics by not printing "note: "
314 : : all the time. */
315 : 138 : if (diagnostic.kind == DK_NOTE)
316 : : return indent_prefix;
317 : :
318 : 6 : char *result = build_message_string ("%s%s%s%s", indent_prefix,
319 : : text_cs, text, text_ce);
320 : 6 : free (indent_prefix);
321 : 6 : return result;
322 : : }
323 : : else
324 : : {
325 : 320495 : const expanded_location s = diagnostic_expand_location (&diagnostic);
326 : 320495 : label_text location_text = get_location_text (s);
327 : 320495 : return build_message_string ("%s %s%s%s", location_text.get (),
328 : : text_cs, text, text_ce);
329 : 320495 : }
330 : : }
331 : :
332 : : /* Same as build_prefix, but only the source FILE is given. */
333 : : char *
334 : 38302 : diagnostic_text_output_format::file_name_as_prefix (const char *f) const
335 : : {
336 : 38302 : pretty_printer *const pp = get_printer ();
337 : 38302 : const char *locus_cs
338 : 38302 : = colorize_start (pp_show_color (pp), "locus");
339 : 38302 : const char *locus_ce = colorize_stop (pp_show_color (pp));
340 : 38302 : return build_message_string ("%s%s:%s ", locus_cs, f, locus_ce);
341 : : }
342 : :
343 : : /* Get the unicode code point for bullet points when showing
344 : : nested diagnostics. */
345 : :
346 : : static unsigned
347 : 285 : get_bullet_point_unichar (bool unicode)
348 : : {
349 : 285 : if (unicode)
350 : : return 0x2022; /* U+2022: Bullet */
351 : : else
352 : 273 : return '*';
353 : : }
354 : :
355 : : /* Return true if DC's theme supports unicode characters. */
356 : :
357 : : static bool
358 : 285 : use_unicode_p (const diagnostic_context &dc)
359 : : {
360 : 285 : if (text_art::theme *theme = dc.get_diagram_theme ())
361 : 12 : return theme->unicode_p ();
362 : : else
363 : : return false;
364 : : }
365 : :
366 : : /* Get the unicode code point for bullet points when showing
367 : : nested diagnostics. */
368 : :
369 : : static unsigned
370 : 285 : get_bullet_point_unichar (diagnostic_context &dc)
371 : : {
372 : 285 : return get_bullet_point_unichar (use_unicode_p (dc));
373 : : }
374 : :
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.
378 : :
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.
382 : :
383 : : The caller is responsible for freeing the memory. */
384 : :
385 : : char *
386 : 510088 : diagnostic_text_output_format::build_indent_prefix (bool with_bullet) const
387 : : {
388 : 510088 : if (!m_show_nesting)
389 : 509608 : return xstrdup ("");
390 : :
391 : 480 : const int nesting_level = get_context ().get_diagnostic_nesting_level ();
392 : 480 : if (nesting_level == 0)
393 : 21 : return xstrdup ("");
394 : :
395 : 459 : pretty_printer pp;
396 : 1974 : for (int i = 0; i < nesting_level; i++)
397 : 1515 : pp_string (&pp, " ");
398 : 459 : if (with_bullet)
399 : 570 : pp_unicode_character (&pp, get_bullet_point_unichar (get_context ()));
400 : : else
401 : 174 : pp_space (&pp);
402 : 459 : pp_space (&pp);
403 : 459 : if (m_show_nesting_levels)
404 : 36 : pp_printf (&pp, "(level %i):", nesting_level);
405 : 459 : return xstrdup (pp_formatted_text (&pp));
406 : 459 : }
407 : :
408 : : /* Add a purely textual note with text GMSGID and with LOCATION. */
409 : :
410 : : void
411 : 12635 : diagnostic_text_output_format::append_note (location_t location,
412 : : const char * gmsgid, ...)
413 : : {
414 : 12635 : diagnostic_context *context = &get_context ();
415 : :
416 : 12635 : diagnostic_info diagnostic;
417 : 12635 : va_list ap;
418 : 12635 : rich_location richloc (line_table, location);
419 : :
420 : 12635 : va_start (ap, gmsgid);
421 : 12635 : diagnostic_set_info (&diagnostic, gmsgid, &ap, &richloc, DK_NOTE);
422 : 12635 : if (context->m_inhibit_notes_p)
423 : : {
424 : 0 : va_end (ap);
425 : 0 : return;
426 : : }
427 : 12635 : pretty_printer *pp = get_printer ();
428 : 12635 : char *saved_prefix = pp_take_prefix (pp);
429 : 12635 : pp_set_prefix (pp, build_prefix (diagnostic));
430 : 12635 : pp_format (pp, &diagnostic.message);
431 : 12635 : pp_output_formatted_text (pp);
432 : 12635 : pp_destroy_prefix (pp);
433 : 12635 : pp_set_prefix (pp, saved_prefix);
434 : 12635 : pp_newline (pp);
435 : 12635 : diagnostic_show_locus (context, get_source_printing_options (),
436 : : &richloc, DK_NOTE, pp);
437 : 12635 : va_end (ap);
438 : 12635 : }
439 : :
440 : : bool
441 : 3289774 : diagnostic_text_output_format::follows_reference_printer_p () const
442 : : {
443 : 3289774 : return m_follows_reference_printer;
444 : : }
445 : :
446 : : void
447 : 483728 : diagnostic_text_output_format::
448 : : update_printer ()
449 : : {
450 : 483728 : pretty_printer *copy_from_pp
451 : 483728 : = (m_follows_reference_printer
452 : 483728 : ? get_context ().get_reference_printer ()
453 : 0 : : m_printer.get ());
454 : 483728 : const bool show_color = pp_show_color (copy_from_pp);
455 : 483728 : const diagnostic_url_format url_format = copy_from_pp->get_url_format ();
456 : :
457 : 483728 : m_printer = get_context ().clone_printer ();
458 : :
459 : 483728 : pp_show_color (m_printer.get ()) = show_color;
460 : 483728 : m_printer->set_url_format (url_format);
461 : : // ...etc
462 : :
463 : 483728 : m_source_printing = get_context ().m_source_printing;
464 : 483728 : }
465 : :
466 : : /* If DIAGNOSTIC has a CWE identifier, print it.
467 : :
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. */
471 : :
472 : : void
473 : 1468439 : diagnostic_text_output_format::print_any_cwe (const diagnostic_info &diagnostic)
474 : : {
475 : 1468439 : if (diagnostic.metadata == NULL)
476 : : return;
477 : :
478 : 4046 : int cwe = diagnostic.metadata->get_cwe ();
479 : 4046 : if (cwe)
480 : : {
481 : 3229 : pretty_printer * const pp = get_printer ();
482 : 3229 : char *saved_prefix = pp_take_prefix (pp);
483 : 3229 : pp_string (pp, " [");
484 : 3229 : const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
485 : 3229 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
486 : 3229 : if (pp->supports_urls_p ())
487 : : {
488 : 0 : char *cwe_url = get_cwe_url (cwe);
489 : 0 : pp_begin_url (pp, cwe_url);
490 : 0 : free (cwe_url);
491 : : }
492 : 3229 : pp_printf (pp, "CWE-%i", cwe);
493 : 3229 : pp_set_prefix (pp, saved_prefix);
494 : 3229 : if (pp->supports_urls_p ())
495 : 0 : pp_end_url (pp);
496 : 3229 : pp_string (pp, colorize_stop (pp_show_color (pp)));
497 : 3229 : pp_character (pp, ']');
498 : : }
499 : : }
500 : :
501 : : /* If DIAGNOSTIC has any rules associated with it, print them.
502 : :
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. */
506 : :
507 : : void
508 : 1468439 : diagnostic_text_output_format::
509 : : print_any_rules (const diagnostic_info &diagnostic)
510 : : {
511 : 1468439 : if (diagnostic.metadata == NULL)
512 : : return;
513 : :
514 : 4330 : for (unsigned idx = 0; idx < diagnostic.metadata->get_num_rules (); idx++)
515 : : {
516 : 284 : const diagnostic_metadata::rule &rule
517 : 284 : = diagnostic.metadata->get_rule (idx);
518 : 284 : if (char *desc = rule.make_description ())
519 : : {
520 : 284 : pretty_printer * const pp = get_printer ();
521 : 284 : char *saved_prefix = pp_take_prefix (pp);
522 : 284 : pp_string (pp, " [");
523 : 284 : const char *kind_color
524 : 284 : = diagnostic_get_color_for_kind (diagnostic.kind);
525 : 284 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
526 : 284 : char *url = NULL;
527 : 284 : if (pp->supports_urls_p ())
528 : : {
529 : 0 : url = rule.make_url ();
530 : 0 : if (url)
531 : 0 : pp_begin_url (pp, url);
532 : : }
533 : 284 : pp_string (pp, desc);
534 : 284 : pp_set_prefix (pp, saved_prefix);
535 : 284 : if (pp->supports_urls_p ())
536 : 0 : if (url)
537 : 0 : pp_end_url (pp);
538 : 284 : free (url);
539 : 284 : pp_string (pp, colorize_stop (pp_show_color (pp)));
540 : 284 : pp_character (pp, ']');
541 : 284 : free (desc);
542 : : }
543 : : }
544 : : }
545 : :
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. */
549 : :
550 : : void
551 : 1468439 : diagnostic_text_output_format::
552 : : print_option_information (const diagnostic_info &diagnostic,
553 : : diagnostic_t orig_diag_kind)
554 : : {
555 : 2936878 : if (char *option_text
556 : 1468439 : = m_context.make_option_name (diagnostic.option_id,
557 : 1468439 : orig_diag_kind, diagnostic.kind))
558 : : {
559 : 83984 : char *option_url = nullptr;
560 : 83984 : pretty_printer * const pp = get_printer ();
561 : 83984 : if (pp->supports_urls_p ())
562 : 0 : option_url = m_context.make_option_url (diagnostic.option_id);
563 : 83984 : pp_string (pp, " [");
564 : 83984 : const char *kind_color = diagnostic_get_color_for_kind (diagnostic.kind);
565 : 83984 : pp_string (pp, colorize_start (pp_show_color (pp), kind_color));
566 : 83984 : if (option_url)
567 : 0 : pp_begin_url (pp, option_url);
568 : 83984 : pp_string (pp, option_text);
569 : 83984 : if (option_url)
570 : : {
571 : 0 : pp_end_url (pp);
572 : 0 : free (option_url);
573 : : }
574 : 83984 : pp_string (pp, colorize_stop (pp_show_color (pp)));
575 : 83984 : pp_character (pp, ']');
576 : 83984 : free (option_text);
577 : : }
578 : 1468439 : }
579 : :
580 : : /* Only dump the "In file included from..." stack once for each file. */
581 : :
582 : : bool
583 : 58072 : diagnostic_text_output_format::includes_seen_p (const line_map_ordinary *map)
584 : : {
585 : : /* No include path for main. */
586 : 58072 : if (MAIN_FILE_P (map))
587 : : return true;
588 : :
589 : : /* Always identify C++ modules, at least for now. */
590 : 7788 : auto probe = map;
591 : 7788 : if (linemap_check_ordinary (map)->reason == LC_RENAME)
592 : : /* The module source file shows up as LC_RENAME inside LC_MODULE. */
593 : 455 : probe = linemap_included_from_linemap (line_table, map);
594 : 7788 : if (MAP_MODULE_P (probe))
595 : : return false;
596 : :
597 : 6924 : if (!m_includes_seen)
598 : 981 : m_includes_seen = new hash_set<location_t, false, location_hash>;
599 : :
600 : : /* Hash the location of the #include directive to better handle files
601 : : that are included multiple times with different macros defined. */
602 : 6924 : return m_includes_seen->add (linemap_included_from (map));
603 : : }
604 : :
605 : : label_text
606 : 320495 : diagnostic_text_output_format::
607 : : get_location_text (const expanded_location &s) const
608 : : {
609 : 320495 : diagnostic_column_policy column_policy (get_context ());
610 : 320495 : return column_policy.get_location_text (s,
611 : 320495 : show_column_p (),
612 : 320495 : pp_show_color (get_printer ()));
613 : : }
614 : :
615 : : /* Helpers for writing lang-specific starters/finalizers for text output. */
616 : :
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. */
621 : :
622 : : const char *
623 : 326402 : maybe_line_and_column (int line, int col)
624 : : {
625 : 326402 : static char result[32];
626 : :
627 : 326402 : if (line)
628 : : {
629 : 322352 : size_t l
630 : 322352 : = snprintf (result, sizeof (result),
631 : 322352 : col >= 0 ? ":%d:%d" : ":%d", line, col);
632 : 322352 : gcc_checking_assert (l < sizeof (result));
633 : : }
634 : : else
635 : 4050 : result[0] = 0;
636 : 326402 : return result;
637 : : }
638 : :
639 : : void
640 : 307998 : diagnostic_text_output_format::report_current_module (location_t where)
641 : : {
642 : 307998 : pretty_printer *pp = get_printer ();
643 : 307998 : const line_map_ordinary *map = NULL;
644 : :
645 : 307998 : if (pp_needs_newline (pp))
646 : : {
647 : 0 : pp_newline (pp);
648 : 0 : pp_needs_newline (pp) = false;
649 : : }
650 : :
651 : 307998 : if (where <= BUILTINS_LOCATION)
652 : 2889 : return;
653 : :
654 : 305109 : linemap_resolve_location (line_table, where,
655 : : LRK_MACRO_DEFINITION_LOCATION,
656 : : &map);
657 : :
658 : 305109 : if (map && m_last_module != map)
659 : : {
660 : 54005 : m_last_module = map;
661 : 54005 : if (!includes_seen_p (map))
662 : : {
663 : 1790 : bool first = true, need_inc = true, was_module = MAP_MODULE_P (map);
664 : 1790 : expanded_location s = {};
665 : 4067 : do
666 : : {
667 : 4067 : where = linemap_included_from (map);
668 : 4067 : map = linemap_included_from_linemap (line_table, map);
669 : 4067 : bool is_module = MAP_MODULE_P (map);
670 : 4067 : s.file = LINEMAP_FILE (map);
671 : 4067 : s.line = SOURCE_LINE (map, where);
672 : 4067 : int col = -1;
673 : 4067 : if (first && show_column_p ())
674 : : {
675 : 875 : s.column = SOURCE_COLUMN (map, where);
676 : 875 : col = get_column_policy ().converted_column (s);
677 : : }
678 : 4067 : const char *line_col = maybe_line_and_column (s.line, col);
679 : 4067 : static const char *const msgs[] =
680 : : {
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"),
689 : : };
690 : :
691 : 4067 : unsigned index = (was_module ? 6 : is_module ? 4
692 : 3203 : : need_inc ? 2 : 0) + !first;
693 : :
694 : 5941 : pp_verbatim (pp, "%s%s %r%s%s%R",
695 : : first ? "" : was_module ? ", " : ",\n",
696 : 4067 : _(msgs[index]),
697 : : "locus", s.file, line_col);
698 : 4067 : first = false, need_inc = was_module, was_module = is_module;
699 : : }
700 : 4067 : while (!includes_seen_p (map));
701 : 1790 : pp_verbatim (pp, ":");
702 : 1790 : pp_newline (pp);
703 : : }
704 : : }
705 : : }
706 : :
707 : : void
708 : 1211 : default_diagnostic_text_starter (diagnostic_text_output_format &text_output,
709 : : const diagnostic_info *diagnostic)
710 : : {
711 : 1211 : text_output.report_current_module (diagnostic_location (diagnostic));
712 : 1211 : pretty_printer *const pp = text_output.get_printer ();
713 : 1211 : pp_set_prefix (pp, text_output.build_prefix (*diagnostic));
714 : 1211 : }
715 : :
716 : : void
717 : 16197 : default_diagnostic_text_finalizer (diagnostic_text_output_format &text_output,
718 : : const diagnostic_info *diagnostic,
719 : : diagnostic_t)
720 : : {
721 : 16197 : pretty_printer *const pp = text_output.get_printer ();
722 : 16197 : char *saved_prefix = pp_take_prefix (pp);
723 : 16197 : pp_set_prefix (pp, NULL);
724 : 16197 : pp_newline (pp);
725 : 16197 : diagnostic_show_locus (&text_output.get_context (),
726 : 16197 : text_output.get_source_printing_options (),
727 : 16197 : diagnostic->richloc, diagnostic->kind, pp);
728 : 16197 : pp_set_prefix (pp, saved_prefix);
729 : 16197 : pp_flush (pp);
730 : 16197 : }
731 : :
732 : : #if __GNUC__ >= 10
733 : : # pragma GCC diagnostic pop
734 : : #endif
|