LCOV - code coverage report
Current view: top level - gcc - tree-diagnostic-path.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 99.0 % 385 381
Test Date: 2024-04-20 14:03:02 Functions: 95.7 % 23 22
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Paths through the code associated with a diagnostic.
       2                 :             :    Copyright (C) 2019-2024 Free Software Foundation, Inc.
       3                 :             :    Contributed by David Malcolm <dmalcolm@redhat.com>
       4                 :             : 
       5                 :             : This file is part of GCC.
       6                 :             : 
       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.
      11                 :             : 
      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.
      16                 :             : 
      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/>.  */
      20                 :             : 
      21                 :             : #include "config.h"
      22                 :             : #define INCLUDE_VECTOR
      23                 :             : #include "system.h"
      24                 :             : #include "coretypes.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "diagnostic.h"
      27                 :             : #include "tree-pretty-print.h"
      28                 :             : #include "gimple-pretty-print.h"
      29                 :             : #include "tree-diagnostic.h"
      30                 :             : #include "langhooks.h"
      31                 :             : #include "intl.h"
      32                 :             : #include "diagnostic-path.h"
      33                 :             : #include "json.h"
      34                 :             : #include "gcc-rich-location.h"
      35                 :             : #include "diagnostic-color.h"
      36                 :             : #include "diagnostic-event-id.h"
      37                 :             : #include "selftest.h"
      38                 :             : #include "selftest-diagnostic.h"
      39                 :             : 
      40                 :             : /* Anonymous namespace for path-printing code.  */
      41                 :             : 
      42                 :             : namespace {
      43                 :             : 
      44                 :             : /* Subclass of range_label for showing a particular event
      45                 :             :    when showing a consecutive run of events within a diagnostic_path as
      46                 :             :    labelled ranges within one gcc_rich_location.  */
      47                 :             : 
      48                 :         813 : class path_label : public range_label
      49                 :             : {
      50                 :             :  public:
      51                 :         813 :   path_label (const diagnostic_path *path, unsigned start_idx)
      52                 :         813 :   : m_path (path), m_start_idx (start_idx)
      53                 :             :   {}
      54                 :             : 
      55                 :        1511 :   label_text get_text (unsigned range_idx) const final override
      56                 :             :   {
      57                 :        1511 :     unsigned event_idx = m_start_idx + range_idx;
      58                 :        1511 :     const diagnostic_event &event = m_path->get_event (event_idx);
      59                 :             : 
      60                 :             :     /* Get the description of the event, perhaps with colorization:
      61                 :             :        normally, we don't colorize within a range_label, but this
      62                 :             :        is special-cased for diagnostic paths.  */
      63                 :        1511 :     bool colorize = pp_show_color (global_dc->printer);
      64                 :        1511 :     label_text event_text (event.get_desc (colorize));
      65                 :        1511 :     gcc_assert (event_text.get ());
      66                 :        1511 :     pretty_printer pp;
      67                 :        1511 :     pp_show_color (&pp) = pp_show_color (global_dc->printer);
      68                 :        1511 :     diagnostic_event_id_t event_id (event_idx);
      69                 :        1511 :     pp_printf (&pp, "%@ %s", &event_id, event_text.get ());
      70                 :        1511 :     label_text result = label_text::take (xstrdup (pp_formatted_text (&pp)));
      71                 :        3022 :     return result;
      72                 :        1511 :   }
      73                 :             : 
      74                 :             :  private:
      75                 :             :   const diagnostic_path *m_path;
      76                 :             :   unsigned m_start_idx;
      77                 :             : };
      78                 :             : 
      79                 :             : /* Return true if E1 and E2 can be consolidated into the same run of events
      80                 :             :    when printing a diagnostic_path.  */
      81                 :             : 
      82                 :             : static bool
      83                 :        1394 : can_consolidate_events (const diagnostic_event &e1,
      84                 :             :                         const diagnostic_event &e2,
      85                 :             :                         bool check_locations)
      86                 :             : {
      87                 :        1394 :   if (e1.get_thread_id () != e2.get_thread_id ())
      88                 :             :     return false;
      89                 :             : 
      90                 :        1391 :   if (e1.get_fndecl () != e2.get_fndecl ())
      91                 :             :     return false;
      92                 :             : 
      93                 :         940 :   if (e1.get_stack_depth () != e2.get_stack_depth ())
      94                 :             :     return false;
      95                 :             : 
      96                 :         919 :   if (check_locations)
      97                 :             :     {
      98                 :         855 :       location_t loc1 = e1.get_location ();
      99                 :         855 :       location_t loc2 = e2.get_location ();
     100                 :             : 
     101                 :         855 :       if (loc1 < RESERVED_LOCATION_COUNT
     102                 :         855 :           || loc2 < RESERVED_LOCATION_COUNT)
     103                 :             :         return false;
     104                 :             : 
     105                 :             :       /* Neither can be macro-based.  */
     106                 :         853 :       if (linemap_location_from_macro_expansion_p (line_table, loc1))
     107                 :             :         return false;
     108                 :         813 :       if (linemap_location_from_macro_expansion_p (line_table, loc2))
     109                 :             :         return false;
     110                 :             :     }
     111                 :             : 
     112                 :             :   /* Passed all the tests.  */
     113                 :             :   return true;
     114                 :             : }
     115                 :             : 
     116                 :             : struct event_range;
     117                 :             : struct path_summary;
     118                 :             : class thread_event_printer;
     119                 :             : 
     120                 :             : /* A bundle of information about all of the events in a diagnostic_path
     121                 :             :    relating to a specific path, for use by path_summary.  */
     122                 :             : 
     123                 :             : class per_thread_summary
     124                 :             : {
     125                 :             : public:
     126                 :         271 :   per_thread_summary (label_text name, unsigned swimlane_idx)
     127                 :         271 :   : m_name (std::move (name)),
     128                 :         271 :     m_swimlane_idx (swimlane_idx),
     129                 :         271 :     m_min_depth (INT_MAX),
     130                 :         271 :     m_max_depth (INT_MIN)
     131                 :             :   {}
     132                 :             : 
     133                 :        1664 :   void update_depth_limits (int stack_depth)
     134                 :             :   {
     135                 :        1664 :     if (stack_depth < m_min_depth)
     136                 :         282 :       m_min_depth = stack_depth;
     137                 :        1664 :     if (stack_depth > m_max_depth)
     138                 :         491 :       m_max_depth = stack_depth;
     139                 :             :   }
     140                 :             : 
     141                 :           4 :   const char *get_name () const { return m_name.get (); }
     142                 :         813 :   unsigned get_swimlane_index () const { return m_swimlane_idx; }
     143                 :             : 
     144                 :             : private:
     145                 :             :   friend struct path_summary;
     146                 :             :   friend class thread_event_printer;
     147                 :             : 
     148                 :             :   const label_text m_name;
     149                 :             : 
     150                 :             :   /* The "swimlane index" is the order in which this per_thread_summary
     151                 :             :      was created, for use when printing the events.  */
     152                 :             :   const unsigned m_swimlane_idx;
     153                 :             : 
     154                 :             :   // The event ranges specific to this thread:
     155                 :             :   auto_vec<event_range *> m_event_ranges;
     156                 :             :   int m_min_depth;
     157                 :             :   int m_max_depth;
     158                 :             : };
     159                 :             : 
     160                 :             : /* A range of consecutive events within a diagnostic_path, all within the
     161                 :             :    same thread, and with the same fndecl and stack_depth, and which are suitable
     162                 :             :    to print with a single call to diagnostic_show_locus.  */
     163                 :         813 : struct event_range
     164                 :             : {
     165                 :         813 :   event_range (const diagnostic_path *path, unsigned start_idx,
     166                 :             :                const diagnostic_event &initial_event,
     167                 :             :                const per_thread_summary &t)
     168                 :         813 :   : m_path (path),
     169                 :         813 :     m_initial_event (initial_event),
     170                 :         813 :     m_fndecl (initial_event.get_fndecl ()),
     171                 :         813 :     m_stack_depth (initial_event.get_stack_depth ()),
     172                 :         813 :     m_start_idx (start_idx), m_end_idx (start_idx),
     173                 :         813 :     m_path_label (path, start_idx),
     174                 :         813 :     m_richloc (initial_event.get_location (), &m_path_label),
     175                 :         813 :     m_thread_id (initial_event.get_thread_id ()),
     176                 :         813 :     m_per_thread_summary (t)
     177                 :         813 :   {}
     178                 :             : 
     179                 :        1394 :   bool maybe_add_event (const diagnostic_event &new_ev, unsigned idx,
     180                 :             :                         bool check_rich_locations)
     181                 :             :   {
     182                 :        1394 :     if (!can_consolidate_events (m_initial_event, new_ev,
     183                 :             :                                  check_rich_locations))
     184                 :             :       return false;
     185                 :         852 :     if (check_rich_locations)
     186                 :         788 :       if (!m_richloc.add_location_if_nearby (new_ev.get_location (),
     187                 :             :                                              false, &m_path_label))
     188                 :             :         return false;
     189                 :         851 :     m_end_idx = idx;
     190                 :         851 :     return true;
     191                 :             :   }
     192                 :             : 
     193                 :             :   /* Print the events in this range to DC, typically as a single
     194                 :             :      call to the printer's diagnostic_show_locus.  */
     195                 :             : 
     196                 :         813 :   void print (diagnostic_context *dc, pretty_printer *pp)
     197                 :             :   {
     198                 :         813 :     location_t initial_loc = m_initial_event.get_location ();
     199                 :             : 
     200                 :             :     /* Emit a span indicating the filename (and line/column) if the
     201                 :             :        line has changed relative to the last call to
     202                 :             :        diagnostic_show_locus.  */
     203                 :         813 :     if (dc->m_source_printing.enabled)
     204                 :             :       {
     205                 :         813 :         expanded_location exploc
     206                 :             :           = linemap_client_expand_location_to_spelling_point
     207                 :         813 :           (line_table, initial_loc, LOCATION_ASPECT_CARET);
     208                 :         813 :         if (exploc.file != LOCATION_FILE (dc->m_last_location))
     209                 :          29 :           diagnostic_start_span (dc) (dc, exploc);
     210                 :             :       }
     211                 :             : 
     212                 :             :     /* If we have an UNKNOWN_LOCATION (or BUILTINS_LOCATION) as the
     213                 :             :        primary location for an event, diagnostic_show_locus won't print
     214                 :             :        anything.
     215                 :             : 
     216                 :             :        In particular the label for the event won't get printed.
     217                 :             :        Fail more gracefully in this case by showing the event
     218                 :             :        index and text, at no particular location.  */
     219                 :         813 :     if (get_pure_location (initial_loc) <= BUILTINS_LOCATION)
     220                 :             :       {
     221                 :         242 :         for (unsigned i = m_start_idx; i <= m_end_idx; i++)
     222                 :             :           {
     223                 :         153 :             const diagnostic_event &iter_event = m_path->get_event (i);
     224                 :         153 :             diagnostic_event_id_t event_id (i);
     225                 :         153 :             label_text event_text (iter_event.get_desc (true));
     226                 :         153 :             pp_printf (pp, " %@: %s", &event_id, event_text.get ());
     227                 :         153 :             pp_newline (pp);
     228                 :         153 :           }
     229                 :             :         return;
     230                 :             :       }
     231                 :             : 
     232                 :             :     /* Call diagnostic_show_locus to show the events using labels.  */
     233                 :         724 :     diagnostic_show_locus (dc, &m_richloc, DK_DIAGNOSTIC_PATH, pp);
     234                 :             : 
     235                 :             :     /* If we have a macro expansion, show the expansion to the user.  */
     236                 :         724 :     if (linemap_location_from_macro_expansion_p (line_table, initial_loc))
     237                 :             :       {
     238                 :          52 :         gcc_assert (m_start_idx == m_end_idx);
     239                 :          52 :         maybe_unwind_expanded_macro_loc (dc, initial_loc);
     240                 :             :       }
     241                 :             :   }
     242                 :             : 
     243                 :             :   const diagnostic_path *m_path;
     244                 :             :   const diagnostic_event &m_initial_event;
     245                 :             :   tree m_fndecl;
     246                 :             :   int m_stack_depth;
     247                 :             :   unsigned m_start_idx;
     248                 :             :   unsigned m_end_idx;
     249                 :             :   path_label m_path_label;
     250                 :             :   gcc_rich_location m_richloc;
     251                 :             :   diagnostic_thread_id_t m_thread_id;
     252                 :             :   const per_thread_summary &m_per_thread_summary;
     253                 :             : };
     254                 :             : 
     255                 :             : /* A struct for grouping together the events in a diagnostic_path into
     256                 :             :    ranges of events, partitioned by thread and by stack frame (i.e. by fndecl
     257                 :             :    and stack depth).  */
     258                 :             : 
     259                 :             : struct path_summary
     260                 :             : {
     261                 :             :   path_summary (const diagnostic_path &path, bool check_rich_locations);
     262                 :             : 
     263                 :          40 :   unsigned get_num_ranges () const { return m_ranges.length (); }
     264                 :        2439 :   bool multithreaded_p () const { return m_per_thread_summary.length () > 1; }
     265                 :             : 
     266                 :             :   const per_thread_summary &get_events_for_thread_id (diagnostic_thread_id_t tid)
     267                 :             :   {
     268                 :             :     per_thread_summary **slot = m_thread_id_to_events.get (tid);
     269                 :             :     gcc_assert (slot);
     270                 :             :     gcc_assert (*slot);
     271                 :             :     return **slot;
     272                 :             :   }
     273                 :             : 
     274                 :             :   auto_delete_vec <event_range> m_ranges;
     275                 :             :   auto_delete_vec <per_thread_summary> m_per_thread_summary;
     276                 :             :   hash_map<int_hash<diagnostic_thread_id_t, -1, -2>,
     277                 :             :            per_thread_summary *> m_thread_id_to_events;
     278                 :             : 
     279                 :             : private:
     280                 :             :   per_thread_summary &
     281                 :        1664 :   get_or_create_events_for_thread_id (const diagnostic_path &path,
     282                 :             :                                       diagnostic_thread_id_t tid)
     283                 :             :   {
     284                 :        1664 :     if (per_thread_summary **slot = m_thread_id_to_events.get (tid))
     285                 :        1393 :       return **slot;
     286                 :             : 
     287                 :         271 :     const diagnostic_thread &thread = path.get_thread (tid);
     288                 :         271 :     per_thread_summary *pts = new per_thread_summary (thread.get_name (false),
     289                 :         272 :                                                 m_per_thread_summary.length ());
     290                 :         271 :     m_thread_id_to_events.put (tid, pts);
     291                 :         271 :     m_per_thread_summary.safe_push (pts);
     292                 :         271 :     return *pts;
     293                 :             :   }
     294                 :             : };
     295                 :             : 
     296                 :             : /* path_summary's ctor.  */
     297                 :             : 
     298                 :         274 : path_summary::path_summary (const diagnostic_path &path,
     299                 :         274 :                             bool check_rich_locations)
     300                 :             : {
     301                 :         274 :   const unsigned num_events = path.num_events ();
     302                 :             : 
     303                 :         274 :   event_range *cur_event_range = NULL;
     304                 :        1938 :   for (unsigned idx = 0; idx < num_events; idx++)
     305                 :             :     {
     306                 :        1664 :       const diagnostic_event &event = path.get_event (idx);
     307                 :        1664 :       const diagnostic_thread_id_t thread_id = event.get_thread_id ();
     308                 :        1664 :       per_thread_summary &pts
     309                 :        1664 :         = get_or_create_events_for_thread_id (path, thread_id);
     310                 :             : 
     311                 :        1664 :       pts.update_depth_limits (event.get_stack_depth ());
     312                 :             : 
     313                 :        1664 :       if (cur_event_range)
     314                 :        1394 :         if (cur_event_range->maybe_add_event (event, idx, check_rich_locations))
     315                 :         851 :           continue;
     316                 :             : 
     317                 :         813 :       cur_event_range = new event_range (&path, idx, event, pts);
     318                 :         813 :       m_ranges.safe_push (cur_event_range);
     319                 :         813 :       pts.m_event_ranges.safe_push (cur_event_range);
     320                 :             :     }
     321                 :         274 : }
     322                 :             : 
     323                 :             : /* Write SPACES to PP.  */
     324                 :             : 
     325                 :             : static void
     326                 :        3490 : write_indent (pretty_printer *pp, int spaces)
     327                 :             : {
     328                 :       30284 :   for (int i = 0; i < spaces; i++)
     329                 :       26794 :     pp_space (pp);
     330                 :           0 : }
     331                 :             : 
     332                 :             : /* Print FNDDECL to PP, quoting it if QUOTED is true.
     333                 :             : 
     334                 :             :    We can't use "%qE" here since we can't guarantee the capabilities
     335                 :             :    of PP.  */
     336                 :             : 
     337                 :             : static void
     338                 :         798 : print_fndecl (pretty_printer *pp, tree fndecl, bool quoted)
     339                 :             : {
     340                 :         798 :   const char *n = DECL_NAME (fndecl)
     341                 :         798 :     ? identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2))
     342                 :           0 :     : _("<anonymous>");
     343                 :         798 :   if (quoted)
     344                 :         798 :     pp_printf (pp, "%qs", n);
     345                 :             :   else
     346                 :           0 :     pp_string (pp, n);
     347                 :         798 : }
     348                 :             : 
     349                 :             : static const int base_indent = 2;
     350                 :             : static const int per_frame_indent = 2;
     351                 :             : 
     352                 :             : /* A bundle of state for printing event_range instances for a particular
     353                 :             :    thread.  */
     354                 :             : 
     355                 :         272 : class thread_event_printer
     356                 :             : {
     357                 :             : public:
     358                 :         271 :   thread_event_printer (const per_thread_summary &t, bool show_depths)
     359                 :         271 :   : m_per_thread_summary (t),
     360                 :         271 :     m_show_depths (show_depths),
     361                 :         271 :     m_cur_indent (base_indent),
     362                 :         271 :     m_vbar_column_for_depth (),
     363                 :         271 :     m_num_printed (0)
     364                 :             :   {
     365                 :         271 :   }
     366                 :             : 
     367                 :             :   /* Get the previous event_range within this thread, if any.  */
     368                 :         813 :   const event_range *get_any_prev_range () const
     369                 :             :   {
     370                 :         813 :     if (m_num_printed > 0)
     371                 :         542 :       return m_per_thread_summary.m_event_ranges[m_num_printed - 1];
     372                 :             :     else
     373                 :             :       return nullptr;
     374                 :             :   }
     375                 :             : 
     376                 :             :   /* Get the next event_range within this thread, if any.  */
     377                 :         813 :   const event_range *get_any_next_range () const
     378                 :             :   {
     379                 :        1626 :     if (m_num_printed < m_per_thread_summary.m_event_ranges.length () - 1)
     380                 :         542 :       return m_per_thread_summary.m_event_ranges[m_num_printed + 1];
     381                 :             :     else
     382                 :             :       return nullptr;
     383                 :             :   }
     384                 :             : 
     385                 :         813 :   void print_swimlane_for_event_range (diagnostic_context *dc,
     386                 :             :                                        pretty_printer *pp,
     387                 :             :                                        event_range *range)
     388                 :             :   {
     389                 :         813 :     const char *const line_color = "path";
     390                 :         813 :     const char *start_line_color
     391                 :         813 :       = colorize_start (pp_show_color (pp), line_color);
     392                 :         813 :     const char *end_line_color = colorize_stop (pp_show_color (pp));
     393                 :             : 
     394                 :         813 :     write_indent (pp, m_cur_indent);
     395                 :         813 :     if (const event_range *prev_range = get_any_prev_range ())
     396                 :             :       {
     397                 :         542 :         if (range->m_stack_depth > prev_range->m_stack_depth)
     398                 :             :           {
     399                 :             :             /* Show pushed stack frame(s).  */
     400                 :         342 :             const char *push_prefix = "+--> ";
     401                 :         342 :             pp_string (pp, start_line_color);
     402                 :         342 :             pp_string (pp, push_prefix);
     403                 :         342 :             pp_string (pp, end_line_color);
     404                 :         342 :             m_cur_indent += strlen (push_prefix);
     405                 :             :           }
     406                 :             :       }
     407                 :         813 :     if (range->m_fndecl)
     408                 :             :       {
     409                 :         798 :         print_fndecl (pp, range->m_fndecl, true);
     410                 :         798 :         pp_string (pp, ": ");
     411                 :             :       }
     412                 :         813 :     if (range->m_start_idx == range->m_end_idx)
     413                 :         256 :       pp_printf (pp, "event %i",
     414                 :             :                  range->m_start_idx + 1);
     415                 :             :     else
     416                 :         557 :       pp_printf (pp, "events %i-%i",
     417                 :             :                  range->m_start_idx + 1, range->m_end_idx + 1);
     418                 :         813 :     if (m_show_depths)
     419                 :         289 :       pp_printf (pp, " (depth %i)", range->m_stack_depth);
     420                 :         813 :     pp_newline (pp);
     421                 :             : 
     422                 :             :     /* Print a run of events.  */
     423                 :         813 :     {
     424                 :         813 :       write_indent (pp, m_cur_indent + per_frame_indent);
     425                 :         813 :       pp_string (pp, start_line_color);
     426                 :         813 :       pp_string (pp, "|");
     427                 :         813 :       pp_string (pp, end_line_color);
     428                 :         813 :       pp_newline (pp);
     429                 :             : 
     430                 :         813 :       char *saved_prefix = pp_take_prefix (pp);
     431                 :         813 :       char *prefix;
     432                 :         813 :       {
     433                 :         813 :         pretty_printer tmp_pp;
     434                 :         813 :         write_indent (&tmp_pp, m_cur_indent + per_frame_indent);
     435                 :         813 :         pp_string (&tmp_pp, start_line_color);
     436                 :         813 :         pp_string (&tmp_pp, "|");
     437                 :         813 :         pp_string (&tmp_pp, end_line_color);
     438                 :         813 :         prefix = xstrdup (pp_formatted_text (&tmp_pp));
     439                 :         813 :       }
     440                 :         813 :       pp_set_prefix (pp, prefix);
     441                 :         813 :       pp_prefixing_rule (pp) = DIAGNOSTICS_SHOW_PREFIX_EVERY_LINE;
     442                 :         813 :       range->print (dc, pp);
     443                 :         813 :       pp_set_prefix (pp, saved_prefix);
     444                 :             : 
     445                 :         813 :       write_indent (pp, m_cur_indent + per_frame_indent);
     446                 :         813 :       pp_string (pp, start_line_color);
     447                 :         813 :       pp_string (pp, "|");
     448                 :         813 :       pp_string (pp, end_line_color);
     449                 :         813 :       pp_newline (pp);
     450                 :             :     }
     451                 :             : 
     452                 :         813 :     if (const event_range *next_range = get_any_next_range ())
     453                 :             :       {
     454                 :         542 :         if (range->m_stack_depth > next_range->m_stack_depth)
     455                 :             :           {
     456                 :         130 :             if (m_vbar_column_for_depth.get (next_range->m_stack_depth))
     457                 :             :               {
     458                 :             :                 /* Show returning from stack frame(s), by printing
     459                 :             :                    something like:
     460                 :             :                    "                   |\n"
     461                 :             :                    "     <------------ +\n"
     462                 :             :                    "     |\n".  */
     463                 :         119 :                 int vbar_for_next_frame
     464                 :         119 :                   = *m_vbar_column_for_depth.get (next_range->m_stack_depth);
     465                 :             : 
     466                 :         119 :                 int indent_for_next_frame
     467                 :             :                   = vbar_for_next_frame - per_frame_indent;
     468                 :         119 :                 write_indent (pp, vbar_for_next_frame);
     469                 :         119 :                 pp_string (pp, start_line_color);
     470                 :         119 :                 pp_character (pp, '<');
     471                 :        1050 :                 for (int i = indent_for_next_frame + per_frame_indent;
     472                 :        1050 :                      i < m_cur_indent + per_frame_indent - 1; i++)
     473                 :         931 :                   pp_character (pp, '-');
     474                 :         119 :                 pp_character (pp, '+');
     475                 :         119 :                 pp_string (pp, end_line_color);
     476                 :         119 :                 pp_newline (pp);
     477                 :         119 :                 m_cur_indent = indent_for_next_frame;
     478                 :             : 
     479                 :         119 :                 write_indent (pp, vbar_for_next_frame);
     480                 :         119 :                 pp_string (pp, start_line_color);
     481                 :         119 :                 pp_character (pp, '|');
     482                 :         119 :                 pp_string (pp, end_line_color);
     483                 :         119 :                 pp_newline (pp);
     484                 :             :               }
     485                 :             :             else
     486                 :             :               {
     487                 :             :                 /* Handle disjoint paths (e.g. a callback at some later
     488                 :             :                    time).  */
     489                 :          11 :                 m_cur_indent = base_indent;
     490                 :             :               }
     491                 :             :           }
     492                 :         412 :         else if (range->m_stack_depth < next_range->m_stack_depth)
     493                 :             :           {
     494                 :             :             /* Prepare to show pushed stack frame.  */
     495                 :         342 :             gcc_assert (range->m_stack_depth != EMPTY);
     496                 :         342 :             gcc_assert (range->m_stack_depth != DELETED);
     497                 :         342 :             m_vbar_column_for_depth.put (range->m_stack_depth,
     498                 :         342 :                                          m_cur_indent + per_frame_indent);
     499                 :         342 :             m_cur_indent += per_frame_indent;
     500                 :             :           }
     501                 :             :       }
     502                 :             : 
     503                 :         813 :     m_num_printed++;
     504                 :         813 :   }
     505                 :             : 
     506                 :             :   int get_cur_indent () const { return m_cur_indent; }
     507                 :             : 
     508                 :             : private:
     509                 :             :   const per_thread_summary &m_per_thread_summary;
     510                 :             :   bool m_show_depths;
     511                 :             : 
     512                 :             :   /* Print the ranges.  */
     513                 :             :   int m_cur_indent;
     514                 :             : 
     515                 :             :   /* Keep track of column numbers of existing '|' characters for
     516                 :             :      stack depths we've already printed.  */
     517                 :             :   static const int EMPTY = -1;
     518                 :             :   static const int DELETED = -2;
     519                 :             :   typedef int_hash <int, EMPTY, DELETED> vbar_hash;
     520                 :             :   hash_map <vbar_hash, int> m_vbar_column_for_depth;
     521                 :             : 
     522                 :             :   /* How many event ranges within this swimlane have we printed.
     523                 :             :      This is the index of the next event_range to print.  */
     524                 :             :   unsigned  m_num_printed;
     525                 :             : };
     526                 :             : 
     527                 :             : /* Print path_summary PS to DC, giving an overview of the interprocedural
     528                 :             :    calls and returns.
     529                 :             : 
     530                 :             :    Print the event descriptions in a nested form, printing the event
     531                 :             :    descriptions within calls to diagnostic_show_locus, using labels to
     532                 :             :    show the events:
     533                 :             : 
     534                 :             :    'foo' (events 1-2)
     535                 :             :      | NN |
     536                 :             :      |    |
     537                 :             :      +--> 'bar' (events 3-4)
     538                 :             :             | NN |
     539                 :             :             |    |
     540                 :             :             +--> 'baz' (events 5-6)
     541                 :             :                    | NN |
     542                 :             :                    |    |
     543                 :             :      <------------ +
     544                 :             :      |
     545                 :             :    'foo' (events 7-8)
     546                 :             :      | NN |
     547                 :             :      |    |
     548                 :             :      +--> 'bar' (events 9-10)
     549                 :             :             | NN |
     550                 :             :             |    |
     551                 :             :             +--> 'baz' (events 11-12)
     552                 :             :                    | NN |
     553                 :             :                    |    |
     554                 :             : 
     555                 :             :    If SHOW_DEPTHS is true, append " (depth N)" to the header of each run
     556                 :             :    of events.
     557                 :             : 
     558                 :             :    For events with UNKNOWN_LOCATION, print a summary of each the event.  */
     559                 :             : 
     560                 :             : static void
     561                 :         274 : print_path_summary_as_text (const path_summary *ps, diagnostic_context *dc,
     562                 :             :                             bool show_depths)
     563                 :             : {
     564                 :         274 :   pretty_printer *pp = dc->printer;
     565                 :             : 
     566                 :         274 :   std::vector<thread_event_printer> thread_event_printers;
     567                 :        1085 :   for (auto t : ps->m_per_thread_summary)
     568                 :         271 :     thread_event_printers.push_back (thread_event_printer (*t, show_depths));
     569                 :             : 
     570                 :             :   unsigned i;
     571                 :             :   event_range *range;
     572                 :        1087 :   FOR_EACH_VEC_ELT (ps->m_ranges, i, range)
     573                 :             :     {
     574                 :         813 :       const int swimlane_idx
     575                 :         813 :         = range->m_per_thread_summary.get_swimlane_index ();
     576                 :         813 :       if (ps->multithreaded_p ())
     577                 :           6 :         if (i == 0 || ps->m_ranges[i - 1]->m_thread_id != range->m_thread_id)
     578                 :             :           {
     579                 :           4 :             if (i > 0)
     580                 :           3 :               pp_newline (pp);
     581                 :           4 :             pp_printf (pp, "Thread: %qs",
     582                 :           4 :                        range->m_per_thread_summary.get_name ());
     583                 :           4 :             pp_newline (pp);
     584                 :             :           }
     585                 :         813 :       thread_event_printer &tep = thread_event_printers[swimlane_idx];
     586                 :         813 :       tep.print_swimlane_for_event_range (dc, pp, range);
     587                 :             :     }
     588                 :         274 : }
     589                 :             : 
     590                 :             : } /* end of anonymous namespace for path-printing code.  */
     591                 :             : 
     592                 :             : /* Print PATH to CONTEXT, according to CONTEXT's path_format.  */
     593                 :             : 
     594                 :             : void
     595                 :        4418 : default_tree_diagnostic_path_printer (diagnostic_context *context,
     596                 :             :                                       const diagnostic_path *path)
     597                 :             : {
     598                 :        4418 :   gcc_assert (path);
     599                 :             : 
     600                 :        4418 :   const unsigned num_events = path->num_events ();
     601                 :             : 
     602                 :        4418 :   switch (context->get_path_format ())
     603                 :             :     {
     604                 :             :     case DPF_NONE:
     605                 :             :       /* Do nothing.  */
     606                 :             :       return;
     607                 :             : 
     608                 :             :     case DPF_SEPARATE_EVENTS:
     609                 :             :       {
     610                 :             :         /* A note per event.  */
     611                 :       21107 :         for (unsigned i = 0; i < num_events; i++)
     612                 :             :           {
     613                 :       16949 :             const diagnostic_event &event = path->get_event (i);
     614                 :       16949 :             label_text event_text (event.get_desc (false));
     615                 :       16949 :             gcc_assert (event_text.get ());
     616                 :       16949 :             diagnostic_event_id_t event_id (i);
     617                 :       16949 :             if (context->show_path_depths_p ())
     618                 :             :               {
     619                 :         215 :                 int stack_depth = event.get_stack_depth ();
     620                 :         215 :                 tree fndecl = event.get_fndecl ();
     621                 :             :                 /* -fdiagnostics-path-format=separate-events doesn't print
     622                 :             :                    fndecl information, so with -fdiagnostics-show-path-depths
     623                 :             :                    print the fndecls too, if any.  */
     624                 :         215 :                 if (fndecl)
     625                 :         215 :                   inform (event.get_location (),
     626                 :             :                           "%@ %s (fndecl %qD, depth %i)",
     627                 :             :                           &event_id, event_text.get (),
     628                 :             :                           fndecl, stack_depth);
     629                 :             :                 else
     630                 :           0 :                   inform (event.get_location (),
     631                 :             :                           "%@ %s (depth %i)",
     632                 :             :                           &event_id, event_text.get (),
     633                 :             :                           stack_depth);
     634                 :             :               }
     635                 :             :             else
     636                 :       16734 :               inform (event.get_location (),
     637                 :             :                       "%@ %s", &event_id, event_text.get ());
     638                 :       16949 :           }
     639                 :             :       }
     640                 :             :       break;
     641                 :             : 
     642                 :         254 :     case DPF_INLINE_EVENTS:
     643                 :         254 :       {
     644                 :             :         /* Consolidate related events.  */
     645                 :         254 :         path_summary summary (*path, true);
     646                 :         254 :         char *saved_prefix = pp_take_prefix (context->printer);
     647                 :         254 :         pp_set_prefix (context->printer, NULL);
     648                 :         254 :         print_path_summary_as_text (&summary, context,
     649                 :         254 :                                     context->show_path_depths_p ());
     650                 :         254 :         pp_flush (context->printer);
     651                 :         254 :         pp_set_prefix (context->printer, saved_prefix);
     652                 :         254 :       }
     653                 :         254 :       break;
     654                 :             :     }
     655                 :             : }
     656                 :             : 
     657                 :             : /* This has to be here, rather than diagnostic-format-json.cc,
     658                 :             :    since diagnostic-format-json.o is within OBJS-libcommon and thus
     659                 :             :    doesn't have access to trees (for m_fndecl).  */
     660                 :             : 
     661                 :             : json::value *
     662                 :           6 : default_tree_make_json_for_path (diagnostic_context *context,
     663                 :             :                                  const diagnostic_path *path)
     664                 :             : {
     665                 :           6 :   json::array *path_array = new json::array ();
     666                 :          19 :   for (unsigned i = 0; i < path->num_events (); i++)
     667                 :             :     {
     668                 :          13 :       const diagnostic_event &event = path->get_event (i);
     669                 :             : 
     670                 :          13 :       json::object *event_obj = new json::object ();
     671                 :          13 :       if (event.get_location ())
     672                 :          13 :         event_obj->set ("location",
     673                 :             :                         json_from_expanded_location (context,
     674                 :          13 :                                                      event.get_location ()));
     675                 :          13 :       label_text event_text (event.get_desc (false));
     676                 :          13 :       event_obj->set_string ("description", event_text.get ());
     677                 :          13 :       if (tree fndecl = event.get_fndecl ())
     678                 :             :         {
     679                 :           8 :           const char *function
     680                 :           8 :             = identifier_to_locale (lang_hooks.decl_printable_name (fndecl, 2));
     681                 :           8 :           event_obj->set_string ("function", function);
     682                 :             :         }
     683                 :          13 :       event_obj->set_integer ("depth", event.get_stack_depth ());
     684                 :          13 :       path_array->append (event_obj);
     685                 :          13 :     }
     686                 :           6 :   return path_array;
     687                 :             : }
     688                 :             : 
     689                 :             : #if CHECKING_P
     690                 :             : 
     691                 :             : /* Disable warnings about missing quoting in GCC diagnostics for the print
     692                 :             :    calls in the tests below.  */
     693                 :             : #if __GNUC__ >= 10
     694                 :             : #  pragma GCC diagnostic push
     695                 :             : #  pragma GCC diagnostic ignored "-Wformat-diag"
     696                 :             : #endif
     697                 :             : 
     698                 :             : namespace selftest {
     699                 :             : 
     700                 :             : /* A subclass of simple_diagnostic_path that adds member functions
     701                 :             :    for adding test events.  */
     702                 :             : 
     703                 :          40 : class test_diagnostic_path : public simple_diagnostic_path
     704                 :             : {
     705                 :             :  public:
     706                 :          20 :   test_diagnostic_path (pretty_printer *event_pp)
     707                 :          40 :   : simple_diagnostic_path (event_pp)
     708                 :             :   {
     709                 :             :   }
     710                 :             : 
     711                 :          60 :   void add_entry (tree fndecl, int stack_depth)
     712                 :             :   {
     713                 :          60 :     add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
     714                 :             :                "entering %qE", fndecl);
     715                 :             :   }
     716                 :             : 
     717                 :          12 :   void add_return (tree fndecl, int stack_depth)
     718                 :             :   {
     719                 :          12 :     add_event (UNKNOWN_LOCATION, fndecl, stack_depth,
     720                 :             :                "returning to %qE", fndecl);
     721                 :             :   }
     722                 :             : 
     723                 :          48 :   void add_call (tree caller, int caller_stack_depth, tree callee)
     724                 :             :   {
     725                 :          48 :     add_event (UNKNOWN_LOCATION, caller, caller_stack_depth,
     726                 :             :                "calling %qE", callee);
     727                 :          48 :     add_entry (callee, caller_stack_depth + 1);
     728                 :          48 :   }
     729                 :             : };
     730                 :             : 
     731                 :             : /* Verify that empty paths are handled gracefully.  */
     732                 :             : 
     733                 :             : static void
     734                 :           4 : test_empty_path (pretty_printer *event_pp)
     735                 :             : {
     736                 :           4 :   test_diagnostic_path path (event_pp);
     737                 :           4 :   ASSERT_FALSE (path.interprocedural_p ());
     738                 :             : 
     739                 :           4 :   path_summary summary (path, false);
     740                 :           4 :   ASSERT_EQ (summary.get_num_ranges (), 0);
     741                 :             : 
     742                 :           4 :   test_diagnostic_context dc;
     743                 :           4 :   print_path_summary_as_text (&summary, &dc, true);
     744                 :           4 :   ASSERT_STREQ ("",
     745                 :             :                 pp_formatted_text (dc.printer));
     746                 :           4 : }
     747                 :             : 
     748                 :             : /* Verify that print_path_summary works on a purely intraprocedural path.  */
     749                 :             : 
     750                 :             : static void
     751                 :           4 : test_intraprocedural_path (pretty_printer *event_pp)
     752                 :             : {
     753                 :           4 :   tree fntype_void_void
     754                 :           4 :     = build_function_type_array (void_type_node, 0, NULL);
     755                 :           4 :   tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
     756                 :             : 
     757                 :           4 :   test_diagnostic_path path (event_pp);
     758                 :           4 :   path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "first %qs", "free");
     759                 :           4 :   path.add_event (UNKNOWN_LOCATION, fndecl_foo, 0, "double %qs", "free");
     760                 :             : 
     761                 :           4 :   ASSERT_FALSE (path.interprocedural_p ());
     762                 :             : 
     763                 :           4 :   path_summary summary (path, false);
     764                 :           4 :   ASSERT_EQ (summary.get_num_ranges (), 1);
     765                 :             : 
     766                 :           4 :   test_diagnostic_context dc;
     767                 :           4 :   print_path_summary_as_text (&summary, &dc, true);
     768                 :           4 :   ASSERT_STREQ ("  `foo': events 1-2 (depth 0)\n"
     769                 :             :                 "    |\n"
     770                 :             :                 "    | (1): first `free'\n"
     771                 :             :                 "    | (2): double `free'\n"
     772                 :             :                 "    |\n",
     773                 :             :                 pp_formatted_text (dc.printer));
     774                 :           4 : }
     775                 :             : 
     776                 :             : /* Verify that print_path_summary works on an interprocedural path.  */
     777                 :             : 
     778                 :             : static void
     779                 :           4 : test_interprocedural_path_1 (pretty_printer *event_pp)
     780                 :             : {
     781                 :             :   /* Build fndecls.  The types aren't quite right, but that
     782                 :             :      doesn't matter for the purposes of this test.  */
     783                 :           4 :   tree fntype_void_void
     784                 :           4 :     = build_function_type_array (void_type_node, 0, NULL);
     785                 :           4 :   tree fndecl_test = build_fn_decl ("test", fntype_void_void);
     786                 :           4 :   tree fndecl_make_boxed_int
     787                 :           4 :     = build_fn_decl ("make_boxed_int", fntype_void_void);
     788                 :           4 :   tree fndecl_wrapped_malloc
     789                 :           4 :     = build_fn_decl ("wrapped_malloc", fntype_void_void);
     790                 :           4 :   tree fndecl_free_boxed_int
     791                 :           4 :     = build_fn_decl ("free_boxed_int", fntype_void_void);
     792                 :           4 :   tree fndecl_wrapped_free
     793                 :           4 :     = build_fn_decl ("wrapped_free", fntype_void_void);
     794                 :             : 
     795                 :           4 :   test_diagnostic_path path (event_pp);
     796                 :           4 :   path.add_entry (fndecl_test, 0);
     797                 :           4 :   path.add_call (fndecl_test, 0, fndecl_make_boxed_int);
     798                 :           4 :   path.add_call (fndecl_make_boxed_int, 1, fndecl_wrapped_malloc);
     799                 :           4 :   path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_malloc, 2, "calling malloc");
     800                 :           4 :   path.add_return (fndecl_test, 0);
     801                 :           4 :   path.add_call (fndecl_test, 0, fndecl_free_boxed_int);
     802                 :           4 :   path.add_call (fndecl_free_boxed_int, 1, fndecl_wrapped_free);
     803                 :           4 :   path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_free, 2, "calling free");
     804                 :           4 :   path.add_return (fndecl_test, 0);
     805                 :           4 :   path.add_call (fndecl_test, 0, fndecl_free_boxed_int);
     806                 :           4 :   path.add_call (fndecl_free_boxed_int, 1, fndecl_wrapped_free);
     807                 :           4 :   path.add_event (UNKNOWN_LOCATION, fndecl_wrapped_free, 2, "calling free");
     808                 :           4 :   ASSERT_EQ (path.num_events (), 18);
     809                 :             : 
     810                 :           4 :   ASSERT_TRUE (path.interprocedural_p ());
     811                 :             : 
     812                 :           4 :   path_summary summary (path, false);
     813                 :           4 :   ASSERT_EQ (summary.get_num_ranges (), 9);
     814                 :             : 
     815                 :           4 :   test_diagnostic_context dc;
     816                 :           4 :   print_path_summary_as_text (&summary, &dc, true);
     817                 :           4 :   ASSERT_STREQ
     818                 :             :     ("  `test': events 1-2 (depth 0)\n"
     819                 :             :      "    |\n"
     820                 :             :      "    | (1): entering `test'\n"
     821                 :             :      "    | (2): calling `make_boxed_int'\n"
     822                 :             :      "    |\n"
     823                 :             :      "    +--> `make_boxed_int': events 3-4 (depth 1)\n"
     824                 :             :      "           |\n"
     825                 :             :      "           | (3): entering `make_boxed_int'\n"
     826                 :             :      "           | (4): calling `wrapped_malloc'\n"
     827                 :             :      "           |\n"
     828                 :             :      "           +--> `wrapped_malloc': events 5-6 (depth 2)\n"
     829                 :             :      "                  |\n"
     830                 :             :      "                  | (5): entering `wrapped_malloc'\n"
     831                 :             :      "                  | (6): calling malloc\n"
     832                 :             :      "                  |\n"
     833                 :             :      "    <-------------+\n"
     834                 :             :      "    |\n"
     835                 :             :      "  `test': events 7-8 (depth 0)\n"
     836                 :             :      "    |\n"
     837                 :             :      "    | (7): returning to `test'\n"
     838                 :             :      "    | (8): calling `free_boxed_int'\n"
     839                 :             :      "    |\n"
     840                 :             :      "    +--> `free_boxed_int': events 9-10 (depth 1)\n"
     841                 :             :      "           |\n"
     842                 :             :      "           | (9): entering `free_boxed_int'\n"
     843                 :             :      "           | (10): calling `wrapped_free'\n"
     844                 :             :      "           |\n"
     845                 :             :      "           +--> `wrapped_free': events 11-12 (depth 2)\n"
     846                 :             :      "                  |\n"
     847                 :             :      "                  | (11): entering `wrapped_free'\n"
     848                 :             :      "                  | (12): calling free\n"
     849                 :             :      "                  |\n"
     850                 :             :      "    <-------------+\n"
     851                 :             :      "    |\n"
     852                 :             :      "  `test': events 13-14 (depth 0)\n"
     853                 :             :      "    |\n"
     854                 :             :      "    | (13): returning to `test'\n"
     855                 :             :      "    | (14): calling `free_boxed_int'\n"
     856                 :             :      "    |\n"
     857                 :             :      "    +--> `free_boxed_int': events 15-16 (depth 1)\n"
     858                 :             :      "           |\n"
     859                 :             :      "           | (15): entering `free_boxed_int'\n"
     860                 :             :      "           | (16): calling `wrapped_free'\n"
     861                 :             :      "           |\n"
     862                 :             :      "           +--> `wrapped_free': events 17-18 (depth 2)\n"
     863                 :             :      "                  |\n"
     864                 :             :      "                  | (17): entering `wrapped_free'\n"
     865                 :             :      "                  | (18): calling free\n"
     866                 :             :      "                  |\n",
     867                 :             :      pp_formatted_text (dc.printer));
     868                 :           4 : }
     869                 :             : 
     870                 :             : /* Example where we pop the stack to an intermediate frame, rather than the
     871                 :             :    initial one.  */
     872                 :             : 
     873                 :             : static void
     874                 :           4 : test_interprocedural_path_2 (pretty_printer *event_pp)
     875                 :             : {
     876                 :             :   /* Build fndecls.  The types aren't quite right, but that
     877                 :             :      doesn't matter for the purposes of this test.  */
     878                 :           4 :   tree fntype_void_void
     879                 :           4 :     = build_function_type_array (void_type_node, 0, NULL);
     880                 :           4 :   tree fndecl_foo = build_fn_decl ("foo", fntype_void_void);
     881                 :           4 :   tree fndecl_bar = build_fn_decl ("bar", fntype_void_void);
     882                 :           4 :   tree fndecl_baz = build_fn_decl ("baz", fntype_void_void);
     883                 :             : 
     884                 :           4 :   test_diagnostic_path path (event_pp);
     885                 :           4 :   path.add_entry (fndecl_foo, 0);
     886                 :           4 :   path.add_call (fndecl_foo, 0, fndecl_bar);
     887                 :           4 :   path.add_call (fndecl_bar, 1, fndecl_baz);
     888                 :           4 :   path.add_return (fndecl_bar, 1);
     889                 :           4 :   path.add_call (fndecl_bar, 1, fndecl_baz);
     890                 :           4 :   ASSERT_EQ (path.num_events (), 8);
     891                 :             : 
     892                 :           4 :   ASSERT_TRUE (path.interprocedural_p ());
     893                 :             : 
     894                 :           4 :   path_summary summary (path, false);
     895                 :           4 :   ASSERT_EQ (summary.get_num_ranges (), 5);
     896                 :             : 
     897                 :           4 :   test_diagnostic_context dc;
     898                 :           4 :   print_path_summary_as_text (&summary, &dc, true);
     899                 :           4 :   ASSERT_STREQ
     900                 :             :     ("  `foo': events 1-2 (depth 0)\n"
     901                 :             :      "    |\n"
     902                 :             :      "    | (1): entering `foo'\n"
     903                 :             :      "    | (2): calling `bar'\n"
     904                 :             :      "    |\n"
     905                 :             :      "    +--> `bar': events 3-4 (depth 1)\n"
     906                 :             :      "           |\n"
     907                 :             :      "           | (3): entering `bar'\n"
     908                 :             :      "           | (4): calling `baz'\n"
     909                 :             :      "           |\n"
     910                 :             :      "           +--> `baz': event 5 (depth 2)\n"
     911                 :             :      "                  |\n"
     912                 :             :      "                  | (5): entering `baz'\n"
     913                 :             :      "                  |\n"
     914                 :             :      "           <------+\n"
     915                 :             :      "           |\n"
     916                 :             :      "         `bar': events 6-7 (depth 1)\n"
     917                 :             :      "           |\n"
     918                 :             :      "           | (6): returning to `bar'\n"
     919                 :             :      "           | (7): calling `baz'\n"
     920                 :             :      "           |\n"
     921                 :             :      "           +--> `baz': event 8 (depth 2)\n"
     922                 :             :      "                  |\n"
     923                 :             :      "                  | (8): entering `baz'\n"
     924                 :             :      "                  |\n",
     925                 :             :      pp_formatted_text (dc.printer));
     926                 :           4 : }
     927                 :             : 
     928                 :             : /* Verify that print_path_summary is sane in the face of a recursive
     929                 :             :    diagnostic_path.  */
     930                 :             : 
     931                 :             : static void
     932                 :           4 : test_recursion (pretty_printer *event_pp)
     933                 :             : {
     934                 :           4 :   tree fntype_void_void
     935                 :           4 :     = build_function_type_array (void_type_node, 0, NULL);
     936                 :           4 :   tree fndecl_factorial = build_fn_decl ("factorial", fntype_void_void);
     937                 :             : 
     938                 :           4 :  test_diagnostic_path path (event_pp);
     939                 :           4 :   path.add_entry (fndecl_factorial, 0);
     940                 :          16 :   for (int depth = 0; depth < 3; depth++)
     941                 :          12 :     path.add_call (fndecl_factorial, depth, fndecl_factorial);
     942                 :           4 :   ASSERT_EQ (path.num_events (), 7);
     943                 :             : 
     944                 :           4 :   ASSERT_TRUE (path.interprocedural_p ());
     945                 :             : 
     946                 :           4 :   path_summary summary (path, false);
     947                 :           4 :   ASSERT_EQ (summary.get_num_ranges (), 4);
     948                 :             : 
     949                 :           4 :   test_diagnostic_context dc;
     950                 :           4 :   print_path_summary_as_text (&summary, &dc, true);
     951                 :           4 :   ASSERT_STREQ
     952                 :             :     ("  `factorial': events 1-2 (depth 0)\n"
     953                 :             :      "    |\n"
     954                 :             :      "    | (1): entering `factorial'\n"
     955                 :             :      "    | (2): calling `factorial'\n"
     956                 :             :      "    |\n"
     957                 :             :      "    +--> `factorial': events 3-4 (depth 1)\n"
     958                 :             :      "           |\n"
     959                 :             :      "           | (3): entering `factorial'\n"
     960                 :             :      "           | (4): calling `factorial'\n"
     961                 :             :      "           |\n"
     962                 :             :      "           +--> `factorial': events 5-6 (depth 2)\n"
     963                 :             :      "                  |\n"
     964                 :             :      "                  | (5): entering `factorial'\n"
     965                 :             :      "                  | (6): calling `factorial'\n"
     966                 :             :      "                  |\n"
     967                 :             :      "                  +--> `factorial': event 7 (depth 3)\n"
     968                 :             :      "                         |\n"
     969                 :             :      "                         | (7): entering `factorial'\n"
     970                 :             :      "                         |\n",
     971                 :             :      pp_formatted_text (dc.printer));
     972                 :           4 : }
     973                 :             : 
     974                 :             : /* Run all of the selftests within this file.  */
     975                 :             : 
     976                 :             : void
     977                 :           4 : tree_diagnostic_path_cc_tests ()
     978                 :             : {
     979                 :           4 :   auto_fix_quotes fix_quotes;
     980                 :           4 :   pretty_printer *event_pp = global_dc->printer->clone ();
     981                 :           4 :   pp_show_color (event_pp) = 0;
     982                 :           4 :   test_empty_path (event_pp);
     983                 :           4 :   test_intraprocedural_path (event_pp);
     984                 :           4 :   test_interprocedural_path_1 (event_pp);
     985                 :           4 :   test_interprocedural_path_2 (event_pp);
     986                 :           4 :   test_recursion (event_pp);
     987                 :           4 :   delete event_pp;
     988                 :           4 : }
     989                 :             : 
     990                 :             : } // namespace selftest
     991                 :             : 
     992                 :             : #if __GNUC__ >= 10
     993                 :             : #  pragma GCC diagnostic pop
     994                 :             : #endif
     995                 :             : 
     996                 :             : #endif /* #if CHECKING_P */
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.