LCOV - code coverage report
Current view: top level - gcc/analyzer - checker-event.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 89.2 % 556 496
Test Date: 2026-05-11 19:44:49 Functions: 94.4 % 72 68
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Subclasses of diagnostics::paths::event for analyzer diagnostics.
       2              :    Copyright (C) 2019-2026 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
       8              : under the terms of the GNU General Public License as published by
       9              : the Free Software Foundation; either version 3, or (at your option)
      10              : any later version.
      11              : 
      12              : GCC is distributed in the hope that it will be useful, but
      13              : WITHOUT ANY WARRANTY; without even the implied warranty of
      14              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15              : General Public License 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 "analyzer/common.h"
      22              : 
      23              : #include "gimple-pretty-print.h"
      24              : #include "sbitmap.h"
      25              : #include "ordered-hash-map.h"
      26              : #include "fold-const.h"
      27              : #include "gimple-iterator.h"
      28              : #include "inlining-iterator.h"
      29              : #include "tree-logical-location.h"
      30              : #include "diagnostics/sarif-sink.h"
      31              : #include "diagnostics/state-graphs.h"
      32              : #include "custom-sarif-properties/state-graphs.h"
      33              : 
      34              : #include "analyzer/analyzer-logging.h"
      35              : #include "analyzer/sm.h"
      36              : #include "analyzer/call-string.h"
      37              : #include "analyzer/program-point.h"
      38              : #include "analyzer/store.h"
      39              : #include "analyzer/region-model.h"
      40              : #include "analyzer/program-state.h"
      41              : #include "analyzer/checker-path.h"
      42              : #include "analyzer/supergraph.h"
      43              : #include "analyzer/pending-diagnostic.h"
      44              : #include "analyzer/diagnostic-manager.h"
      45              : #include "analyzer/constraint-manager.h"
      46              : #include "analyzer/checker-event.h"
      47              : #include "analyzer/exploded-graph.h"
      48              : #include "analyzer/callsite-expr.h"
      49              : #include "analyzer/state-transition.h"
      50              : 
      51              : #if ENABLE_ANALYZER
      52              : 
      53              : namespace ana {
      54              : 
      55              : /* Get a string for EK.  */
      56              : 
      57              : const char *
      58          192 : event_kind_to_string (enum event_kind ek)
      59              : {
      60          192 :   switch (ek)
      61              :     {
      62            0 :     default:
      63            0 :       gcc_unreachable ();
      64              :     case event_kind::debug:
      65              :       return "debug";
      66            4 :     case event_kind::custom:
      67            4 :       return "custom";
      68            8 :     case event_kind::stmt:
      69            8 :       return "stmt";
      70           18 :     case event_kind::region_creation:
      71           18 :       return "region_creation";
      72            0 :     case event_kind::state_transition:
      73            0 :       return "state_transition";
      74           23 :     case event_kind::function_entry:
      75           23 :       return "function_entry";
      76           26 :     case event_kind::state_change:
      77           26 :       return "state_change";
      78           19 :     case event_kind::start_cfg_edge:
      79           19 :       return "start_cfg_edge";
      80           19 :     case event_kind::end_cfg_edge:
      81           19 :       return "end_cfg_edge";
      82            6 :     case event_kind::catch_:
      83            6 :       return "catch";
      84           13 :     case event_kind::call_:
      85           13 :       return "call";
      86            3 :     case event_kind::return_:
      87            3 :       return "return";
      88            0 :     case event_kind::start_consolidated_cfg_edges:
      89            0 :       return "start_consolidated_cfg_edges";
      90            0 :     case event_kind::end_consolidated_cfg_edges:
      91            0 :       return "end_consolidated_cfg_edges";
      92            1 :     case event_kind::inlined_call:
      93            1 :       return "inlined_call";
      94            1 :     case event_kind::setjmp_:
      95            1 :       return "setjmp";
      96            1 :     case event_kind::rewind_from_longjmp:
      97            1 :       return "rewind_from_longjmp";
      98            1 :     case event_kind::rewind_to_setjmp:
      99            1 :       return "rewind_to_setjmp";
     100            6 :     case event_kind::throw_:
     101            6 :       return "throw";
     102            3 :     case event_kind::unwind:
     103            3 :       return "unwind";
     104           40 :     case event_kind::warning:
     105           40 :       return "warning";
     106              :     }
     107              : }
     108              : 
     109              : /* class checker_event : public diagnostics::paths::event.  */
     110              : 
     111              : /* checker_event's ctor.  */
     112              : 
     113        37737 : checker_event::checker_event (enum event_kind kind,
     114        37737 :                               const event_loc_info &loc_info)
     115        37737 : : m_path (nullptr),
     116        37737 :   m_kind (kind), m_loc (loc_info.m_loc),
     117        37737 :   m_original_fndecl (loc_info.m_fndecl),
     118        37737 :   m_effective_fndecl (loc_info.m_fndecl),
     119        37737 :   m_original_depth (loc_info.m_depth),
     120        37737 :   m_effective_depth (loc_info.m_depth),
     121        37737 :   m_pending_diagnostic (nullptr), m_emission_id (),
     122              :   m_logical_loc
     123        37737 :     (tree_logical_location_manager::key_from_tree (loc_info.m_fndecl))
     124              : {
     125              :   /* Update effective fndecl and depth if inlining has been recorded.  */
     126        37737 :   if (flag_analyzer_undo_inlining)
     127              :     {
     128        37725 :       inlining_info info (m_loc);
     129        37725 :       if (info.get_inner_fndecl ())
     130              :         {
     131        30361 :           m_effective_fndecl = info.get_inner_fndecl ();
     132        30361 :           m_effective_depth += info.get_extra_frames ();
     133        30361 :           m_logical_loc
     134        30361 :             = tree_logical_location_manager::key_from_tree (m_effective_fndecl);
     135              :         }
     136              :     }
     137        37737 : }
     138              : 
     139              : /* No-op implementation of diagnostics::paths::event::get_meaning vfunc for
     140              :    checker_event: checker events have no meaning by default.  */
     141              : 
     142              : diagnostics::paths::event::meaning
     143           56 : checker_event::get_meaning () const
     144              : {
     145           56 :   return diagnostics::paths::event::meaning ();
     146              : }
     147              : 
     148              : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
     149              :    for checker_event.  */
     150              : 
     151              : void
     152          155 : checker_event::
     153              : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
     154              :                             diagnostics::sarif_object &thread_flow_loc_obj) const
     155              : {
     156          155 :   auto &props = thread_flow_loc_obj.get_or_create_properties ();
     157              : #define PROPERTY_PREFIX "gcc/analyzer/checker_event/"
     158          310 :   props.set (PROPERTY_PREFIX "emission_id",
     159          155 :              diagnostic_event_id_to_json  (m_emission_id));
     160          155 :   props.set_string (PROPERTY_PREFIX "kind", event_kind_to_string (m_kind));
     161              : 
     162          155 :   if (m_original_fndecl != m_effective_fndecl)
     163            0 :     props.set_logical_location
     164            0 :       (PROPERTY_PREFIX "original_fndecl",
     165              :        builder,
     166            0 :        tree_logical_location_manager::key_from_tree (m_original_fndecl));
     167              : 
     168          155 :   if (m_original_depth != m_effective_depth)
     169            0 :     props.set_integer (PROPERTY_PREFIX "original_depth", m_original_depth);
     170              : #undef PROPERTY_PREFIX
     171          155 : }
     172              : 
     173              : /* Dump this event to PP (for debugging/logging purposes).  */
     174              : 
     175              : void
     176           37 : checker_event::dump (pretty_printer *pp) const
     177              : {
     178           37 :   pp_character (pp, '"');
     179           37 :   print_desc (*pp);
     180           37 :   pp_printf (pp, "\" (depth %i", m_effective_depth);
     181              : 
     182           37 :   if (m_effective_depth != m_original_depth)
     183           10 :     pp_printf (pp, " corrected from %i",
     184              :                m_original_depth);
     185           37 :   if (m_effective_fndecl)
     186              :     {
     187           37 :       pp_printf (pp, ", fndecl %qE", m_effective_fndecl);
     188           37 :       if (m_effective_fndecl != m_original_fndecl)
     189           10 :         pp_printf (pp, " corrected from %qE", m_original_fndecl);
     190              :     }
     191           37 :   pp_printf (pp, ", m_loc=%llx)",
     192           37 :              (unsigned long long) get_location ());
     193           37 : }
     194              : 
     195              : /* Dump this event to stderr (for debugging/logging purposes).  */
     196              : 
     197              : DEBUG_FUNCTION void
     198            0 : checker_event::debug () const
     199              : {
     200            0 :   tree_dump_pretty_printer pp (stderr);
     201            0 :   dump (&pp);
     202            0 :   pp_newline (&pp);
     203            0 : }
     204              : 
     205              : /* Hook for being notified when this event has its final id EMISSION_ID
     206              :    and is about to emitted for PD.
     207              : 
     208              :    Base implementation of checker_event::prepare_for_emission vfunc;
     209              :    subclasses that override this should chain up to it.
     210              : 
     211              :    Record PD and EMISSION_ID, and call the print_desc vfunc, so that any
     212              :    side-effects of the call to print_desc take place before
     213              :    pending_diagnostic::emit is called.
     214              : 
     215              :    For example, state_change_event::print_desc can call
     216              :    pending_diagnostic::describe_state_change; free_of_non_heap can use this
     217              :    to tweak the message (TODO: would be neater to simply capture the
     218              :    pertinent data within the sm-state).  */
     219              : 
     220              : void
     221        17355 : checker_event::prepare_for_emission (checker_path *path,
     222              :                                      pending_diagnostic *pd,
     223              :                                      diagnostics::paths::event_id_t emission_id)
     224              : {
     225        17355 :   m_path = path;
     226        17355 :   m_pending_diagnostic = pd;
     227        17355 :   m_emission_id = emission_id;
     228              : 
     229        17355 :   auto pp = global_dc->clone_printer ();
     230        17355 :   print_desc (*pp.get ());
     231        17355 : }
     232              : 
     233              : std::unique_ptr<diagnostics::digraphs::digraph>
     234           28 : checker_event::maybe_make_diagnostic_state_graph (bool debug) const
     235              : {
     236           28 :   const program_state *state = get_program_state ();
     237           28 :   if (!state)
     238            0 :     return nullptr;
     239              : 
     240           28 :   gcc_assert (m_path);
     241           28 :   const extrinsic_state &ext_state = m_path->get_ext_state ();
     242              : 
     243           28 :   auto result = state->make_diagnostic_state_graph (ext_state);
     244              : 
     245           28 :   if (debug)
     246              :     {
     247           27 :       pretty_printer pp;
     248           27 :       text_art::theme *theme = global_dc->get_diagram_theme ();
     249           27 :       text_art::dump_to_pp (*state, theme, &pp);
     250           27 :       const json::string_property program_state_property
     251              :         (custom_sarif_properties::state_graphs::graph::prefix,
     252           27 :          "analyzer/program_state/");
     253           27 :       result->set_property (program_state_property,
     254              :                             pp_formatted_text (&pp));
     255           27 :     }
     256              : 
     257           28 :   return result;
     258           28 : }
     259              : 
     260              : /* class debug_event : public checker_event.  */
     261              : 
     262              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     263              :    debug_event.
     264              :    Use the saved string as the event's description.  */
     265              : 
     266              : void
     267            0 : debug_event::print_desc (pretty_printer &pp) const
     268              : {
     269            0 :   pp_string (&pp, m_desc);
     270            0 : }
     271              : 
     272              : /* class precanned_custom_event : public custom_event.  */
     273              : 
     274              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     275              :    precanned_custom_event.
     276              :    Use the saved string as the event's description.  */
     277              : 
     278              : void
     279           40 : precanned_custom_event::print_desc (pretty_printer &pp) const
     280              : {
     281           40 :   pp_string (&pp, m_desc);
     282           40 : }
     283              : 
     284              : /* class statement_event : public checker_event.  */
     285              : 
     286              : /* statement_event's ctor.  */
     287              : 
     288        13944 : statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
     289        13944 :                                   const program_state &dst_state)
     290              : : checker_event (event_kind::stmt,
     291        13944 :                  event_loc_info (gimple_location (stmt), fndecl, depth)),
     292        13944 :   m_stmt (stmt),
     293        13944 :   m_dst_state (dst_state)
     294              : {
     295        13944 : }
     296              : 
     297              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     298              :    statement_event.
     299              :    Use the statement's dump form as the event's description.  */
     300              : 
     301              : void
     302           12 : statement_event::print_desc (pretty_printer &pp) const
     303              : {
     304           12 :   pp_string (&pp, "stmt: ");
     305           12 :   pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
     306           12 : }
     307              : 
     308              : /* class state_transition_event : public checker_event.  */
     309              : 
     310              : void
     311          132 : state_transition_event::print_desc (pretty_printer &pp) const
     312              : {
     313          132 :   gcc_assert (m_state_trans);
     314          132 :   switch (m_state_trans->get_kind ())
     315              :     {
     316            0 :     default:
     317            0 :       gcc_unreachable ();
     318           90 :     case state_transition::kind::origin:
     319           90 :       {
     320           90 :         const state_transition_origin &state_trans
     321              :           = *static_cast <const state_transition_origin *> (m_state_trans);
     322           90 :         if (m_pending_diagnostic)
     323              :           {
     324           60 :             evdesc::origin_of_state evd (state_trans.m_dst_reg_expr);
     325           60 :             if (m_pending_diagnostic->describe_origin_of_state (pp, evd))
     326           44 :               return;
     327              :           }
     328           46 :         pp_printf (&pp, "value originates here");
     329              :       }
     330           46 :       break;
     331              : 
     332            0 :     case state_transition::kind::at_call:
     333            0 :     case state_transition::kind::at_return:
     334              :       // These should be handled by call_event and return_event
     335            0 :       gcc_unreachable ();
     336           18 :       break;
     337              : 
     338           18 :     case state_transition::kind::copy:
     339           18 :       {
     340           18 :         const state_transition_copy &state_trans
     341              :           = *static_cast <const state_transition_copy *> (m_state_trans);
     342           18 :         if (m_pending_diagnostic)
     343              :           {
     344           24 :             evdesc::copy_of_state evd (state_trans.m_src_reg_expr,
     345              :                                        state_trans.get_src_event_id (),
     346           12 :                                        state_trans.m_dst_reg_expr);
     347           12 :             if (m_pending_diagnostic->describe_copy_of_state (pp, evd))
     348           12 :               return;
     349              :           }
     350            6 :         auto event_id = state_trans.get_src_event_id ();
     351            6 :         if (event_id.known_p ())
     352            0 :           pp_printf (&pp, "copying value from %@ from %qE to %qE",
     353              :                      &event_id,
     354            0 :                      state_trans.m_src_reg_expr,
     355            0 :                      state_trans.m_dst_reg_expr);
     356              :         else
     357            6 :           pp_printf (&pp, "copying value from %qE to %qE",
     358            6 :                      state_trans.m_src_reg_expr,
     359            6 :                      state_trans.m_dst_reg_expr);
     360              :       }
     361            6 :       break;
     362           24 :     case state_transition::kind::use:
     363           24 :       {
     364           24 :         const state_transition_use &state_trans
     365              :           = *static_cast <const state_transition_use *> (m_state_trans);
     366           24 :         if (m_pending_diagnostic)
     367              :           {
     368           32 :             evdesc::use_of_state evd (state_trans.m_src_reg_expr,
     369           16 :                                       state_trans.get_src_event_id ());
     370           16 :             if (m_pending_diagnostic->describe_use_of_state (pp, evd))
     371           16 :               return;
     372              :           }
     373            8 :         auto event_id = state_trans.get_src_event_id ();
     374            8 :         if (state_trans.get_src_event_id ().known_p ())
     375            0 :           pp_printf (&pp, "using value from %@ from %qE",
     376              :                      &event_id,
     377            0 :                      state_trans.m_src_reg_expr);
     378              :         else
     379            8 :           pp_printf (&pp, "using value from %qE",
     380            8 :                      state_trans.m_src_reg_expr);
     381              :       }
     382            8 :       break;
     383              :     }
     384              : }
     385              : 
     386              : void
     387           44 : state_transition_event::
     388              : prepare_for_emission (checker_path *path,
     389              :                       pending_diagnostic *pd,
     390              :                       diagnostics::paths::event_id_t emission_id)
     391              : {
     392           44 :   checker_event::prepare_for_emission (path, pd, emission_id);
     393           44 :   const_cast<state_transition *> (m_state_trans)->m_event_id = emission_id;
     394           44 : }
     395              : 
     396              : /* class region_creation_event : public checker_event.  */
     397              : 
     398         1579 : region_creation_event::region_creation_event (const event_loc_info &loc_info)
     399         1579 : : checker_event (event_kind::region_creation, loc_info)
     400              : {
     401         1579 : }
     402              : 
     403              : /* The various region_creation_event subclasses' print_desc
     404              :    implementations.  */
     405              : 
     406              : void
     407         1212 : region_creation_event_memory_space::print_desc (pretty_printer &pp) const
     408              : {
     409         1212 :   switch (m_mem_space)
     410              :     {
     411           28 :     default:
     412           28 :       pp_string (&pp, "region created here");
     413           28 :       return;
     414         1086 :     case MEMSPACE_STACK:
     415         1086 :       pp_string (&pp, "region created on stack here");
     416         1086 :       return;
     417           98 :     case MEMSPACE_HEAP:
     418           98 :       pp_string (&pp, "region created on heap here");
     419           98 :       return;
     420              :     }
     421              : }
     422              : 
     423              : void
     424         1630 : region_creation_event_capacity::print_desc (pretty_printer &pp) const
     425              : {
     426         1630 :   gcc_assert (m_capacity);
     427         1630 :   if (TREE_CODE (m_capacity) == INTEGER_CST)
     428              :     {
     429         1434 :       unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
     430         1434 :       return pp_printf_n (&pp,
     431              :                           hwi,
     432              :                           "capacity: %wu byte",
     433              :                           "capacity: %wu bytes",
     434         1434 :                           hwi);
     435              :     }
     436              :   else
     437          196 :     return pp_printf (&pp, "capacity: %qE bytes", m_capacity);
     438              : }
     439              : 
     440              : void
     441          214 : region_creation_event_allocation_size::print_desc (pretty_printer &pp) const
     442              : {
     443          214 :   if (m_capacity)
     444              :     {
     445          206 :       if (TREE_CODE (m_capacity) == INTEGER_CST)
     446          118 :         pp_printf_n (&pp,
     447              :                      tree_to_uhwi (m_capacity),
     448              :                      "allocated %E byte here",
     449              :                      "allocated %E bytes here",
     450              :                      m_capacity);
     451              :       else
     452           88 :         pp_printf (&pp,
     453              :                    "allocated %qE bytes here",
     454              :                    m_capacity);
     455              :     }
     456              :   else
     457            8 :     pp_printf (&pp, "allocated here");
     458          214 : }
     459              : 
     460              : void
     461            0 : region_creation_event_debug::print_desc (pretty_printer &pp) const
     462              : {
     463            0 :   pp_string (&pp, "region creation: ");
     464            0 :   m_reg->dump_to_pp (&pp, true);
     465            0 :   if (m_capacity)
     466            0 :     pp_printf (&pp, " capacity: %qE", m_capacity);
     467            0 : }
     468              : 
     469              : /* class function_entry_event : public checker_event.  */
     470              : 
     471              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     472              :    function_entry_event.
     473              : 
     474              :    Use a string such as "entry to 'foo'" as the event's description.  */
     475              : 
     476              : void
     477         2847 : function_entry_event::print_desc (pretty_printer &pp) const
     478              : {
     479         2847 :   if (m_state_trans)
     480              :     {
     481           42 :       callsite_expr expr = m_state_trans->get_callsite_expr ();
     482           42 :       if (tree parm = expr.get_param_tree (m_effective_fndecl))
     483              :         {
     484           40 :           auto src_event_id = m_state_trans->get_src_event_id ();
     485           40 :           if (src_event_id.known_p ())
     486           16 :             pp_printf (&pp,
     487              :                        "entry to %qE with problematic value from %@ for %qE",
     488           16 :                        m_effective_fndecl,
     489              :                        &src_event_id,
     490              :                        parm);
     491              :           else
     492           24 :             pp_printf (&pp, "entry to %qE with problematic value for %qE",
     493           24 :                        m_effective_fndecl, parm);
     494           40 :           return;
     495              :         }
     496              :     }
     497              : 
     498         2807 :   pp_printf (&pp, "entry to %qE", m_effective_fndecl);
     499              : }
     500              : 
     501              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     502              :    function entry.  */
     503              : 
     504              : diagnostics::paths::event::meaning
     505          220 : function_entry_event::get_meaning () const
     506              : {
     507          220 :   return meaning (verb::enter, noun::function);
     508              : }
     509              : 
     510              : void
     511         1715 : function_entry_event::
     512              : prepare_for_emission (checker_path *path,
     513              :                       pending_diagnostic *pd,
     514              :                       diagnostics::paths::event_id_t emission_id)
     515              : {
     516         1715 :   checker_event::prepare_for_emission (path, pd, emission_id);
     517         1715 :   if (m_state_trans)
     518           23 :     const_cast<state_transition_at_call *> (m_state_trans)->m_event_id = emission_id;
     519         1715 : }
     520              : 
     521              : /* class state_change_event : public checker_event.  */
     522              : 
     523              : /* state_change_event's ctor.  */
     524              : 
     525         3827 : state_change_event::state_change_event (const event_loc_info &loc_info,
     526              :                                         const gimple *stmt,
     527              :                                         const state_machine &sm,
     528              :                                         const svalue *sval,
     529              :                                         state_machine::state_t from,
     530              :                                         state_machine::state_t to,
     531              :                                         const svalue *origin,
     532              :                                         const program_state &dst_state,
     533         3827 :                                         const exploded_node *enode)
     534              : : checker_event (event_kind::state_change, loc_info),
     535         3827 :   m_stmt (stmt),
     536         3827 :   m_sm (sm),
     537         3827 :   m_sval (sval), m_from (from), m_to (to),
     538         3827 :   m_origin (origin),
     539         3827 :   m_dst_state (dst_state),
     540         3827 :   m_enode (enode)
     541              : {
     542         3827 : }
     543              : 
     544              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     545              :    state_change_event.
     546              : 
     547              :    Attempt to generate a nicer human-readable description.
     548              :    For greatest precision-of-wording, give the pending diagnostic
     549              :    a chance to describe this state change (in terms of the
     550              :    diagnostic).
     551              :    Note that we only have a pending_diagnostic set on the event once
     552              :    the diagnostic is about to being emitted, so the description for
     553              :    an event can change.  */
     554              : 
     555              : void
     556         4309 : state_change_event::print_desc (pretty_printer &pp) const
     557              : {
     558         4309 :   if (m_pending_diagnostic)
     559              :     {
     560         4309 :       region_model *model = m_dst_state.m_region_model;
     561         4309 :       tree var = model->get_representative_tree (m_sval);
     562         4309 :       tree origin = model->get_representative_tree (m_origin);
     563         4309 :       evdesc::state_change evd (var, origin,
     564         4309 :                                 m_from, m_to, m_emission_id, *this);
     565         4309 :       if (m_pending_diagnostic->describe_state_change (pp, evd))
     566              :         {
     567         4303 :           if (flag_analyzer_verbose_state_changes)
     568              :             {
     569              :               /* Append debugging information about this event.  */
     570              : 
     571          144 :               if (var)
     572          136 :                 pp_printf (&pp, " (state of %qE: ", var);
     573              :               else
     574            8 :                 pp_string (&pp, " (state: ");
     575              : 
     576          144 :               pp_printf (&pp, "%qs -> %qs, ",
     577          144 :                          m_from->get_name (),
     578          144 :                          m_to->get_name ());
     579              : 
     580          144 :               if (m_origin)
     581            0 :                 pp_printf (&pp, "origin: %qE", origin);
     582              :               else
     583          144 :                 pp_string (&pp, "NULL origin");
     584              : 
     585              :               /* Get any "meaning" of event.  */
     586          144 :               diagnostics::paths::event::meaning meaning = get_meaning ();
     587          144 :               pp_string (&pp, ", meaning: ");
     588          144 :               meaning.dump_to_pp (&pp);
     589          144 :               pp_string (&pp, ")");
     590              :             }
     591         4303 :           return;
     592              :         }
     593              :     }
     594              : 
     595              :   /* Fallback description.  */
     596            6 :   if (m_sval)
     597              :     {
     598            6 :       label_text sval_desc = m_sval->get_desc ();
     599            6 :       pp_printf (&pp,
     600              :                  "state of %qs: %qs -> %qs",
     601              :                  sval_desc.get (),
     602            6 :                  m_from->get_name (),
     603            6 :                  m_to->get_name ());
     604            6 :       if (m_origin)
     605              :         {
     606            0 :           label_text origin_desc = m_origin->get_desc ();
     607            0 :           pp_printf (&pp, " (origin: %qs)",
     608              :                      origin_desc.get ());
     609            0 :         }
     610              :       else
     611            6 :         pp_string (&pp, " (NULL origin)");
     612            6 :     }
     613              :   else
     614              :     {
     615            0 :       gcc_assert (m_origin == nullptr);
     616            0 :       pp_printf (&pp,
     617              :                  "global state: %qs -> %qs",
     618            0 :                  m_from->get_name (),
     619            0 :                  m_to->get_name ());
     620              :     }
     621              : }
     622              : 
     623              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     624              :    state change events: delegate to the pending_diagnostic to
     625              :    get any meaning.  */
     626              : 
     627              : diagnostics::paths::event::meaning
     628          336 : state_change_event::get_meaning () const
     629              : {
     630          336 :   if (m_pending_diagnostic)
     631              :     {
     632          336 :       region_model *model = m_dst_state.m_region_model;
     633          336 :       tree var = model->get_representative_tree (m_sval);
     634          336 :       tree origin = model->get_representative_tree (m_origin);
     635          336 :       evdesc::state_change evd (var, origin,
     636          336 :                                 m_from, m_to, m_emission_id, *this);
     637          336 :       return m_pending_diagnostic->get_meaning_for_state_change (evd);
     638              :     }
     639              :   else
     640            0 :     return meaning ();
     641              : }
     642              : 
     643              : /* class superedge_event : public checker_event.  */
     644              : 
     645              : /* Implementation of diagnostics::paths::event::maybe_add_sarif_properties
     646              :    for superedge_event.  */
     647              : 
     648              : void
     649           49 : superedge_event::
     650              : maybe_add_sarif_properties (diagnostics::sarif_builder &builder,
     651              :                             diagnostics::sarif_object &thread_flow_loc_obj)
     652              :   const
     653              : {
     654           49 :   checker_event::maybe_add_sarif_properties (builder, thread_flow_loc_obj);
     655           49 :   auto &props = thread_flow_loc_obj.get_or_create_properties ();
     656              : #define PROPERTY_PREFIX "gcc/analyzer/superedge_event/"
     657           49 :   if (m_sedge)
     658           49 :     props.set (PROPERTY_PREFIX "superedge", m_sedge->to_json ());
     659              : #undef PROPERTY_PREFIX
     660           49 : }
     661              : 
     662              : /* Determine if this event should be filtered at the given verbosity
     663              :    level.  */
     664              : 
     665              : bool
     666         2690 : superedge_event::should_filter_p (int verbosity) const
     667              : {
     668         2690 :   if (m_sedge->get_any_cfg_edge ())
     669              :     {
     670         2690 :       if (verbosity < 2)
     671              :         return true;
     672              : 
     673         2657 :       if (verbosity < 4)
     674              :         {
     675              :           /* Filter events with empty descriptions.  This ought to filter
     676              :              FALLTHRU, but retain true/false/switch edges.  */
     677         2657 :           auto pp = global_dc->clone_printer ();
     678         2657 :           print_desc (*pp.get ());
     679         2657 :           if (pp_formatted_text (pp.get ()) [0] == '\0')
     680            3 :             return true;
     681         2657 :         }
     682              :     }
     683              :   return false;
     684              : }
     685              : 
     686              : const program_state *
     687           12 : superedge_event::get_program_state () const
     688              : {
     689           12 :   return &m_eedge.m_dest->get_state ();
     690              : }
     691              : 
     692              : const call_and_return_op *
     693         1241 : superedge_event::get_call_and_return_op () const
     694              : {
     695         1241 :   if (m_sedge)
     696         1241 :     if (auto base_op = m_sedge->get_op ())
     697         1241 :       return base_op->dyn_cast_call_and_return_op ();
     698              :   return nullptr;
     699              : }
     700              : 
     701              : /* superedge_event's ctor.  */
     702              : 
     703         7017 : superedge_event::superedge_event (enum event_kind kind,
     704              :                                   const exploded_edge &eedge,
     705         7017 :                                   const event_loc_info &loc_info)
     706              : : checker_event (kind, loc_info),
     707         7017 :   m_eedge (eedge), m_sedge (eedge.m_sedge)
     708              : {
     709         7017 :   gcc_assert (m_sedge);
     710         7017 : }
     711              : 
     712              : /* class cfg_edge_event : public superedge_event.  */
     713              : 
     714              : /* cfg_edge_event's ctor.  */
     715              : 
     716         5776 : cfg_edge_event::cfg_edge_event (enum event_kind kind,
     717              :                                 const exploded_edge &eedge,
     718              :                                 const event_loc_info &loc_info,
     719         5776 :                                 const control_flow_op *op)
     720              : : superedge_event (kind, eedge, loc_info),
     721         5776 :   m_op (op)
     722              : {
     723         5776 : }
     724              : 
     725              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     726              :    CFG edge events.  */
     727              : 
     728              : diagnostics::paths::event::meaning
     729          292 : cfg_edge_event::get_meaning () const
     730              : {
     731          292 :   if (::edge e = get_cfg_edge ())
     732              :     {
     733          292 :       if (e->flags & EDGE_TRUE_VALUE)
     734          124 :         return meaning (verb::branch, property::true_);
     735          168 :       else if (e->flags & EDGE_FALSE_VALUE)
     736          128 :         return meaning (verb::branch, property::false_);
     737              :     }
     738           40 :   return meaning ();
     739              : }
     740              : 
     741              : ::edge
     742          825 : cfg_edge_event::get_cfg_edge () const
     743              : {
     744          825 :   return m_sedge->get_any_cfg_edge ();
     745              : }
     746              : 
     747              : /* If this event is for a conditional, write the sense of the
     748              :    conditional to *OUT and return true.
     749              :    Otherwise return false.  */
     750              : 
     751              : bool
     752          533 : cfg_edge_event::maybe_get_edge_sense (bool *out) const
     753              : {
     754          533 :   if (::edge e = get_cfg_edge ())
     755              :     {
     756          533 :       if (e->flags & EDGE_TRUE_VALUE)
     757              :         {
     758          263 :           *out = true;
     759          263 :           return true;
     760              :         }
     761          270 :       else if (e->flags & EDGE_FALSE_VALUE)
     762              :         {
     763          267 :           *out = false;
     764          267 :           return true;
     765              :         }
     766              :     }
     767              :   return false;
     768              : }
     769              : 
     770              : /* class start_cfg_edge_event : public cfg_edge_event.  */
     771              : 
     772              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     773              :    start_cfg_edge_event.
     774              : 
     775              :    If -fanalyzer-verbose-edges, then generate low-level descriptions, such
     776              :    as
     777              :      "taking 'true' edge SN:7 -> SN:8".
     778              : 
     779              :    Otherwise, generate strings using the label of the underlying CFG if
     780              :    any, such as:
     781              :      "following 'true' branch..." or
     782              :      "following 'case 3' branch..."
     783              :      "following 'default' branch..."
     784              : 
     785              :    For conditionals, attempt to supply a description of the condition that
     786              :    holds, such as:
     787              :      "following 'false' branch (when 'ptr' is non-NULL)..."
     788              : 
     789              :    Failing that, print nothing (which will lead to this event
     790              :    being filtered).  */
     791              : 
     792              : void
     793         7307 : start_cfg_edge_event::print_desc (pretty_printer &pp) const
     794              : {
     795         7307 :   bool user_facing = !flag_analyzer_verbose_edges;
     796         7307 :   label_text edge_desc (m_sedge->get_description (user_facing));
     797         7307 :   if (user_facing)
     798              :     {
     799         7307 :       if (edge_desc.get ()
     800         7307 :           && strlen (edge_desc.get ()) > 0
     801        14611 :           && m_op)
     802              :         {
     803         7304 :           label_text cond_desc
     804         7304 :             = m_op->maybe_describe_condition (pp_show_color (&pp));
     805         7304 :           label_text result;
     806         7304 :           if (cond_desc.get ())
     807         4128 :             pp_printf (&pp,
     808              :                        "following %qs branch (%s)...",
     809              :                        edge_desc.get (), cond_desc.get ());
     810              :           else
     811         3176 :             pp_printf (&pp,
     812              :                        "following %qs branch...",
     813              :                        edge_desc.get ());
     814        11312 :         }
     815              :     }
     816              :   else
     817              :     {
     818            0 :       if (strlen (edge_desc.get ()) > 0)
     819            0 :         return pp_printf (&pp,
     820              :                           "taking %qs edge SN:%i -> SN:%i",
     821              :                           edge_desc.get (),
     822            0 :                           m_sedge->m_src->m_id,
     823            0 :                           m_sedge->m_dest->m_id);
     824              :       else
     825            0 :         return pp_printf (&pp,
     826              :                           "taking edge SN:%i -> SN:%i",
     827            0 :                           m_sedge->m_src->m_id,
     828            0 :                           m_sedge->m_dest->m_id);
     829              :     }
     830         7307 : }
     831              : 
     832              : /* class catch_cfg_edge_event : public cfg_edge_event.  */
     833              : 
     834              : diagnostics::paths::event::meaning
     835            6 : catch_cfg_edge_event::get_meaning () const
     836              : {
     837            6 :   return meaning (verb::catch_);
     838              : }
     839              : 
     840              : /* class call_event : public superedge_event.  */
     841              : 
     842              : /* call_event's ctor.  */
     843              : 
     844         1241 : call_event::call_event (const exploded_edge &eedge,
     845              :                         const event_loc_info &loc_info,
     846         1241 :                         const state_transition_at_call *state_trans)
     847              : : superedge_event (event_kind::call_, eedge, loc_info),
     848         1241 :   m_state_trans (state_trans)
     849              : {
     850         1241 :    m_src_snode = eedge.m_src->get_supernode ();
     851         1241 :    m_dest_snode = eedge.m_dest->get_supernode ();
     852         1241 : }
     853              : 
     854              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     855              :    call_event.
     856              : 
     857              :    If this call event passes critical state for an sm-based warning,
     858              :    allow the diagnostic to generate a precise description, such as:
     859              : 
     860              :      "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
     861              : 
     862              :    Otherwise, generate a description of the form
     863              :    "calling 'foo' from 'bar'".  */
     864              : 
     865              : void
     866         1777 : call_event::print_desc (pretty_printer &pp) const
     867              : {
     868         1777 :   if (m_pending_diagnostic)
     869              :     {
     870         1777 :       if (m_critical_state.m_state)
     871              :         {
     872          394 :           gcc_assert (m_critical_state.m_var);
     873          394 :           tree var = fixup_tree_for_diagnostic (m_critical_state.m_var);
     874          394 :           evdesc::call_with_state evd (m_src_snode->m_fun->decl,
     875          394 :                                        m_dest_snode->m_fun->decl,
     876              :                                        var,
     877          394 :                                        m_critical_state.m_state,
     878          394 :                                        m_state_trans);
     879          394 :           if (m_pending_diagnostic->describe_call_with_state (pp, evd))
     880          180 :             return;
     881              :         }
     882         1383 :       else if (m_state_trans)
     883              :         {
     884           46 :           evdesc::call_with_state evd (m_src_snode->m_fun->decl,
     885           46 :                                        m_dest_snode->m_fun->decl,
     886              :                                        NULL_TREE, nullptr,
     887           46 :                                        m_state_trans);
     888           46 :           if (m_pending_diagnostic->describe_call_with_state (pp, evd))
     889           44 :             return;
     890           42 :           callsite_expr expr = m_state_trans->get_callsite_expr ();
     891           42 :           if (expr.param_p ())
     892              :             {
     893           40 :               auto src_event_id = m_state_trans->get_src_event_id ();
     894           40 :               if (src_event_id.known_p ())
     895           16 :                 pp_printf (&pp,
     896              :                            "passing problematic value from %@ from %qE to %qE"
     897              :                            " via parameter %i",
     898              :                            &src_event_id,
     899              :                            get_caller_fndecl (),
     900              :                            get_callee_fndecl (),
     901              :                            expr.param_num ());
     902              :               else
     903           24 :                 pp_printf (&pp,
     904              :                            "passing problematic value from %qE to %qE"
     905              :                            " via parameter %i",
     906              :                            get_caller_fndecl (),
     907              :                            get_callee_fndecl (),
     908              :                            expr.param_num ());
     909           40 :               return;
     910              :             }
     911              :         }
     912              :     }
     913              : 
     914         1553 :   pp_printf (&pp,
     915              :              "calling %qE from %qE",
     916              :              get_callee_fndecl (),
     917              :              get_caller_fndecl ());
     918              : }
     919              : 
     920              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
     921              :    function call events.  */
     922              : 
     923              : diagnostics::paths::event::meaning
     924          136 : call_event::get_meaning () const
     925              : {
     926          136 :   return meaning (verb::call, noun::function);
     927              : }
     928              : 
     929              : /* Override of checker_event::is_call_p for calls.  */
     930              : 
     931              : bool
     932         2004 : call_event::is_call_p () const
     933              : {
     934         2004 :   return true;
     935              : }
     936              : 
     937              : tree
     938         1661 : call_event::get_caller_fndecl () const
     939              : {
     940         1661 :   return m_src_snode->m_fun->decl;
     941              : }
     942              : 
     943              : tree
     944         1661 : call_event::get_callee_fndecl () const
     945              : {
     946         1661 :   return m_dest_snode->m_fun->decl;
     947              : }
     948              : 
     949              : const program_state *
     950            3 : call_event::get_program_state () const
     951              : {
     952              :   /* Use the state at the source (at the caller),
     953              :      rather than the one at the dest, which has a frame for the callee.  */
     954            3 :   return &m_eedge.m_src->get_state ();
     955              : }
     956              : 
     957              : void
     958          920 : call_event::prepare_for_emission (checker_path *path,
     959              :                                   pending_diagnostic *pd,
     960              :                                   diagnostics::paths::event_id_t emission_id)
     961              : {
     962          920 :   checker_event::prepare_for_emission (path, pd, emission_id);
     963          920 :   if (m_state_trans)
     964           23 :     const_cast<state_transition_at_call *> (m_state_trans)->m_event_id = emission_id;
     965          920 : }
     966              : 
     967              : /* class return_event : public checker_event.  */
     968              : 
     969              : /* return_event's ctor.  */
     970              : 
     971          631 : return_event::return_event (const exploded_edge &eedge,
     972              :                             const event_loc_info &loc_info,
     973          631 :                             const state_transition_at_return *state_trans)
     974              : : checker_event (event_kind::return_, loc_info),
     975          631 :   m_eedge (eedge),
     976          631 :   m_state_trans (state_trans)
     977              : {
     978          631 :   m_src_snode = eedge.m_src->get_supernode ();
     979          631 :   m_dest_snode = eedge.m_dest->get_supernode ();
     980          631 :   m_call_and_return_op
     981          631 :     = eedge.m_src->get_point ().get_call_string ().get_top_of_stack ().m_call_op;
     982          631 : }
     983              : 
     984              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
     985              :    return_event.
     986              : 
     987              :    If this return event returns critical state for an sm-based warning,
     988              :    allow the diagnostic to generate a precise description, such as:
     989              : 
     990              :       "possible of NULL to 'foo' from 'bar'"
     991              : 
     992              :    Otherwise, generate a description of the form
     993              :    "returning to 'foo' from 'bar'.  */
     994              : 
     995              : void
     996          610 : return_event::print_desc (pretty_printer &pp) const
     997              : {
     998              :   /*  For greatest precision-of-wording, if this is returning the
     999              :       state involved in the pending diagnostic, give the pending
    1000              :       diagnostic a chance to describe this return (in terms of
    1001              :       itself).  */
    1002          610 :   if (m_pending_diagnostic)
    1003              :     {
    1004          610 :       if (m_critical_state.m_state)
    1005              :         {
    1006          133 :           evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
    1007          133 :                                        m_src_snode->m_fun->decl,
    1008              :                                        m_critical_state.m_state,
    1009          133 :                                        nullptr);
    1010          133 :           if (m_pending_diagnostic->describe_return_of_state (pp, evd))
    1011           50 :             return;
    1012              :         }
    1013          477 :       else if (m_state_trans)
    1014              :         {
    1015           24 :           evdesc::return_of_state evd (m_dest_snode->m_fun->decl,
    1016           24 :                                        m_src_snode->m_fun->decl,
    1017              :                                        nullptr,
    1018           24 :                                        m_state_trans);
    1019           24 :           if (m_pending_diagnostic->describe_return_of_state (pp, evd))
    1020           24 :             return;
    1021              :         }
    1022              :     }
    1023              : 
    1024          536 :   pp_printf (&pp,
    1025              :              "returning to %qE from %qE",
    1026          536 :              m_dest_snode->m_fun->decl,
    1027          536 :              m_src_snode->m_fun->decl);
    1028              : }
    1029              : 
    1030              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
    1031              :    function return events.  */
    1032              : 
    1033              : diagnostics::paths::event::meaning
    1034           54 : return_event::get_meaning () const
    1035              : {
    1036           54 :   return meaning (verb::return_, noun::function);
    1037              : }
    1038              : 
    1039              : /* Override of checker_event::is_return_p for returns.  */
    1040              : 
    1041              : bool
    1042          631 : return_event::is_return_p () const
    1043              : {
    1044          631 :   return true;
    1045              : }
    1046              : 
    1047              : const program_state *
    1048            3 : return_event::get_program_state () const
    1049              : {
    1050            3 :   return &m_eedge.m_dest->get_state ();
    1051              : }
    1052              : 
    1053              : void
    1054          310 : return_event::prepare_for_emission (checker_path *path,
    1055              :                                     pending_diagnostic *pd,
    1056              :                                     diagnostics::paths::event_id_t emission_id)
    1057              : {
    1058          310 :   checker_event::prepare_for_emission (path, pd, emission_id);
    1059          310 :   if (m_state_trans)
    1060           12 :     const_cast<state_transition_at_return *> (m_state_trans)->m_event_id = emission_id;
    1061          310 : }
    1062              : 
    1063              : /* class start_consolidated_cfg_edges_event : public checker_event.  */
    1064              : 
    1065              : void
    1066          206 : start_consolidated_cfg_edges_event::print_desc (pretty_printer &pp) const
    1067              : {
    1068          206 :   pp_printf (&pp,
    1069              :              "following %qs branch...",
    1070          206 :              m_edge_sense ? "true" : "false");
    1071          206 : }
    1072              : 
    1073              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
    1074              :    start_consolidated_cfg_edges_event.  */
    1075              : 
    1076              : diagnostics::paths::event::meaning
    1077            0 : start_consolidated_cfg_edges_event::get_meaning () const
    1078              : {
    1079            0 :   return meaning (verb::branch,
    1080            0 :                   (m_edge_sense ? property::true_ : property::false_));
    1081              : }
    1082              : 
    1083              : /* class inlined_call_event : public checker_event.  */
    1084              : 
    1085              : void
    1086          326 : inlined_call_event::print_desc (pretty_printer &pp) const
    1087              : {
    1088          326 :   pp_printf (&pp,
    1089              :              "inlined call to %qE from %qE",
    1090          326 :              m_apparent_callee_fndecl,
    1091          326 :              m_apparent_caller_fndecl);
    1092          326 : }
    1093              : 
    1094              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
    1095              :    reconstructed inlined function calls.  */
    1096              : 
    1097              : diagnostics::paths::event::meaning
    1098           72 : inlined_call_event::get_meaning () const
    1099              : {
    1100           72 :   return meaning (verb::call, noun::function);
    1101              : }
    1102              : 
    1103              : /* class setjmp_event : public checker_event.  */
    1104              : 
    1105              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
    1106              :    setjmp_event.  */
    1107              : 
    1108              : void
    1109           41 : setjmp_event::print_desc (pretty_printer &pp) const
    1110              : {
    1111           41 :   pp_printf (&pp,
    1112              :              "%qs called here",
    1113              :              get_user_facing_name (m_setjmp_call));
    1114           41 : }
    1115              : 
    1116              : diagnostics::paths::event::meaning
    1117           17 : setjmp_event::get_meaning () const
    1118              : {
    1119           17 :   return meaning (verb::setjmp_);
    1120              : }
    1121              : 
    1122              : /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
    1123              : 
    1124              :    Record this setjmp's event ID into the path, so that rewind events can
    1125              :    use it.  */
    1126              : 
    1127              : void
    1128           20 : setjmp_event::prepare_for_emission (checker_path *path,
    1129              :                                     pending_diagnostic *pd,
    1130              :                                     diagnostics::paths::event_id_t emission_id)
    1131              : {
    1132           20 :   checker_event::prepare_for_emission (path, pd, emission_id);
    1133           20 :   path->record_setjmp_event (m_enode, emission_id);
    1134           20 : }
    1135              : 
    1136              : /* class rewind_event : public checker_event.  */
    1137              : 
    1138              : /* Get the fndecl containing the site of the longjmp call.  */
    1139              : 
    1140              : tree
    1141           93 : rewind_event::get_longjmp_caller () const
    1142              : {
    1143           93 :   return m_eedge->m_src->get_function ()->decl;
    1144              : }
    1145              : 
    1146              : /* Get the fndecl containing the site of the setjmp call.  */
    1147              : 
    1148              : tree
    1149           85 : rewind_event::get_setjmp_caller () const
    1150              : {
    1151           85 :   return m_eedge->m_dest->get_function ()->decl;
    1152              : }
    1153              : 
    1154              : diagnostics::paths::event::meaning
    1155           26 : rewind_event::get_meaning () const
    1156              : {
    1157           26 :   return meaning (verb::longjmp_);
    1158              : }
    1159              : 
    1160              : /* rewind_event's ctor.  */
    1161              : 
    1162           30 : rewind_event::rewind_event (const exploded_edge *eedge,
    1163              :                             enum event_kind kind,
    1164              :                             const event_loc_info &loc_info,
    1165           30 :                             const rewind_info_t *rewind_info)
    1166              : : checker_event (kind, loc_info),
    1167           30 :   m_rewind_info (rewind_info),
    1168           30 :   m_eedge (eedge)
    1169              : {
    1170           30 :   gcc_assert (m_eedge->m_custom_info.get () == m_rewind_info);
    1171           30 : }
    1172              : 
    1173              : /* class rewind_from_longjmp_event : public rewind_event.  */
    1174              : 
    1175              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
    1176              :    rewind_from_longjmp_event.  */
    1177              : 
    1178              : void
    1179           31 : rewind_from_longjmp_event::print_desc (pretty_printer &pp) const
    1180              : {
    1181           31 :   const char *src_name
    1182           31 :     = get_user_facing_name (m_rewind_info->get_longjmp_call ());
    1183              : 
    1184           31 :   if (get_longjmp_caller () == get_setjmp_caller ())
    1185              :     /* Special-case: purely intraprocedural rewind.  */
    1186            8 :     pp_printf (&pp,
    1187              :                "rewinding within %qE from %qs...",
    1188              :                get_longjmp_caller (),
    1189              :                src_name);
    1190              :   else
    1191           23 :     pp_printf (&pp,
    1192              :                "rewinding from %qs in %qE...",
    1193              :                src_name,
    1194              :                get_longjmp_caller ());
    1195           31 : }
    1196              : 
    1197              : /* class rewind_to_setjmp_event : public rewind_event.  */
    1198              : 
    1199              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
    1200              :    rewind_to_setjmp_event.  */
    1201              : 
    1202              : void
    1203           31 : rewind_to_setjmp_event::print_desc (pretty_printer &pp) const
    1204              : {
    1205           31 :   const char *dst_name
    1206           31 :     = get_user_facing_name (m_rewind_info->get_setjmp_call ());
    1207              : 
    1208              :   /* If we can, identify the ID of the setjmp_event.  */
    1209           31 :   if (m_original_setjmp_event_id.known_p ())
    1210              :     {
    1211           16 :       if (get_longjmp_caller () == get_setjmp_caller ())
    1212              :         /* Special-case: purely intraprocedural rewind.  */
    1213            4 :         pp_printf (&pp,
    1214              :                    "...to %qs (saved at %@)",
    1215              :                    dst_name,
    1216              :                    &m_original_setjmp_event_id);
    1217              :       else
    1218           12 :         pp_printf (&pp,
    1219              :                    "...to %qs in %qE (saved at %@)",
    1220              :                    dst_name,
    1221              :                    get_setjmp_caller (),
    1222              :                    &m_original_setjmp_event_id);
    1223              :     }
    1224              :   else
    1225              :     {
    1226           15 :       if (get_longjmp_caller () == get_setjmp_caller ())
    1227              :         /* Special-case: purely intraprocedural rewind.  */
    1228            4 :         pp_printf (&pp,
    1229              :                    "...to %qs",
    1230              :                    dst_name);
    1231              :       else
    1232           11 :         pp_printf (&pp,
    1233              :                    "...to %qs in %qE",
    1234              :                    dst_name,
    1235              :                    get_setjmp_caller ());
    1236              :     }
    1237           31 : }
    1238              : 
    1239              : /* Implementation of checker_event::prepare_for_emission vfunc for
    1240              :    rewind_to_setjmp_event.
    1241              : 
    1242              :    Attempt to look up the setjmp event ID that recorded the jmp_buf
    1243              :    for this rewind.  */
    1244              : 
    1245              : void
    1246           15 : rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
    1247              :                                               pending_diagnostic *pd,
    1248              :                                               diagnostics::paths::event_id_t emission_id)
    1249              : {
    1250           15 :   checker_event::prepare_for_emission (path, pd, emission_id);
    1251           15 :   path->get_setjmp_event (m_rewind_info->get_enode_origin (),
    1252              :                           &m_original_setjmp_event_id);
    1253           15 : }
    1254              : 
    1255              : /* class throw_event : public checker_event.  */
    1256              : 
    1257              : diagnostics::paths::event::meaning
    1258            6 : throw_event::get_meaning () const
    1259              : {
    1260            6 :   return meaning (verb::throw_);
    1261              : }
    1262              : 
    1263              : /* class explicit_throw_event : public throw_event.  */
    1264              : void
    1265          150 : explicit_throw_event::print_desc (pretty_printer &pp) const
    1266              : {
    1267          150 :   if (m_is_rethrow)
    1268              :     {
    1269           30 :       if (m_type)
    1270           18 :         pp_printf (&pp, "rethrowing exception of type %qT here...", m_type);
    1271              :       else
    1272           12 :         pp_printf (&pp, "rethrowing exception here...");
    1273              :     }
    1274              :   else
    1275              :     {
    1276          120 :       if (m_type)
    1277          120 :         pp_printf (&pp, "throwing exception of type %qT here...", m_type);
    1278              :       else
    1279            0 :         pp_printf (&pp, "throwing exception here...");
    1280              :     }
    1281          150 : }
    1282              : 
    1283              : /* class throw_from_call_to_external_fn_event : public throw_event.  */
    1284              : 
    1285              : void
    1286           52 : throw_from_call_to_external_fn_event::print_desc (pretty_printer &pp) const
    1287              : {
    1288           52 :   if (m_fndecl)
    1289           52 :     pp_printf (&pp, "if %qD throws an exception...", m_fndecl);
    1290              :   else
    1291            0 :     pp_printf (&pp, "if the called function throws an exception...");
    1292           52 : }
    1293              : 
    1294              : // class unwind_event : public checker_event
    1295              : 
    1296              : void
    1297           26 : unwind_event::print_desc (pretty_printer &pp) const
    1298              : {
    1299           26 :   if (m_num_frames > 1)
    1300           18 :     pp_printf (&pp, "unwinding %i stack frames", m_num_frames);
    1301              :   else
    1302            8 :     pp_printf (&pp, "unwinding stack frame");
    1303           26 : }
    1304              : 
    1305              : diagnostics::paths::event::meaning
    1306            3 : unwind_event::get_meaning () const
    1307              : {
    1308            3 :   return meaning (verb::unwind_);
    1309              : }
    1310              : 
    1311              : /* class warning_event : public checker_event.  */
    1312              : 
    1313              : /* Implementation of diagnostics::paths::event::print_desc vfunc for
    1314              :    warning_event.
    1315              : 
    1316              :    If the pending diagnostic implements describe_final_event, use it,
    1317              :    generating a precise description e.g.
    1318              :      "second 'free' here; first 'free' was at (7)"
    1319              : 
    1320              :    Otherwise generate a generic description.  */
    1321              : 
    1322              : void
    1323         8292 : warning_event::print_desc (pretty_printer &pp) const
    1324              : {
    1325         8292 :   if (m_pending_diagnostic)
    1326              :     {
    1327         8280 :       tree var = fixup_tree_for_diagnostic (m_var);
    1328         8280 :       evdesc::final_event evd (var, m_state, *this);
    1329         8280 :       if (m_pending_diagnostic->describe_final_event (pp, evd))
    1330              :         {
    1331         7661 :           if (m_sm && flag_analyzer_verbose_state_changes)
    1332              :             {
    1333           72 :               if (var)
    1334           64 :                 pp_printf (&pp, " (%qE is in state %qs)",
    1335           64 :                            var, m_state->get_name ());
    1336              :               else
    1337            8 :                 pp_printf (&pp, " (in global state %qs)",
    1338            8 :                            m_state->get_name ());
    1339              :             }
    1340         7661 :           return;
    1341              :         }
    1342              :     }
    1343              : 
    1344          631 :   if (m_sm)
    1345              :     {
    1346           64 :       if (m_var)
    1347           64 :         pp_printf (&pp, "here (%qE is in state %qs)",
    1348           64 :                    m_var, m_state->get_name ());
    1349              :       else
    1350            0 :         pp_printf (&pp, "here (in global state %qs)",
    1351            0 :                    m_state->get_name ());
    1352           64 :       return;
    1353              :     }
    1354              :   else
    1355          567 :     pp_string (&pp, "here");
    1356              : }
    1357              : 
    1358              : /* Implementation of diagnostics::paths::event::get_meaning vfunc for
    1359              :    warning_event.  */
    1360              : 
    1361              : diagnostics::paths::event::meaning
    1362          232 : warning_event::get_meaning () const
    1363              : {
    1364          232 :   return meaning (verb::danger, noun::unknown);
    1365              : }
    1366              : 
    1367              : const program_state *
    1368            3 : warning_event::get_program_state () const
    1369              : {
    1370            3 :   if (m_program_state)
    1371              :     return m_program_state.get ();
    1372              :   else
    1373            1 :     return &m_enode->get_state ();
    1374              : }
    1375              : 
    1376              : } // namespace ana
    1377              : 
    1378              : #endif /* #if ENABLE_ANALYZER */
        

Generated by: LCOV version 2.4-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.