Fix gnat.dg/opt39.adb on hppa.
[official-gcc.git] / gcc / tree-diagnostic-path.cc
blob988ed7f6726389a9e52176c8f13463aa7b29fe10
1 /* Paths through the code associated with a diagnostic.
2 Copyright (C) 2019-2023 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "diagnostic.h"
26 #include "tree-pretty-print.h"
27 #include "gimple-pretty-print.h"
28 #include "tree-diagnostic.h"
29 #include "langhooks.h"
30 #include "intl.h"
31 #include "diagnostic-path.h"
32 #include "json.h"
33 #include "gcc-rich-location.h"
34 #include "diagnostic-color.h"
35 #include "diagnostic-event-id.h"
36 #include "selftest.h"
37 #include "selftest-diagnostic.h"
39 /* Anonymous namespace for path-printing code. */
41 namespace {
43 /* Subclass of range_label for showing a particular event
44 when showing a consecutive run of events within a diagnostic_path as
45 labelled ranges within one gcc_rich_location. */
47 class path_label : public range_label
49 public:
50 path_label (const diagnostic_path *path, unsigned start_idx)
51 : m_path (path), m_start_idx (start_idx)
54 label_text get_text (unsigned range_idx) const final override
56 unsigned event_idx = m_start_idx + range_idx;
57 const diagnostic_event &event = m_path->get_event (event_idx);
59 /* Get the description of the event, perhaps with colorization:
60 normally, we don't colorize within a range_label, but this
61 is special-cased for diagnostic paths. */
62 bool colorize = pp_show_color (global_dc->printer);
63 label_text event_text (event.get_desc (colorize));
64 gcc_assert (event_text.get ());
65 pretty_printer pp;
66 pp_show_color (&pp) = pp_show_color (global_dc->printer);
67 diagnostic_event_id_t event_id (event_idx);
68 pp_printf (&pp, "%@ %s", &event_id, event_text.get ());
69 label_text result = label_text::take (xstrdup (pp_formatted_text (&pp)));
70 return result;
73 private:
74 const diagnostic_path *m_path;
75 unsigned m_start_idx;
78 /* Return true if E1 and E2 can be consolidated into the same run of events
79 when printing a diagnostic_path. */
81 static bool
82 can_consolidate_events (const diagnostic_event &e1,
83 const diagnostic_event &e2,
84 bool check_locations)
86 if (e1.get_fndecl () != e2.get_fndecl ())
87 return false;
89 if (e1.get_stack_depth () != e2.get_stack_depth ())
90 return false;
92 if (check_locations)
94 location_t loc1 = e1.get_location ();
95 location_t loc2 = e2.get_location ();
97 if (loc1 < RESERVED_LOCATION_COUNT
98 || loc2 < RESERVED_LOCATION_COUNT)
99 return false;
101 /* Neither can be macro-based. */
102 if (linemap_location_from_macro_expansion_p (line_table, loc1))
103 return false;
104 if (linemap_location_from_macro_expansion_p (line_table, loc2))
105 return false;
108 /* Passed all the tests. */
109 return true;
112 /* A range of consecutive events within a diagnostic_path,
113 all with the same fndecl and stack_depth, and which are suitable
114 to print with a single call to diagnostic_show_locus. */
115 struct event_range
117 event_range (const diagnostic_path *path, unsigned start_idx,
118 const diagnostic_event &initial_event)
119 : m_path (path),
120 m_initial_event (initial_event),
121 m_fndecl (initial_event.get_fndecl ()),
122 m_stack_depth (initial_event.get_stack_depth ()),
123 m_start_idx (start_idx), m_end_idx (start_idx),
124 m_path_label (path, start_idx),
125 m_richloc (initial_event.get_location (), &m_path_label)
128 bool maybe_add_event (const diagnostic_event &new_ev, unsigned idx,
129 bool check_rich_locations)
131 if (!can_consolidate_events (m_initial_event, new_ev,
132 check_rich_locations))
133 return false;
134 if (check_rich_locations)
135 if (!m_richloc.add_location_if_nearby (new_ev.get_location (),
136 false, &m_path_label))
137 return false;
138 m_end_idx = idx;
139 return true;
142 /* Print the events in this range to DC, typically as a single
143 call to the printer's diagnostic_show_locus. */
145 void print (diagnostic_context *dc)
147 location_t initial_loc = m_initial_event.get_location ();
149 /* Emit a span indicating the filename (and line/column) if the
150 line has changed relative to the last call to
151 diagnostic_show_locus. */
152 if (dc->show_caret)
154 expanded_location exploc
155 = linemap_client_expand_location_to_spelling_point
156 (initial_loc, LOCATION_ASPECT_CARET);
157 if (exploc.file != LOCATION_FILE (dc->last_location))
158 dc->start_span (dc, exploc);
161 /* If we have an UNKNOWN_LOCATION (or BUILTINS_LOCATION) as the
162 primary location for an event, diagnostic_show_locus won't print
163 anything.
165 In particular the label for the event won't get printed.
166 Fail more gracefully in this case by showing the event
167 index and text, at no particular location. */
168 if (get_pure_location (initial_loc) <= BUILTINS_LOCATION)
170 for (unsigned i = m_start_idx; i <= m_end_idx; i++)
172 const diagnostic_event &iter_event = m_path->get_event (i);
173 diagnostic_event_id_t event_id (i);
174 label_text event_text (iter_event.get_desc (true));
175 pretty_printer *pp = dc->printer;
176 pp_printf (pp, " %@: %s", &event_id, event_text.get ());
177 pp_newline (pp);
179 return;
182 /* Call diagnostic_show_locus to show the events using labels. */
183 diagnostic_show_locus (dc, &m_richloc, DK_DIAGNOSTIC_PATH);
185 /* If we have a macro expansion, show the expansion to the user. */
186 if (linemap_location_from_macro_expansion_p (line_table, initial_loc))
188 gcc_assert (m_start_idx == m_end_idx);
189 maybe_unwind_expanded_macro_loc (dc, initial_loc);
193 const diagnostic_path *m_path;
194 const diagnostic_event &m_initial_event;
195 tree m_fndecl;
196 int m_stack_depth;
197 unsigned m_start_idx;
198 unsigned m_end_idx;
199 path_label m_path_label;
200 gcc_rich_location m_richloc;
203 /* A struct for grouping together the events in a diagnostic_path into
204 ranges of events, partitioned by stack frame (i.e. by fndecl and
205 stack depth). */
207 struct path_summary
209 path_summary (const diagnostic_path &path, bool check_rich_locations);
211 unsigned get_num_ranges () const { return m_ranges.length (); }
213 auto_delete_vec <event_range> m_ranges;
216 /* path_summary's ctor. */
218 path_summary::path_summary (const diagnostic_path &path,
219 bool check_rich_locations)
221 const unsigned num_events = path.num_events ();
223 event_range *cur_event_range = NULL;
224 for (unsigned idx = 0; idx < num_events; idx++)
226 const diagnostic_event &event = path.get_event (idx);
227 if (cur_event_range)
228 if (cur_event_range->maybe_add_event (event, idx, check_rich_locations))
229 continue;
231 cur_event_range = new event_range (&path, idx, event);
232 m_ranges.safe_push (cur_event_range);
236 /* Write SPACES to PP. */
238 static void
239 write_indent (pretty_printer *pp, int spaces)
241 for (int i = 0; i < spaces; i++)
242 pp_space (pp);
245 /* Print FNDDECL to PP, quoting it if QUOTED is true.
247 We can't use "%qE" here since we can't guarantee the capabilities
248 of PP. */
250 static void
251 print_fndecl (pretty_printer *pp, tree fndecl, bool quoted)
253 const char *n = DECL_NAME (fndecl)
254 ? identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2))
255 : _("<anonymous>");
256 if (quoted)
257 pp_printf (pp, "%qs", n);
258 else
259 pp_string (pp, n);
262 /* Print path_summary PS to DC, giving an overview of the interprocedural
263 calls and returns.
265 Print the event descriptions in a nested form, printing the event
266 descriptions within calls to diagnostic_show_locus, using labels to
267 show the events:
269 'foo' (events 1-2)
270 | NN |
272 +--> 'bar' (events 3-4)
273 | NN |
275 +--> 'baz' (events 5-6)
276 | NN |
278 <------------ +
280 'foo' (events 7-8)
281 | NN |
283 +--> 'bar' (events 9-10)
284 | NN |
286 +--> 'baz' (events 11-12)
287 | NN |
290 If SHOW_DEPTHS is true, append " (depth N)" to the header of each run
291 of events.
293 For events with UNKNOWN_LOCATION, print a summary of each the event. */
295 void
296 print_path_summary_as_text (const path_summary *ps, diagnostic_context *dc,
297 bool show_depths)
299 pretty_printer *pp = dc->printer;
301 const int per_frame_indent = 2;
303 const char *const line_color = "path";
304 const char *start_line_color
305 = colorize_start (pp_show_color (pp), line_color);
306 const char *end_line_color = colorize_stop (pp_show_color (pp));
308 /* Keep track of column numbers of existing '|' characters for
309 stack depths we've already printed. */
310 const int EMPTY = -1;
311 const int DELETED = -2;
312 typedef int_hash <int, EMPTY, DELETED> vbar_hash;
313 hash_map <vbar_hash, int> vbar_column_for_depth;
315 /* Print the ranges. */
316 const int base_indent = 2;
317 int cur_indent = base_indent;
318 unsigned i;
319 event_range *range;
320 FOR_EACH_VEC_ELT (ps->m_ranges, i, range)
322 write_indent (pp, cur_indent);
323 if (i > 0)
325 const event_range *prev_range = ps->m_ranges[i - 1];
326 if (range->m_stack_depth > prev_range->m_stack_depth)
328 /* Show pushed stack frame(s). */
329 const char *push_prefix = "+--> ";
330 pp_string (pp, start_line_color);
331 pp_string (pp, push_prefix);
332 pp_string (pp, end_line_color);
333 cur_indent += strlen (push_prefix);
336 if (range->m_fndecl)
338 print_fndecl (pp, range->m_fndecl, true);
339 pp_string (pp, ": ");
341 if (range->m_start_idx == range->m_end_idx)
342 pp_printf (pp, "event %i",
343 range->m_start_idx + 1);
344 else
345 pp_printf (pp, "events %i-%i",
346 range->m_start_idx + 1, range->m_end_idx + 1);
347 if (show_depths)
348 pp_printf (pp, " (depth %i)", range->m_stack_depth);
349 pp_newline (pp);
351 /* Print a run of events. */
353 write_indent (pp, cur_indent + per_frame_indent);
354 pp_string (pp, start_line_color);
355 pp_string (pp, "|");
356 pp_string (pp, end_line_color);
357 pp_newline (pp);
359 char *saved_prefix = pp_take_prefix (pp);
360 char *prefix;
362 pretty_printer tmp_pp;
363 write_indent (&tmp_pp, cur_indent + per_frame_indent);
364 pp_string (&tmp_pp, start_line_color);
365 pp_string (&tmp_pp, "|");
366 pp_string (&tmp_pp, end_line_color);
367 prefix = xstrdup (pp_formatted_text (&tmp_pp));
369 pp_set_prefix (pp, prefix);
370 pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
371 range->print (dc);
372 pp_set_prefix (pp, saved_prefix);
374 write_indent (pp, cur_indent + per_frame_indent);
375 pp_string (pp, start_line_color);
376 pp_string (pp, "|");
377 pp_string (pp, end_line_color);
378 pp_newline (pp);
381 if (i < ps->m_ranges.length () - 1)
383 const event_range *next_range = ps->m_ranges[i + 1];
385 if (range->m_stack_depth > next_range->m_stack_depth)
387 if (vbar_column_for_depth.get (next_range->m_stack_depth))
389 /* Show returning from stack frame(s), by printing
390 something like:
391 " |\n"
392 " <------------ +\n"
393 " |\n". */
394 int vbar_for_next_frame
395 = *vbar_column_for_depth.get (next_range->m_stack_depth);
397 int indent_for_next_frame
398 = vbar_for_next_frame - per_frame_indent;
399 write_indent (pp, vbar_for_next_frame);
400 pp_string (pp, start_line_color);
401 pp_character (pp, '<');
402 for (int i = indent_for_next_frame + per_frame_indent;
403 i < cur_indent + per_frame_indent - 1; i++)
404 pp_character (pp, '-');
405 pp_character (pp, '+');
406 pp_string (pp, end_line_color);
407 pp_newline (pp);
408 cur_indent = indent_for_next_frame;
410 write_indent (pp, vbar_for_next_frame);
411 pp_string (pp, start_line_color);
412 pp_character (pp, '|');
413 pp_string (pp, end_line_color);
414 pp_newline (pp);
416 else
418 /* Handle disjoint paths (e.g. a callback at some later
419 time). */
420 cur_indent = base_indent;
423 else if (range->m_stack_depth < next_range->m_stack_depth)
425 /* Prepare to show pushed stack frame. */
426 gcc_assert (range->m_stack_depth != EMPTY);
427 gcc_assert (range->m_stack_depth != DELETED);
428 vbar_column_for_depth.put (range->m_stack_depth,
429 cur_indent + per_frame_indent);
430 cur_indent += per_frame_indent;
437 } /* end of anonymous namespace for path-printing code. */
439 /* Print PATH to CONTEXT, according to CONTEXT's path_format. */
441 void
442 default_tree_diagnostic_path_printer (diagnostic_context *context,
443 const diagnostic_path *path)
445 gcc_assert (path);
447 const unsigned num_events = path->num_events ();
449 switch (context->path_format)
451 case DPF_NONE:
452 /* Do nothing. */
453 return;
455 case DPF_SEPARATE_EVENTS:
457 /* A note per event. */
458 for (unsigned i = 0; i < num_events; i++)
460 const diagnostic_event &event = path->get_event (i);
461 label_text event_text (event.get_desc (false));
462 gcc_assert (event_text.get ());
463 diagnostic_event_id_t event_id (i);
464 if (context->show_path_depths)
466 int stack_depth = event.get_stack_depth ();
467 tree fndecl = event.get_fndecl ();
468 /* -fdiagnostics-path-format=separate-events doesn't print
469 fndecl information, so with -fdiagnostics-show-path-depths
470 print the fndecls too, if any. */
471 if (fndecl)
472 inform (event.get_location (),
473 "%@ %s (fndecl %qD, depth %i)",
474 &event_id, event_text.get (),
475 fndecl, stack_depth);
476 else
477 inform (event.get_location (),
478 "%@ %s (depth %i)",
479 &event_id, event_text.get (),
480 stack_depth);
482 else
483 inform (event.get_location (),
484 "%@ %s", &event_id, event_text.get ());
487 break;
489 case DPF_INLINE_EVENTS:
491 /* Consolidate related events. */
492 path_summary summary (*path, true);
493 char *saved_prefix = pp_take_prefix (context->printer);
494 pp_set_prefix (context->printer, NULL);
495 print_path_summary_as_text (&summary, context,
496 context->show_path_depths);
497 pp_flush (context->printer);
498 pp_set_prefix (context->printer, saved_prefix);
503 /* This has to be here, rather than diagnostic-format-json.cc,
504 since diagnostic-format-json.o is within OBJS-libcommon and thus
505 doesn't have access to trees (for m_fndecl). */
507 json::value *
508 default_tree_make_json_for_path (diagnostic_context *context,
509 const diagnostic_path *path)
511 json::array *path_array = new json::array ();
512 for (unsigned i = 0; i < path->num_events (); i++)
514 const diagnostic_event &event = path->get_event (i);
516 json::object *event_obj = new json::object ();
517 if (event.get_location ())
518 event_obj->set ("location",
519 json_from_expanded_location (context,
520 event.get_location ()));
521 label_text event_text (event.get_desc (false));
522 event_obj->set ("description", new json::string (event_text.get ()));
523 if (tree fndecl = event.get_fndecl ())
525 const char *function
526 = identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2));
527 event_obj->set ("function", new json::string (function));
529 event_obj->set ("depth",
530 new json::integer_number (event.get_stack_depth ()));
531 path_array->append (event_obj);
533 return path_array;
536 #if CHECKING_P
538 /* Disable warnings about missing quoting in GCC diagnostics for the print
539 calls in the tests below. */
540 #if __GNUC__ >= 10
541 # pragma GCC diagnostic push
542 # pragma GCC diagnostic ignored "-Wformat-diag"
543 #endif
545 namespace selftest {
547 /* A subclass of simple_diagnostic_path that adds member functions
548 for adding test events. */
550 class test_diagnostic_path : public simple_diagnostic_path
552 public:
553 test_diagnostic_path (pretty_printer *event_pp)
554 : simple_diagnostic_path (event_pp)
558 void add_entry (tree fndecl, int stack_depth)
560 add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
561 "entering %qE", fndecl);
564 void add_return (tree fndecl, int stack_depth)
566 add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
567 "returning to %qE", fndecl);
570 void add_call (tree caller, int caller_stack_depth, tree callee)
572 add_event (UNKNOWN_LOCATION, caller, caller_stack_depth,
573 "calling %qE", callee);
574 add_entry (callee, caller_stack_depth + 1);
578 /* Verify that empty paths are handled gracefully. */
580 static void
581 test_empty_path (pretty_printer *event_pp)
583 test_diagnostic_path path (event_pp);
584 ASSERT_FALSE (path.interprocedural_p ());
586 path_summary summary (path, false);
587 ASSERT_EQ (summary.get_num_ranges (), 0);
589 test_diagnostic_context dc;
590 print_path_summary_as_text (&summary, &dc, true);
591 ASSERT_STREQ ("",
592 pp_formatted_text (dc.printer));
595 /* Verify that print_path_summary works on a purely intraprocedural path. */
597 static void
598 test_intraprocedural_path (pretty_printer *event_pp)
600 tree fntype_void_void
601 = build_function_type_array (void_type_node, 0, NULL);
602 tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
604 test_diagnostic_path path (event_pp);
605 path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
606 path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
608 ASSERT_FALSE (path.interprocedural_p ());
610 path_summary summary (path, false);
611 ASSERT_EQ (summary.get_num_ranges (), 1);
613 test_diagnostic_context dc;
614 print_path_summary_as_text (&summary, &dc, true);
615 ASSERT_STREQ (" `foo': events 1-2 (depth 0)\n"
616 " |\n"
617 " | (1): first `free'\n"
618 " | (2): double `free'\n"
619 " |\n",
620 pp_formatted_text (dc.printer));
623 /* Verify that print_path_summary works on an interprocedural path. */
625 static void
626 test_interprocedural_path_1 (pretty_printer *event_pp)
628 /* Build fndecls. The types aren't quite right, but that
629 doesn't matter for the purposes of this test. */
630 tree fntype_void_void
631 = build_function_type_array (void_type_node, 0, NULL);
632 tree fndecl_test = build_fn_decl ("test", fntype_void_void);
633 tree fndecl_make_boxed_int
634 = build_fn_decl ("make_boxed_int", fntype_void_void);
635 tree fndecl_wrapped_malloc
636 = build_fn_decl ("wrapped_malloc", fntype_void_void);
637 tree fndecl_free_boxed_int
638 = build_fn_decl ("free_boxed_int", fntype_void_void);
639 tree fndecl_wrapped_free
640 = build_fn_decl ("wrapped_free", fntype_void_void);
642 test_diagnostic_path path (event_pp);
643 path.add_entry (fndecl_test, 0);
644 path.add_call (fndecl_test, 0, fndecl_make_boxed_int);
645 path.add_call (fndecl_make_boxed_int, 1, fndecl_wrapped_malloc);
646 path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_malloc, 2, "calling malloc");
647 path.add_return (fndecl_test, 0);
648 path.add_call (fndecl_test, 0, fndecl_free_boxed_int);
649 path.add_call (fndecl_free_boxed_int, 1, fndecl_wrapped_free);
650 path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_free, 2, "calling free");
651 path.add_return (fndecl_test, 0);
652 path.add_call (fndecl_test, 0, fndecl_free_boxed_int);
653 path.add_call (fndecl_free_boxed_int, 1, fndecl_wrapped_free);
654 path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_free, 2, "calling free");
655 ASSERT_EQ (path.num_events (), 18);
657 ASSERT_TRUE (path.interprocedural_p ());
659 path_summary summary (path, false);
660 ASSERT_EQ (summary.get_num_ranges (), 9);
662 test_diagnostic_context dc;
663 print_path_summary_as_text (&summary, &dc, true);
664 ASSERT_STREQ
665 (" `test': events 1-2 (depth 0)\n"
666 " |\n"
667 " | (1): entering `test'\n"
668 " | (2): calling `make_boxed_int'\n"
669 " |\n"
670 " +--> `make_boxed_int': events 3-4 (depth 1)\n"
671 " |\n"
672 " | (3): entering `make_boxed_int'\n"
673 " | (4): calling `wrapped_malloc'\n"
674 " |\n"
675 " +--> `wrapped_malloc': events 5-6 (depth 2)\n"
676 " |\n"
677 " | (5): entering `wrapped_malloc'\n"
678 " | (6): calling malloc\n"
679 " |\n"
680 " <-------------+\n"
681 " |\n"
682 " `test': events 7-8 (depth 0)\n"
683 " |\n"
684 " | (7): returning to `test'\n"
685 " | (8): calling `free_boxed_int'\n"
686 " |\n"
687 " +--> `free_boxed_int': events 9-10 (depth 1)\n"
688 " |\n"
689 " | (9): entering `free_boxed_int'\n"
690 " | (10): calling `wrapped_free'\n"
691 " |\n"
692 " +--> `wrapped_free': events 11-12 (depth 2)\n"
693 " |\n"
694 " | (11): entering `wrapped_free'\n"
695 " | (12): calling free\n"
696 " |\n"
697 " <-------------+\n"
698 " |\n"
699 " `test': events 13-14 (depth 0)\n"
700 " |\n"
701 " | (13): returning to `test'\n"
702 " | (14): calling `free_boxed_int'\n"
703 " |\n"
704 " +--> `free_boxed_int': events 15-16 (depth 1)\n"
705 " |\n"
706 " | (15): entering `free_boxed_int'\n"
707 " | (16): calling `wrapped_free'\n"
708 " |\n"
709 " +--> `wrapped_free': events 17-18 (depth 2)\n"
710 " |\n"
711 " | (17): entering `wrapped_free'\n"
712 " | (18): calling free\n"
713 " |\n",
714 pp_formatted_text (dc.printer));
717 /* Example where we pop the stack to an intermediate frame, rather than the
718 initial one. */
720 static void
721 test_interprocedural_path_2 (pretty_printer *event_pp)
723 /* Build fndecls. The types aren't quite right, but that
724 doesn't matter for the purposes of this test. */
725 tree fntype_void_void
726 = build_function_type_array (void_type_node, 0, NULL);
727 tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
728 tree fndecl_bar = build_fn_decl ("bar", fntype_void_void);
729 tree fndecl_baz = build_fn_decl ("baz", fntype_void_void);
731 test_diagnostic_path path (event_pp);
732 path.add_entry (fndecl_foo, 0);
733 path.add_call (fndecl_foo, 0, fndecl_bar);
734 path.add_call (fndecl_bar, 1, fndecl_baz);
735 path.add_return (fndecl_bar, 1);
736 path.add_call (fndecl_bar, 1, fndecl_baz);
737 ASSERT_EQ (path.num_events (), 8);
739 ASSERT_TRUE (path.interprocedural_p ());
741 path_summary summary (path, false);
742 ASSERT_EQ (summary.get_num_ranges (), 5);
744 test_diagnostic_context dc;
745 print_path_summary_as_text (&summary, &dc, true);
746 ASSERT_STREQ
747 (" `foo': events 1-2 (depth 0)\n"
748 " |\n"
749 " | (1): entering `foo'\n"
750 " | (2): calling `bar'\n"
751 " |\n"
752 " +--> `bar': events 3-4 (depth 1)\n"
753 " |\n"
754 " | (3): entering `bar'\n"
755 " | (4): calling `baz'\n"
756 " |\n"
757 " +--> `baz': event 5 (depth 2)\n"
758 " |\n"
759 " | (5): entering `baz'\n"
760 " |\n"
761 " <------+\n"
762 " |\n"
763 " `bar': events 6-7 (depth 1)\n"
764 " |\n"
765 " | (6): returning to `bar'\n"
766 " | (7): calling `baz'\n"
767 " |\n"
768 " +--> `baz': event 8 (depth 2)\n"
769 " |\n"
770 " | (8): entering `baz'\n"
771 " |\n",
772 pp_formatted_text (dc.printer));
775 /* Verify that print_path_summary is sane in the face of a recursive
776 diagnostic_path. */
778 static void
779 test_recursion (pretty_printer *event_pp)
781 tree fntype_void_void
782 = build_function_type_array (void_type_node, 0, NULL);
783 tree fndecl_factorial = build_fn_decl ("factorial", fntype_void_void);
785 test_diagnostic_path path (event_pp);
786 path.add_entry (fndecl_factorial, 0);
787 for (int depth = 0; depth < 3; depth++)
788 path.add_call (fndecl_factorial, depth, fndecl_factorial);
789 ASSERT_EQ (path.num_events (), 7);
791 ASSERT_TRUE (path.interprocedural_p ());
793 path_summary summary (path, false);
794 ASSERT_EQ (summary.get_num_ranges (), 4);
796 test_diagnostic_context dc;
797 print_path_summary_as_text (&summary, &dc, true);
798 ASSERT_STREQ
799 (" `factorial': events 1-2 (depth 0)\n"
800 " |\n"
801 " | (1): entering `factorial'\n"
802 " | (2): calling `factorial'\n"
803 " |\n"
804 " +--> `factorial': events 3-4 (depth 1)\n"
805 " |\n"
806 " | (3): entering `factorial'\n"
807 " | (4): calling `factorial'\n"
808 " |\n"
809 " +--> `factorial': events 5-6 (depth 2)\n"
810 " |\n"
811 " | (5): entering `factorial'\n"
812 " | (6): calling `factorial'\n"
813 " |\n"
814 " +--> `factorial': event 7 (depth 3)\n"
815 " |\n"
816 " | (7): entering `factorial'\n"
817 " |\n",
818 pp_formatted_text (dc.printer));
821 /* Run all of the selftests within this file. */
823 void
824 tree_diagnostic_path_cc_tests ()
826 auto_fix_quotes fix_quotes;
827 pretty_printer *event_pp = global_dc->printer->clone ();
828 pp_show_color (event_pp) = 0;
829 test_empty_path (event_pp);
830 test_intraprocedural_path (event_pp);
831 test_interprocedural_path_1 (event_pp);
832 test_interprocedural_path_2 (event_pp);
833 test_recursion (event_pp);
834 delete event_pp;
837 } // namespace selftest
839 #if __GNUC__ >= 10
840 # pragma GCC diagnostic pop
841 #endif
843 #endif /* #if CHECKING_P */