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