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
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
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/>. */
23 #include "coretypes.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"
31 #include "diagnostic-path.h"
33 #include "gcc-rich-location.h"
34 #include "diagnostic-color.h"
35 #include "diagnostic-event-id.h"
37 #include "selftest-diagnostic.h"
39 /* Anonymous namespace for path-printing code. */
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
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 ());
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
)));
74 const diagnostic_path
*m_path
;
78 /* Return true if E1 and E2 can be consolidated into the same run of events
79 when printing a diagnostic_path. */
82 can_consolidate_events (const diagnostic_event
&e1
,
83 const diagnostic_event
&e2
,
86 if (e1
.get_fndecl () != e2
.get_fndecl ())
89 if (e1
.get_stack_depth () != e2
.get_stack_depth ())
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
)
101 /* Neither can be macro-based. */
102 if (linemap_location_from_macro_expansion_p (line_table
, loc1
))
104 if (linemap_location_from_macro_expansion_p (line_table
, loc2
))
108 /* Passed all the tests. */
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. */
117 event_range (const diagnostic_path
*path
, unsigned start_idx
,
118 const diagnostic_event
&initial_event
)
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
))
134 if (check_rich_locations
)
135 if (!m_richloc
.add_location_if_nearby (new_ev
.get_location (),
136 false, &m_path_label
))
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. */
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
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 ());
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
;
197 unsigned m_start_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
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
);
228 if (cur_event_range
->maybe_add_event (event
, idx
, check_rich_locations
))
231 cur_event_range
= new event_range (&path
, idx
, event
);
232 m_ranges
.safe_push (cur_event_range
);
236 /* Write SPACES to PP. */
239 write_indent (pretty_printer
*pp
, int spaces
)
241 for (int i
= 0; i
< spaces
; i
++)
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
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))
257 pp_printf (pp
, "%qs", n
);
262 /* Print path_summary PS to DC, giving an overview of the interprocedural
265 Print the event descriptions in a nested form, printing the event
266 descriptions within calls to diagnostic_show_locus, using labels to
272 +--> 'bar' (events 3-4)
275 +--> 'baz' (events 5-6)
283 +--> 'bar' (events 9-10)
286 +--> 'baz' (events 11-12)
290 If SHOW_DEPTHS is true, append " (depth N)" to the header of each run
293 For events with UNKNOWN_LOCATION, print a summary of each the event. */
296 print_path_summary_as_text (const path_summary
*ps
, diagnostic_context
*dc
,
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
;
320 FOR_EACH_VEC_ELT (ps
->m_ranges
, i
, range
)
322 write_indent (pp
, cur_indent
);
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
);
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);
345 pp_printf (pp
, "events %i-%i",
346 range
->m_start_idx
+ 1, range
->m_end_idx
+ 1);
348 pp_printf (pp
, " (depth %i)", range
->m_stack_depth
);
351 /* Print a run of events. */
353 write_indent (pp
, cur_indent
+ per_frame_indent
);
354 pp_string (pp
, start_line_color
);
356 pp_string (pp
, end_line_color
);
359 char *saved_prefix
= pp_take_prefix (pp
);
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
;
372 pp_set_prefix (pp
, saved_prefix
);
374 write_indent (pp
, cur_indent
+ per_frame_indent
);
375 pp_string (pp
, start_line_color
);
377 pp_string (pp
, end_line_color
);
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
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
);
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
);
418 /* Handle disjoint paths (e.g. a callback at some later
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. */
442 default_tree_diagnostic_path_printer (diagnostic_context
*context
,
443 const diagnostic_path
*path
)
447 const unsigned num_events
= path
->num_events ();
449 switch (context
->path_format
)
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. */
472 inform (event
.get_location (),
473 "%@ %s (fndecl %qD, depth %i)",
474 &event_id
, event_text
.get (),
475 fndecl
, stack_depth
);
477 inform (event
.get_location (),
479 &event_id
, event_text
.get (),
483 inform (event
.get_location (),
484 "%@ %s", &event_id
, event_text
.get ());
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). */
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 ())
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
);
538 /* Disable warnings about missing quoting in GCC diagnostics for the print
539 calls in the tests below. */
541 # pragma GCC diagnostic push
542 # pragma GCC diagnostic ignored "-Wformat-diag"
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
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. */
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);
592 pp_formatted_text (dc
.printer
));
595 /* Verify that print_path_summary works on a purely intraprocedural path. */
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"
617 " | (1): first `free'\n"
618 " | (2): double `free'\n"
620 pp_formatted_text (dc
.printer
));
623 /* Verify that print_path_summary works on an interprocedural path. */
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);
665 (" `test': events 1-2 (depth 0)\n"
667 " | (1): entering `test'\n"
668 " | (2): calling `make_boxed_int'\n"
670 " +--> `make_boxed_int': events 3-4 (depth 1)\n"
672 " | (3): entering `make_boxed_int'\n"
673 " | (4): calling `wrapped_malloc'\n"
675 " +--> `wrapped_malloc': events 5-6 (depth 2)\n"
677 " | (5): entering `wrapped_malloc'\n"
678 " | (6): calling malloc\n"
682 " `test': events 7-8 (depth 0)\n"
684 " | (7): returning to `test'\n"
685 " | (8): calling `free_boxed_int'\n"
687 " +--> `free_boxed_int': events 9-10 (depth 1)\n"
689 " | (9): entering `free_boxed_int'\n"
690 " | (10): calling `wrapped_free'\n"
692 " +--> `wrapped_free': events 11-12 (depth 2)\n"
694 " | (11): entering `wrapped_free'\n"
695 " | (12): calling free\n"
699 " `test': events 13-14 (depth 0)\n"
701 " | (13): returning to `test'\n"
702 " | (14): calling `free_boxed_int'\n"
704 " +--> `free_boxed_int': events 15-16 (depth 1)\n"
706 " | (15): entering `free_boxed_int'\n"
707 " | (16): calling `wrapped_free'\n"
709 " +--> `wrapped_free': events 17-18 (depth 2)\n"
711 " | (17): entering `wrapped_free'\n"
712 " | (18): calling free\n"
714 pp_formatted_text (dc
.printer
));
717 /* Example where we pop the stack to an intermediate frame, rather than the
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);
747 (" `foo': events 1-2 (depth 0)\n"
749 " | (1): entering `foo'\n"
750 " | (2): calling `bar'\n"
752 " +--> `bar': events 3-4 (depth 1)\n"
754 " | (3): entering `bar'\n"
755 " | (4): calling `baz'\n"
757 " +--> `baz': event 5 (depth 2)\n"
759 " | (5): entering `baz'\n"
763 " `bar': events 6-7 (depth 1)\n"
765 " | (6): returning to `bar'\n"
766 " | (7): calling `baz'\n"
768 " +--> `baz': event 8 (depth 2)\n"
770 " | (8): entering `baz'\n"
772 pp_formatted_text (dc
.printer
));
775 /* Verify that print_path_summary is sane in the face of a recursive
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);
799 (" `factorial': events 1-2 (depth 0)\n"
801 " | (1): entering `factorial'\n"
802 " | (2): calling `factorial'\n"
804 " +--> `factorial': events 3-4 (depth 1)\n"
806 " | (3): entering `factorial'\n"
807 " | (4): calling `factorial'\n"
809 " +--> `factorial': events 5-6 (depth 2)\n"
811 " | (5): entering `factorial'\n"
812 " | (6): calling `factorial'\n"
814 " +--> `factorial': event 7 (depth 3)\n"
816 " | (7): entering `factorial'\n"
818 pp_formatted_text (dc
.printer
));
821 /* Run all of the selftests within this file. */
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
);
837 } // namespace selftest
840 # pragma GCC diagnostic pop
843 #endif /* #if CHECKING_P */