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