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