LCOV - code coverage report
Current view: top level - gcc/analyzer - diagnostic-manager.cc (source / functions) Hit Total Coverage
Test: gcc.info Lines: 494 564 87.6 %
Date: 2020-03-28 11:57:23 Functions: 26 27 96.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /* Classes for saving, deduplicating, and emitting analyzer diagnostics.
       2                 :            :    Copyright (C) 2019-2020 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 "config.h"
      22                 :            : #include "system.h"
      23                 :            : #include "coretypes.h"
      24                 :            : #include "tree.h"
      25                 :            : #include "pretty-print.h"
      26                 :            : #include "gcc-rich-location.h"
      27                 :            : #include "gimple-pretty-print.h"
      28                 :            : #include "function.h"
      29                 :            : #include "diagnostic-core.h"
      30                 :            : #include "diagnostic-event-id.h"
      31                 :            : #include "diagnostic-path.h"
      32                 :            : #include "alloc-pool.h"
      33                 :            : #include "fibonacci_heap.h"
      34                 :            : #include "shortest-paths.h"
      35                 :            : #include "sbitmap.h"
      36                 :            : #include "tristate.h"
      37                 :            : #include "selftest.h"
      38                 :            : #include "ordered-hash-map.h"
      39                 :            : #include "analyzer/analyzer.h"
      40                 :            : #include "analyzer/analyzer-logging.h"
      41                 :            : #include "analyzer/sm.h"
      42                 :            : #include "analyzer/pending-diagnostic.h"
      43                 :            : #include "analyzer/diagnostic-manager.h"
      44                 :            : #include "analyzer/region-model.h"
      45                 :            : #include "analyzer/constraint-manager.h"
      46                 :            : #include "cfg.h"
      47                 :            : #include "basic-block.h"
      48                 :            : #include "gimple.h"
      49                 :            : #include "gimple-iterator.h"
      50                 :            : #include "cgraph.h"
      51                 :            : #include "digraph.h"
      52                 :            : #include "analyzer/supergraph.h"
      53                 :            : #include "analyzer/call-string.h"
      54                 :            : #include "analyzer/program-point.h"
      55                 :            : #include "analyzer/program-state.h"
      56                 :            : #include "analyzer/exploded-graph.h"
      57                 :            : #include "analyzer/checker-path.h"
      58                 :            : #include "analyzer/reachability.h"
      59                 :            : 
      60                 :            : #if ENABLE_ANALYZER
      61                 :            : 
      62                 :            : namespace ana {
      63                 :            : 
      64                 :            : /* class saved_diagnostic.  */
      65                 :            : 
      66                 :            : /* saved_diagnostic's ctor.
      67                 :            :    Take ownership of D and STMT_FINDER.  */
      68                 :            : 
      69                 :        463 : saved_diagnostic::saved_diagnostic (const state_machine *sm,
      70                 :            :                                     const exploded_node *enode,
      71                 :            :                                     const supernode *snode, const gimple *stmt,
      72                 :            :                                     stmt_finder *stmt_finder,
      73                 :            :                                     tree var, state_machine::state_t state,
      74                 :        463 :                                     pending_diagnostic *d)
      75                 :            : : m_sm (sm), m_enode (enode), m_snode (snode), m_stmt (stmt),
      76                 :            :  /* stmt_finder could be on-stack; we want our own copy that can
      77                 :            :     outlive that.  */
      78                 :        147 :   m_stmt_finder (stmt_finder ? stmt_finder->clone () : NULL),
      79                 :            :   m_var (var), m_state (state),
      80                 :            :   m_d (d), m_trailing_eedge (NULL),
      81                 :        463 :   m_status (STATUS_NEW), m_epath_length (0), m_problem (NULL)
      82                 :            : {
      83                 :        463 :   gcc_assert (m_stmt || m_stmt_finder);
      84                 :            : 
      85                 :            :   /* We must have an enode in order to be able to look for paths
      86                 :            :      through the exploded_graph to this diagnostic.  */
      87                 :        463 :   gcc_assert (m_enode);
      88                 :        463 : }
      89                 :            : 
      90                 :            : /* saved_diagnostic's dtor.  */
      91                 :            : 
      92                 :        926 : saved_diagnostic::~saved_diagnostic ()
      93                 :            : {
      94                 :        463 :   delete m_stmt_finder;
      95                 :        463 :   delete m_d;
      96                 :        592 :   delete m_problem;
      97                 :        463 : }
      98                 :            : 
      99                 :            : bool
     100                 :       1642 : saved_diagnostic::operator== (const saved_diagnostic &other) const
     101                 :            : {
     102                 :       1642 :   return (m_sm == other.m_sm
     103                 :            :           /* We don't compare m_enode.  */
     104                 :       1564 :           && m_snode == other.m_snode
     105                 :        455 :           && m_stmt == other.m_stmt
     106                 :            :           /* We don't compare m_stmt_finder.  */
     107                 :        454 :           && pending_diagnostic::same_tree_p (m_var, other.m_var)
     108                 :        355 :           && m_state == other.m_state
     109                 :        352 :           && m_d->equal_p (*other.m_d)
     110                 :       1976 :           && m_trailing_eedge == other.m_trailing_eedge);
     111                 :            : }
     112                 :            : 
     113                 :            : /* State for building a checker_path from a particular exploded_path.
     114                 :            :    In particular, this precomputes reachability information: the set of
     115                 :            :    source enodes for which a path be found to the diagnostic enode.  */
     116                 :            : 
     117                 :        307 : class path_builder
     118                 :            : {
     119                 :            : public:
     120                 :        307 :   path_builder (const exploded_graph &eg,
     121                 :            :                 const exploded_path &epath)
     122                 :        307 :   : m_eg (eg),
     123                 :        307 :     m_diag_enode (epath.get_final_enode ()),
     124                 :        307 :     m_reachability (eg, m_diag_enode)
     125                 :            :   {}
     126                 :            : 
     127                 :          0 :   const exploded_node *get_diag_node () const { return m_diag_enode; }
     128                 :            : 
     129                 :        160 :   bool reachable_from_p (const exploded_node *src_enode) const
     130                 :            :   {
     131                 :        320 :     return m_reachability.reachable_from_p (src_enode);
     132                 :            :   }
     133                 :            : 
     134                 :       4203 :   const extrinsic_state &get_ext_state () const { return m_eg.get_ext_state (); }
     135                 :            : 
     136                 :            : private:
     137                 :            :   typedef reachability<eg_traits> enode_reachability;
     138                 :            : 
     139                 :            :   const exploded_graph &m_eg;
     140                 :            : 
     141                 :            :   /* The enode where the diagnostic occurs.  */
     142                 :            :   const exploded_node *m_diag_enode;
     143                 :            : 
     144                 :            :   /* Precompute all enodes from which the diagnostic is reachable.  */
     145                 :            :   enode_reachability m_reachability;
     146                 :            : };
     147                 :            : 
     148                 :            : /* class diagnostic_manager.  */
     149                 :            : 
     150                 :            : /* diagnostic_manager's ctor.  */
     151                 :            : 
     152                 :        377 : diagnostic_manager::diagnostic_manager (logger *logger, int verbosity)
     153                 :        377 : : log_user (logger), m_verbosity (verbosity)
     154                 :            : {
     155                 :        377 : }
     156                 :            : 
     157                 :            : /* Queue pending_diagnostic D at ENODE for later emission.  */
     158                 :            : 
     159                 :            : void
     160                 :        463 : diagnostic_manager::add_diagnostic (const state_machine *sm,
     161                 :            :                                     const exploded_node *enode,
     162                 :            :                                     const supernode *snode, const gimple *stmt,
     163                 :            :                                     stmt_finder *finder,
     164                 :            :                                     tree var, state_machine::state_t state,
     165                 :            :                                     pending_diagnostic *d)
     166                 :            : {
     167                 :        926 :   LOG_FUNC (get_logger ());
     168                 :            : 
     169                 :            :   /* We must have an enode in order to be able to look for paths
     170                 :            :      through the exploded_graph to the diagnostic.  */
     171                 :        463 :   gcc_assert (enode);
     172                 :            : 
     173                 :        463 :   saved_diagnostic *sd
     174                 :        463 :     = new saved_diagnostic (sm, enode, snode, stmt, finder, var, state, d);
     175                 :        463 :   m_saved_diagnostics.safe_push (sd);
     176                 :        463 :   if (get_logger ())
     177                 :          0 :     log ("adding saved diagnostic %i at SN %i: %qs",
     178                 :          0 :          m_saved_diagnostics.length () - 1,
     179                 :          0 :          snode->m_index, d->get_kind ());
     180                 :        463 : }
     181                 :            : 
     182                 :            : /* Queue pending_diagnostic D at ENODE for later emission.  */
     183                 :            : 
     184                 :            : void
     185                 :         15 : diagnostic_manager::add_diagnostic (const exploded_node *enode,
     186                 :            :                                     const supernode *snode, const gimple *stmt,
     187                 :            :                                     stmt_finder *finder,
     188                 :            :                                     pending_diagnostic *d)
     189                 :            : {
     190                 :         15 :   gcc_assert (enode);
     191                 :         15 :   add_diagnostic (NULL, enode, snode, stmt, finder, NULL_TREE, 0, d);
     192                 :         15 : }
     193                 :            : 
     194                 :            : /* A class for identifying sets of duplicated pending_diagnostic.
     195                 :            : 
     196                 :            :    We want to find the simplest dedupe_candidate amongst those that share a
     197                 :            :    dedupe_key.  */
     198                 :            : 
     199                 :            : class dedupe_key
     200                 :            : {
     201                 :            : public:
     202                 :        334 :   dedupe_key (const saved_diagnostic &sd,
     203                 :            :               const exploded_path &epath)
     204                 :        334 :   : m_sd (sd), m_stmt (sd.m_stmt)
     205                 :            :   {
     206                 :            :     /* Support deferring the choice of stmt until after an emission path has
     207                 :            :      been built, using an optional stmt_finder.  */
     208                 :        334 :     if (m_stmt == NULL)
     209                 :            :       {
     210                 :         88 :         gcc_assert (sd.m_stmt_finder);
     211                 :         88 :         m_stmt = sd.m_stmt_finder->find_stmt (epath);
     212                 :            :       }
     213                 :        334 :     gcc_assert (m_stmt);
     214                 :        334 :   }
     215                 :            : 
     216                 :       2082 :   hashval_t hash () const
     217                 :            :   {
     218                 :       2082 :     inchash::hash hstate;
     219                 :       2082 :     hstate.add_ptr (m_stmt);
     220                 :            :     // TODO: m_sd
     221                 :       2082 :     return hstate.end ();
     222                 :            :   }
     223                 :            :   bool operator== (const dedupe_key &other) const
     224                 :            :   {
     225                 :            :     return (m_sd == other.m_sd
     226                 :            :             && m_stmt == other.m_stmt);
     227                 :            :   }
     228                 :            : 
     229                 :       2289 :   location_t get_location () const
     230                 :            :   {
     231                 :       2289 :     return m_stmt->location;
     232                 :            :   }
     233                 :            : 
     234                 :            :   /* A qsort comparator for use by dedupe_winners::emit_best
     235                 :            :      to sort them into location_t order.  */
     236                 :            : 
     237                 :            :   static int
     238                 :       2289 :   comparator (const void *p1, const void *p2)
     239                 :            :   {
     240                 :       2289 :     const dedupe_key *pk1 = *(const dedupe_key * const *)p1;
     241                 :       2289 :     const dedupe_key *pk2 = *(const dedupe_key * const *)p2;
     242                 :            : 
     243                 :       2289 :     location_t loc1 = pk1->get_location ();
     244                 :       2289 :     location_t loc2 = pk2->get_location ();
     245                 :            : 
     246                 :       2289 :     return linemap_compare_locations (line_table, loc2, loc1);
     247                 :            :   }
     248                 :            : 
     249                 :            :   const saved_diagnostic &m_sd;
     250                 :            :   const gimple *m_stmt;
     251                 :            : };
     252                 :            : 
     253                 :            : /* The value of a slot for a dedupe_key within dedupe_winners:
     254                 :            :    the exploded_path for the best candidate for that key, and the
     255                 :            :    number of duplicates seen so far.  */
     256                 :            : 
     257                 :        448 : class dedupe_candidate
     258                 :            : {
     259                 :            : public:
     260                 :            :   // has the exploded_path
     261                 :        463 :   dedupe_candidate (const shortest_exploded_paths &sp,
     262                 :            :                     saved_diagnostic *sd)
     263                 :        463 :   : m_epath (sp.get_shortest_path (sd->m_enode)),
     264                 :        926 :     m_num_dupes (0)
     265                 :            :   {
     266                 :            :   }
     267                 :            : 
     268                 :       1007 :   unsigned length () const { return m_epath.length (); }
     269                 :       1104 :   const exploded_path &get_path () const { return m_epath; }
     270                 :            : 
     271                 :         27 :   void add_duplicate () { m_num_dupes++; }
     272                 :        322 :   int get_num_dupes () const { return m_num_dupes; }
     273                 :            : 
     274                 :            : private:
     275                 :            :   exploded_path m_epath;
     276                 :            : public:
     277                 :            :   int m_num_dupes;
     278                 :            : };
     279                 :            : 
     280                 :            : /* Traits for use by dedupe_winners.  */
     281                 :            : 
     282                 :            : class dedupe_hash_map_traits
     283                 :            : {
     284                 :            : public:
     285                 :            :   typedef const dedupe_key *key_type;
     286                 :            :   typedef dedupe_candidate *value_type;
     287                 :            :   typedef dedupe_candidate *compare_type;
     288                 :            : 
     289                 :       2082 :   static inline hashval_t hash (const key_type &v)
     290                 :            :   {
     291                 :       2082 :     return v->hash ();
     292                 :            :   }
     293                 :            :   static inline bool equal_keys (const key_type &k1, const key_type &k2)
     294                 :            :   {
     295                 :            :     return *k1 == *k2;
     296                 :            :   }
     297                 :            :   template <typename T>
     298                 :            :   static inline void remove (T &)
     299                 :            :   {
     300                 :            :     // TODO
     301                 :            :   }
     302                 :            :   template <typename T>
     303                 :            :   static inline void mark_deleted (T &entry)
     304                 :            :   {
     305                 :            :     entry.m_key = reinterpret_cast<key_type> (1);
     306                 :            :   }
     307                 :            :   template <typename T>
     308                 :          0 :   static inline void mark_empty (T &entry)
     309                 :            :   {
     310                 :          0 :     entry.m_key = NULL;
     311                 :            :   }
     312                 :            :   template <typename T>
     313                 :       2444 :   static inline bool is_deleted (const T &entry)
     314                 :            :   {
     315                 :            :     return entry.m_key == reinterpret_cast<key_type> (1);
     316                 :            :   }
     317                 :            :   template <typename T>
     318                 :      12235 :   static inline bool is_empty (const T &entry)
     319                 :            :   {
     320                 :            :     return entry.m_key == NULL;
     321                 :            :   }
     322                 :            :   static const bool empty_zero_p = true;
     323                 :            : };
     324                 :            : 
     325                 :            : /* A class for deduplicating diagnostics and finding (and emitting) the
     326                 :            :    best diagnostic within each partition.  */
     327                 :            : 
     328                 :        142 : class dedupe_winners
     329                 :            : {
     330                 :            : public:
     331                 :        142 :   ~dedupe_winners ()
     332                 :        284 :   {
     333                 :            :     /* Delete all keys and candidates.  */
     334                 :        898 :     for (map_t::iterator iter = m_map.begin ();
     335                 :        142 :          iter != m_map.end ();
     336                 :        449 :          ++iter)
     337                 :            :       {
     338                 :        307 :         delete (*iter).first;
     339                 :        614 :         delete (*iter).second;
     340                 :            :       }
     341                 :        142 :   }
     342                 :            : 
     343                 :            :   /* Determine an exploded_path for SD using SP and, if it's feasible,
     344                 :            :      determine if it's the best seen so far for its dedupe_key.
     345                 :            :      Retain the winner for each dedupe_key, and discard the rest.  */
     346                 :            : 
     347                 :        463 :   void add (logger *logger,
     348                 :            :             const shortest_exploded_paths &sp,
     349                 :            :             saved_diagnostic *sd)
     350                 :            :   {
     351                 :            :     /* Build a dedupe_candidate for SD.
     352                 :            :        This uses SP to build an exploded_path.  */
     353                 :        463 :     dedupe_candidate *dc = new dedupe_candidate (sp, sd);
     354                 :            : 
     355                 :        926 :     sd->set_epath_length (dc->length ());
     356                 :            : 
     357                 :            :     /* Verify that the epath is feasible.
     358                 :            :        State-merging means that not every path in the epath corresponds
     359                 :            :        to a feasible one w.r.t. states.
     360                 :            :        Here we simply check each duplicate saved_diagnostic's
     361                 :            :        shortest_path, and reject any that aren't feasible.
     362                 :            :        This could introduce false negatives, as there could be longer
     363                 :            :        feasible paths within the egraph.  */
     364                 :        463 :     if (logger)
     365                 :          0 :       logger->log ("considering %qs at EN: %i, SN: %i",
     366                 :          0 :                    sd->m_d->get_kind (), sd->m_enode->m_index,
     367                 :          0 :                    sd->m_snode->m_index);
     368                 :            : 
     369                 :        463 :     feasibility_problem *p = NULL;
     370                 :        463 :     if (!dc->get_path ().feasible_p (logger, &p))
     371                 :            :       {
     372                 :        129 :         if (logger)
     373                 :          0 :           logger->log ("rejecting %qs at EN: %i, SN: %i"
     374                 :            :                        " due to infeasible path",
     375                 :          0 :                        sd->m_d->get_kind (), sd->m_enode->m_index,
     376                 :          0 :                        sd->m_snode->m_index);
     377                 :        129 :         sd->set_infeasible (p);
     378                 :        258 :         delete dc;
     379                 :        129 :         return;
     380                 :            :       }
     381                 :            :     else
     382                 :        334 :       if (logger)
     383                 :          0 :         logger->log ("accepting %qs at EN: %i, SN: %i with feasible path",
     384                 :          0 :                      sd->m_d->get_kind (), sd->m_enode->m_index,
     385                 :          0 :                      sd->m_snode->m_index);
     386                 :            : 
     387                 :        334 :     sd->set_feasible ();
     388                 :            : 
     389                 :        334 :     dedupe_key *key = new dedupe_key (*sd, dc->get_path ());
     390                 :        334 :     if (dedupe_candidate **slot = m_map.get (key))
     391                 :            :       {
     392                 :         27 :         if (logger)
     393                 :          0 :           logger->log ("already have this dedupe_key");
     394                 :            : 
     395                 :         27 :         (*slot)->add_duplicate ();
     396                 :            : 
     397                 :         81 :         if (dc->length () < (*slot)->length ())
     398                 :            :           {
     399                 :            :             /* We've got a shorter path for the key; replace
     400                 :            :                the current candidate.  */
     401                 :         15 :             if (logger)
     402                 :          0 :               logger->log ("length %i is better than existing length %i;"
     403                 :            :                            " taking over this dedupe_key",
     404                 :            :                            dc->length (), (*slot)->length ());
     405                 :         15 :             dc->m_num_dupes = (*slot)->get_num_dupes ();
     406                 :         30 :             delete *slot;
     407                 :         15 :             *slot = dc;
     408                 :            :           }
     409                 :            :         else
     410                 :            :           /* We haven't beaten the current best candidate;
     411                 :            :              drop the new candidate.  */
     412                 :            :           {
     413                 :         12 :             if (logger)
     414                 :          0 :               logger->log ("length %i isn't better than existing length %i;"
     415                 :            :                            " dropping this candidate",
     416                 :            :                            dc->length (), (*slot)->length ());
     417                 :         24 :             delete dc;
     418                 :            :           }
     419                 :         27 :         delete key;
     420                 :            :       }
     421                 :            :     else
     422                 :            :       {
     423                 :            :         /* This is the first candidate for this key.  */
     424                 :        307 :         m_map.put (key, dc);
     425                 :        307 :         if (logger)
     426                 :          0 :           logger->log ("first candidate for this dedupe_key");
     427                 :            :       }
     428                 :            :   }
     429                 :            : 
     430                 :            :  /* Emit the simplest diagnostic within each set.  */
     431                 :            : 
     432                 :        142 :   void emit_best (diagnostic_manager *dm,
     433                 :            :                   const exploded_graph &eg)
     434                 :            :   {
     435                 :        142 :     LOG_SCOPE (dm->get_logger ());
     436                 :            : 
     437                 :            :     /* Get keys into a vec for sorting.  */
     438                 :        284 :     auto_vec<const dedupe_key *> keys (m_map.elements ());
     439                 :        591 :     for (map_t::iterator iter = m_map.begin ();
     440                 :        898 :          iter != m_map.end ();
     441                 :        449 :          ++iter)
     442                 :        307 :       keys.quick_push ((*iter).first);
     443                 :            : 
     444                 :        281 :     dm->log ("# keys after de-duplication: %i", keys.length ());
     445                 :            : 
     446                 :            :     /* Sort into a good emission order.  */
     447                 :        142 :     keys.qsort (dedupe_key::comparator);
     448                 :            : 
     449                 :            :     /* Emit the best candidate for each key.  */
     450                 :            :     int i;
     451                 :            :     const dedupe_key *key;
     452                 :        588 :     FOR_EACH_VEC_ELT (keys, i, key)
     453                 :            :       {
     454                 :        307 :         dedupe_candidate **slot = m_map.get (key);
     455                 :        307 :         gcc_assert (*slot);
     456                 :        307 :         const dedupe_candidate &dc = **slot;
     457                 :            : 
     458                 :        307 :         dm->emit_saved_diagnostic (eg, key->m_sd,
     459                 :        307 :                                    dc.get_path (), key->m_stmt,
     460                 :            :                                    dc.get_num_dupes ());
     461                 :            :       }
     462                 :        142 :   }
     463                 :            : 
     464                 :            : private:
     465                 :            : 
     466                 :            :   /* This maps from each dedupe_key to a current best dedupe_candidate.  */
     467                 :            : 
     468                 :            :   typedef hash_map<const dedupe_key *, dedupe_candidate *,
     469                 :            :                    dedupe_hash_map_traits> map_t;
     470                 :            :   map_t m_map;
     471                 :            : };
     472                 :            : 
     473                 :            : /* Emit all saved diagnostics.  */
     474                 :            : 
     475                 :            : void
     476                 :        377 : diagnostic_manager::emit_saved_diagnostics (const exploded_graph &eg)
     477                 :            : {
     478                 :        377 :   LOG_SCOPE (get_logger ());
     479                 :        519 :   auto_timevar tv (TV_ANALYZER_DIAGNOSTICS);
     480                 :        519 :   log ("# saved diagnostics: %i", m_saved_diagnostics.length ());
     481                 :        377 :   if (get_logger ())
     482                 :            :     {
     483                 :            :       unsigned i;
     484                 :            :       saved_diagnostic *sd;
     485                 :          0 :       FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
     486                 :          0 :         log ("[%i] sd: %qs at EN: %i, SN: %i",
     487                 :          0 :              i, sd->m_d->get_kind (), sd->m_enode->m_index,
     488                 :          0 :              sd->m_snode->m_index);
     489                 :            :     }
     490                 :            : 
     491                 :        377 :   if (m_saved_diagnostics.length () == 0)
     492                 :        235 :     return;
     493                 :            : 
     494                 :            :   /* Compute the shortest_paths once, sharing it between all diagnostics.  */
     495                 :        284 :   shortest_exploded_paths sp (eg, eg.get_origin ());
     496                 :            : 
     497                 :            :   /* Iterate through all saved diagnostics, adding them to a dedupe_winners
     498                 :            :      instance.  This partitions the saved diagnostics by dedupe_key,
     499                 :            :      generating exploded_paths for them, and retaining the best one in each
     500                 :            :      partition.  */
     501                 :        284 :   dedupe_winners best_candidates;
     502                 :            : 
     503                 :        142 :   int i;
     504                 :        142 :   saved_diagnostic *sd;
     505                 :        605 :   FOR_EACH_VEC_ELT (m_saved_diagnostics, i, sd)
     506                 :        463 :     best_candidates.add (get_logger (), sp, sd);
     507                 :            : 
     508                 :            :   /* For each dedupe-key, call emit_saved_diagnostic on the "best"
     509                 :            :      saved_diagnostic.  */
     510                 :        142 :   best_candidates.emit_best (this, eg);
     511                 :            : }
     512                 :            : 
     513                 :            : /* Given a saved_diagnostic SD at STMT with feasible path EPATH through EG,
     514                 :            :    create an checker_path of suitable events and use it to call
     515                 :            :    SD's underlying pending_diagnostic "emit" vfunc to emit a diagnostic.  */
     516                 :            : 
     517                 :            : void
     518                 :        307 : diagnostic_manager::emit_saved_diagnostic (const exploded_graph &eg,
     519                 :            :                                            const saved_diagnostic &sd,
     520                 :            :                                            const exploded_path &epath,
     521                 :            :                                            const gimple *stmt,
     522                 :            :                                            int num_dupes)
     523                 :            : {
     524                 :        307 :   LOG_SCOPE (get_logger ());
     525                 :        307 :   log ("sd: %qs at SN: %i", sd.m_d->get_kind (), sd.m_snode->m_index);
     526                 :        307 :   log ("num dupes: %i", num_dupes);
     527                 :            : 
     528                 :        307 :   pretty_printer *pp = global_dc->printer->clone ();
     529                 :            : 
     530                 :            :   /* Precompute all enodes from which the diagnostic is reachable.  */
     531                 :        614 :   path_builder pb (eg, epath);
     532                 :            : 
     533                 :            :   /* This is the diagnostic_path subclass that will be built for
     534                 :            :      the diagnostic.  */
     535                 :        614 :   checker_path emission_path;
     536                 :            : 
     537                 :            :   /* Populate emission_path with a full description of EPATH.  */
     538                 :        307 :   build_emission_path (pb, epath, &emission_path);
     539                 :            : 
     540                 :            :   /* Now prune it to just cover the most pertinent events.  */
     541                 :        307 :   prune_path (&emission_path, sd.m_sm, sd.m_var, sd.m_state);
     542                 :            : 
     543                 :            :   /* Add a final event to the path, covering the diagnostic itself.
     544                 :            :      We use the final enode from the epath, which might be different from
     545                 :            :      the sd.m_enode, as the dedupe code doesn't care about enodes, just
     546                 :            :      snodes.  */
     547                 :        307 :   emission_path.add_final_event (sd.m_sm, epath.get_final_enode (), stmt,
     548                 :        307 :                                  sd.m_var, sd.m_state);
     549                 :            : 
     550                 :            :   /* The "final" event might not be final; if the saved_diagnostic has a
     551                 :            :      trailing eedge stashed, add any events for it.  This is for use
     552                 :            :      in handling longjmp, to show where a longjmp is rewinding to.  */
     553                 :        307 :   if (sd.m_trailing_eedge)
     554                 :          3 :     add_events_for_eedge (pb, *sd.m_trailing_eedge, &emission_path);
     555                 :            : 
     556                 :        307 :   emission_path.prepare_for_emission (sd.m_d);
     557                 :            : 
     558                 :        614 :   gcc_rich_location rich_loc (stmt->location);
     559                 :        307 :   rich_loc.set_path (&emission_path);
     560                 :            : 
     561                 :        614 :   auto_diagnostic_group d;
     562                 :        307 :   auto_cfun sentinel (sd.m_snode->m_fun);
     563                 :        307 :   if (sd.m_d->emit (&rich_loc))
     564                 :            :     {
     565                 :        302 :       if (flag_analyzer_show_duplicate_count && num_dupes > 0)
     566                 :          1 :         inform_n (stmt->location, num_dupes,
     567                 :            :                   "%i duplicate", "%i duplicates",
     568                 :            :                   num_dupes);
     569                 :            :     }
     570                 :        307 :   delete pp;
     571                 :        307 : }
     572                 :            : 
     573                 :            : /* Given a state change to DST_REP, determine a tree that gives the origin
     574                 :            :    of that state at STMT, using DST_STATE's region model, so that state
     575                 :            :    changes based on assignments can be tracked back to their origins.
     576                 :            : 
     577                 :            :    For example, if we have
     578                 :            : 
     579                 :            :      (S1) _1 = malloc (64);
     580                 :            :      (S2) EXPR = _1;
     581                 :            : 
     582                 :            :    then at stmt S2 we can get the origin of EXPR's state as being _1,
     583                 :            :    and thus track the allocation back to S1.  */
     584                 :            : 
     585                 :            : static tree
     586                 :       1994 : get_any_origin (const gimple *stmt,
     587                 :            :                 tree dst_rep,
     588                 :            :                 const program_state &dst_state)
     589                 :            : {
     590                 :       1994 :   if (!stmt)
     591                 :            :     return NULL_TREE;
     592                 :            : 
     593                 :       1994 :   gcc_assert (dst_rep);
     594                 :            : 
     595                 :       1994 :   if (const gassign *assign = dyn_cast <const gassign *> (stmt))
     596                 :            :     {
     597                 :        629 :       tree lhs = gimple_assign_lhs (assign);
     598                 :            :       /* Use region IDs to compare lhs with DST_REP, bulletproofing against
     599                 :            :          cases where they can't have lvalues by using
     600                 :            :          tentative_region_model_context.  */
     601                 :        629 :       tentative_region_model_context ctxt;
     602                 :        629 :       region_id lhs_rid = dst_state.m_region_model->get_lvalue (lhs, &ctxt);
     603                 :        629 :       region_id dst_rep_rid
     604                 :        629 :         = dst_state.m_region_model->get_lvalue (dst_rep, &ctxt);
     605                 :        629 :       if (lhs_rid == dst_rep_rid && !ctxt.had_errors_p ())
     606                 :            :         {
     607                 :        189 :           tree rhs1 = gimple_assign_rhs1 (assign);
     608                 :        189 :           enum tree_code op = gimple_assign_rhs_code (assign);
     609                 :        189 :           switch (op)
     610                 :            :             {
     611                 :            :             default:
     612                 :            :               //gcc_unreachable ();  // TODO
     613                 :            :               break;
     614                 :         97 :             case COMPONENT_REF:
     615                 :         97 :             case SSA_NAME:
     616                 :         97 :               return rhs1;
     617                 :            :             }
     618                 :            :         }
     619                 :            :     }
     620                 :            :   return NULL_TREE;
     621                 :            : }
     622                 :            : 
     623                 :            : /* Emit a "path" of events to EMISSION_PATH describing the exploded path
     624                 :            :    EPATH within EG.  */
     625                 :            : 
     626                 :            : void
     627                 :        307 : diagnostic_manager::build_emission_path (const path_builder &pb,
     628                 :            :                                          const exploded_path &epath,
     629                 :            :                                          checker_path *emission_path) const
     630                 :            : {
     631                 :        614 :   LOG_SCOPE (get_logger ());
     632                 :       9014 :   for (unsigned i = 0; i < epath.m_edges.length (); i++)
     633                 :            :     {
     634                 :       4200 :       const exploded_edge *eedge = epath.m_edges[i];
     635                 :       4200 :       add_events_for_eedge (pb, *eedge, emission_path);
     636                 :            :     }
     637                 :        307 : }
     638                 :            : 
     639                 :            : /* Subclass of state_change_visitor that creates state_change_event
     640                 :            :    instances.  */
     641                 :            : 
     642                 :       4203 : class state_change_event_creator : public state_change_visitor
     643                 :            : {
     644                 :            : public:
     645                 :       4203 :   state_change_event_creator (const exploded_edge &eedge,
     646                 :            :                               checker_path *emission_path)
     647                 :       4203 :     : m_eedge (eedge),
     648                 :       4203 :       m_emission_path (emission_path)
     649                 :            :   {}
     650                 :            : 
     651                 :          8 :   bool on_global_state_change (const state_machine &sm,
     652                 :            :                                state_machine::state_t src_sm_val,
     653                 :            :                                state_machine::state_t dst_sm_val)
     654                 :            :     FINAL OVERRIDE
     655                 :            :   {
     656                 :          8 :     const exploded_node *src_node = m_eedge.m_src;
     657                 :          8 :     const program_point &src_point = src_node->get_point ();
     658                 :          8 :     const int src_stack_depth = src_point.get_stack_depth ();
     659                 :          8 :     const exploded_node *dst_node = m_eedge.m_dest;
     660                 :          8 :     const gimple *stmt = src_point.get_stmt ();
     661                 :          8 :     const supernode *supernode = src_point.get_supernode ();
     662                 :          8 :     const program_state &dst_state = dst_node->get_state ();
     663                 :            : 
     664                 :          8 :     int stack_depth = src_stack_depth;
     665                 :            : 
     666                 :         16 :     m_emission_path->add_event (new state_change_event (supernode,
     667                 :            :                                                         stmt,
     668                 :            :                                                         stack_depth,
     669                 :            :                                                         sm,
     670                 :            :                                                         NULL_TREE,
     671                 :            :                                                         src_sm_val,
     672                 :            :                                                         dst_sm_val,
     673                 :            :                                                         NULL_TREE,
     674                 :          8 :                                                         dst_state));
     675                 :          8 :     return false;
     676                 :            :   }
     677                 :            : 
     678                 :        952 :   bool on_state_change (const state_machine &sm,
     679                 :            :                         state_machine::state_t src_sm_val,
     680                 :            :                         state_machine::state_t dst_sm_val,
     681                 :            :                         tree dst_rep,
     682                 :            :                         svalue_id dst_origin_sid) FINAL OVERRIDE
     683                 :            :   {
     684                 :        952 :     const exploded_node *src_node = m_eedge.m_src;
     685                 :        952 :     const program_point &src_point = src_node->get_point ();
     686                 :        952 :     const int src_stack_depth = src_point.get_stack_depth ();
     687                 :        952 :     const exploded_node *dst_node = m_eedge.m_dest;
     688                 :        952 :     const gimple *stmt = src_point.get_stmt ();
     689                 :        952 :     const supernode *supernode = src_point.get_supernode ();
     690                 :        952 :     const program_state &dst_state = dst_node->get_state ();
     691                 :            : 
     692                 :        952 :     int stack_depth = src_stack_depth;
     693                 :            : 
     694                 :        952 :     if (m_eedge.m_sedge
     695                 :        133 :         && m_eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE)
     696                 :            :       {
     697                 :         83 :         supernode = src_point.get_supernode ();
     698                 :         83 :         stmt = supernode->get_last_stmt ();
     699                 :            :         stack_depth = src_stack_depth;
     700                 :            :       }
     701                 :            : 
     702                 :            :     /* Bulletproofing for state changes at calls/returns;
     703                 :            :        TODO: is there a better way? */
     704                 :        952 :     if (!stmt)
     705                 :            :       return false;
     706                 :            : 
     707                 :        807 :     tree origin_rep
     708                 :        807 :       = dst_state.get_representative_tree (dst_origin_sid);
     709                 :            : 
     710                 :        807 :     if (origin_rep == NULL_TREE)
     711                 :        792 :       origin_rep = get_any_origin (stmt, dst_rep, dst_state);
     712                 :       1614 :     m_emission_path->add_event (new state_change_event (supernode,
     713                 :            :                                                         stmt,
     714                 :            :                                                         stack_depth,
     715                 :            :                                                         sm,
     716                 :            :                                                         dst_rep,
     717                 :            :                                                         src_sm_val,
     718                 :            :                                                         dst_sm_val,
     719                 :            :                                                         origin_rep,
     720                 :        807 :                                                         dst_state));
     721                 :        807 :     return false;
     722                 :            :   }
     723                 :            : 
     724                 :            :   const exploded_edge &m_eedge;
     725                 :            :   checker_path *m_emission_path;
     726                 :            : };
     727                 :            : 
     728                 :            : /* Compare SRC_STATE and DST_STATE (which use EXT_STATE), and call
     729                 :            :    VISITOR's on_state_change for every sm-state change that occurs
     730                 :            :    to a tree, and on_global_state_change for every global state change
     731                 :            :    that occurs.
     732                 :            : 
     733                 :            :    This determines the state changes that ought to be reported to
     734                 :            :    the user: a combination of the effects of changes to sm_state_map
     735                 :            :    (which maps svalues to sm-states), and of region_model changes
     736                 :            :    (which map trees to svalues).
     737                 :            : 
     738                 :            :    Bail out early and return true if any call to on_global_state_change
     739                 :            :    or on_state_change returns true, otherwise return false.
     740                 :            : 
     741                 :            :    This is split out to make it easier to experiment with changes to
     742                 :            :    exploded_node granularity (so that we can observe what state changes
     743                 :            :    lead to state_change_events being emitted).  */
     744                 :            : 
     745                 :            : bool
     746                 :       4203 : for_each_state_change (const program_state &src_state,
     747                 :            :                        const program_state &dst_state,
     748                 :            :                        const extrinsic_state &ext_state,
     749                 :            :                        state_change_visitor *visitor)
     750                 :            : {
     751                 :      12609 :   gcc_assert (src_state.m_checker_states.length ()
     752                 :            :               == ext_state.get_num_checkers ());
     753                 :       8406 :   gcc_assert (dst_state.m_checker_states.length ()
     754                 :            :               == ext_state.get_num_checkers ());
     755                 :      40374 :   for (unsigned i = 0; i < ext_state.get_num_checkers (); i++)
     756                 :            :     {
     757                 :      15984 :       const state_machine &sm = ext_state.get_sm (i);
     758                 :      15984 :       const sm_state_map &src_smap = *src_state.m_checker_states[i];
     759                 :      15984 :       const sm_state_map &dst_smap = *dst_state.m_checker_states[i];
     760                 :            : 
     761                 :            :       /* Add events for any global state changes.  */
     762                 :      15984 :       if (src_smap.get_global_state () != dst_smap.get_global_state ())
     763                 :          8 :         if (visitor->on_global_state_change (sm,
     764                 :            :                                              src_smap.get_global_state (),
     765                 :          8 :                                              dst_smap.get_global_state ()))
     766                 :            :           return true;
     767                 :            : 
     768                 :            :       /* Add events for per-svalue state changes.  */
     769                 :      35177 :       for (sm_state_map::iterator_t iter = dst_smap.begin ();
     770                 :      15984 :            iter != dst_smap.end ();
     771                 :      19193 :            ++iter)
     772                 :            :         {
     773                 :            :           /* Ideally we'd directly compare the SM state between src state
     774                 :            :              and dst state, but there's no guarantee that the IDs can
     775                 :            :              be meaningfully compared.  */
     776                 :       3209 :           svalue_id dst_sid = (*iter).first;
     777                 :       3209 :           state_machine::state_t dst_sm_val = (*iter).second.m_state;
     778                 :            : 
     779                 :       6418 :           auto_vec<path_var> dst_pvs;
     780                 :       3209 :           dst_state.m_region_model->get_path_vars_for_svalue (dst_sid,
     781                 :            :                                                               &dst_pvs);
     782                 :            : 
     783                 :       3209 :           unsigned j;
     784                 :       3209 :           path_var *dst_pv;
     785                 :      11158 :           FOR_EACH_VEC_ELT (dst_pvs, j, dst_pv)
     786                 :            :             {
     787                 :       4817 :               tree dst_rep = dst_pv->m_tree;
     788                 :       4817 :               gcc_assert (dst_rep);
     789                 :       4817 :               if (dst_pv->m_stack_depth
     790                 :       4817 :                   >= src_state.m_region_model->get_stack_depth ())
     791                 :         85 :                 continue;
     792                 :       4732 :               tentative_region_model_context ctxt;
     793                 :       4732 :               svalue_id src_sid
     794                 :       4732 :                 = src_state.m_region_model->get_rvalue (*dst_pv, &ctxt);
     795                 :       4732 :               if (src_sid.null_p () || ctxt.had_errors_p ())
     796                 :          0 :                 continue;
     797                 :       4732 :               state_machine::state_t src_sm_val = src_smap.get_state (src_sid);
     798                 :       4732 :               if (dst_sm_val != src_sm_val)
     799                 :            :                 {
     800                 :        952 :                   svalue_id dst_origin_sid = (*iter).second.m_origin;
     801                 :        952 :                   if (visitor->on_state_change (sm, src_sm_val, dst_sm_val,
     802                 :        952 :                                                 dst_rep, dst_origin_sid))
     803                 :          0 :                     return true;
     804                 :            :                 }
     805                 :            :             }
     806                 :            :         }
     807                 :            :     }
     808                 :            :   return false;
     809                 :            : }
     810                 :            : 
     811                 :            : /* Subroutine of diagnostic_manager::build_emission_path.
     812                 :            :    Add any events for EEDGE to EMISSION_PATH.  */
     813                 :            : 
     814                 :            : void
     815                 :       4203 : diagnostic_manager::add_events_for_eedge (const path_builder &pb,
     816                 :            :                                           const exploded_edge &eedge,
     817                 :            :                                           checker_path *emission_path) const
     818                 :            : {
     819                 :       4203 :   const exploded_node *src_node = eedge.m_src;
     820                 :       4203 :   const program_point &src_point = src_node->get_point ();
     821                 :       4203 :   const exploded_node *dst_node = eedge.m_dest;
     822                 :       4203 :   const program_point &dst_point = dst_node->get_point ();
     823                 :       4203 :   const int dst_stack_depth = dst_point.get_stack_depth ();
     824                 :       4203 :   if (get_logger ())
     825                 :            :     {
     826                 :          0 :       get_logger ()->start_log_line ();
     827                 :          0 :       pretty_printer *pp = get_logger ()->get_printer ();
     828                 :          0 :       pp_printf (pp, "EN %i -> EN %i: ",
     829                 :          0 :                  eedge.m_src->m_index,
     830                 :          0 :                  eedge.m_dest->m_index);
     831                 :          0 :       src_point.print (pp, format (false));
     832                 :          0 :       pp_string (pp, "-> ");
     833                 :          0 :       dst_point.print (pp, format (false));
     834                 :          0 :       get_logger ()->end_log_line ();
     835                 :            :     }
     836                 :       4203 :   const program_state &src_state = src_node->get_state ();
     837                 :       4203 :   const program_state &dst_state = dst_node->get_state ();
     838                 :            : 
     839                 :            :   /* Add state change events for the states that have changed.
     840                 :            :      We add these before events for superedges, so that if we have a
     841                 :            :      state_change_event due to following an edge, we'll get this sequence
     842                 :            :      of events:
     843                 :            : 
     844                 :            :       | if (!ptr)
     845                 :            :       |    ~
     846                 :            :       |    |
     847                 :            :       |    (1) assuming 'ptr' is non-NULL  (state_change_event)
     848                 :            :       |    (2) following 'false' branch... (start_cfg_edge_event)
     849                 :            :      ...
     850                 :            :       | do_something (ptr);
     851                 :            :       | ~~~~~~~~~~~~~^~~~~
     852                 :            :       |              |
     853                 :            :       |              (3) ...to here        (end_cfg_edge_event).  */
     854                 :       4203 :   state_change_event_creator visitor (eedge, emission_path);
     855                 :       4203 :   for_each_state_change (src_state, dst_state, pb.get_ext_state (),
     856                 :            :                          &visitor);
     857                 :            : 
     858                 :            :   /* Allow non-standard edges to add events, e.g. when rewinding from
     859                 :            :      longjmp to a setjmp.  */
     860                 :       4203 :   if (eedge.m_custom_info)
     861                 :         16 :     eedge.m_custom_info->add_events_to_path (emission_path, eedge);
     862                 :            : 
     863                 :            :   /* Add events for superedges, function entries, and for statements.  */
     864                 :       4203 :   switch (dst_point.get_kind ())
     865                 :            :     {
     866                 :            :     default:
     867                 :            :       break;
     868                 :       1544 :     case PK_BEFORE_SUPERNODE:
     869                 :       1544 :       if (src_point.get_kind () == PK_AFTER_SUPERNODE)
     870                 :            :         {
     871                 :       1219 :           if (eedge.m_sedge)
     872                 :       1219 :             add_events_for_superedge (pb, eedge, emission_path);
     873                 :            :         }
     874                 :            :       /* Add function entry events.  */
     875                 :       1544 :       if (dst_point.get_supernode ()->entry_p ())
     876                 :            :         {
     877                 :        464 :           emission_path->add_event
     878                 :        464 :             (new function_entry_event
     879                 :        464 :              (dst_point.get_supernode ()->get_start_location (),
     880                 :        464 :               dst_point.get_fndecl (),
     881                 :        464 :               dst_stack_depth));
     882                 :            :         }
     883                 :            :       break;
     884                 :       1343 :     case PK_BEFORE_STMT:
     885                 :       1343 :       {
     886                 :       1343 :         const gimple *stmt = dst_point.get_stmt ();
     887                 :       1343 :         const gcall *call = dyn_cast <const gcall *> (stmt);
     888                 :        587 :         if (call && is_setjmp_call_p (call))
     889                 :          9 :           emission_path->add_event
     890                 :          9 :             (new setjmp_event (stmt->location,
     891                 :            :                                dst_node,
     892                 :          9 :                                dst_point.get_fndecl (),
     893                 :            :                                dst_stack_depth,
     894                 :          9 :                                call));
     895                 :            :         else
     896                 :       1334 :           emission_path->add_event
     897                 :       1334 :             (new statement_event (stmt,
     898                 :       1334 :                                   dst_point.get_fndecl (),
     899                 :       1334 :                                   dst_stack_depth, dst_state));
     900                 :            :       }
     901                 :            :       break;
     902                 :            :     }
     903                 :       4203 : }
     904                 :            : 
     905                 :            : /* Return true if EEDGE is a significant edge in the path to the diagnostic
     906                 :            :    for PB.
     907                 :            : 
     908                 :            :    Consider all of the sibling out-eedges from the same source enode
     909                 :            :    as EEDGE.
     910                 :            :    If there's no path from the destinations of those eedges to the
     911                 :            :    diagnostic enode, then we have to take this eedge and thus it's
     912                 :            :    significant.
     913                 :            : 
     914                 :            :    Conversely if there is a path from the destination of any other sibling
     915                 :            :    eedge to the diagnostic enode, then this edge is insignificant.
     916                 :            : 
     917                 :            :    Example 1: redundant if-else:
     918                 :            : 
     919                 :            :      (A) if (...)            A
     920                 :            :      (B)   ...              / \
     921                 :            :          else              B   C
     922                 :            :      (C)   ...              \ /
     923                 :            :      (D) [DIAGNOSTIC]        D
     924                 :            : 
     925                 :            :      D is reachable by either B or C, so neither of these edges
     926                 :            :      are significant.
     927                 :            : 
     928                 :            :    Example 2: pertinent if-else:
     929                 :            : 
     930                 :            :      (A) if (...)                         A
     931                 :            :      (B)   ...                           / \
     932                 :            :          else                           B   C
     933                 :            :      (C)   [NECESSARY CONDITION]        |   |
     934                 :            :      (D) [POSSIBLE DIAGNOSTIC]          D1  D2
     935                 :            : 
     936                 :            :      D becomes D1 and D2 in the exploded graph, where the diagnostic occurs
     937                 :            :      at D2.  D2 is only reachable via C, so the A -> C edge is significant.
     938                 :            : 
     939                 :            :    Example 3: redundant loop:
     940                 :            : 
     941                 :            :      (A) while (...)          +-->A
     942                 :            :      (B)   ...                |  / \
     943                 :            :      (C) ...                  +-B  C
     944                 :            :      (D) [DIAGNOSTIC]              |
     945                 :            :                                    D
     946                 :            : 
     947                 :            :      D is reachable from both B and C, so the A->C edge is not significant.  */
     948                 :            : 
     949                 :            : bool
     950                 :       1182 : diagnostic_manager::significant_edge_p (const path_builder &pb,
     951                 :            :                                         const exploded_edge &eedge) const
     952                 :            : {
     953                 :       1182 :   int i;
     954                 :       1182 :   exploded_edge *sibling;
     955                 :       2473 :   FOR_EACH_VEC_ELT (eedge.m_src->m_succs, i, sibling)
     956                 :            :     {
     957                 :       1318 :       if (sibling == &eedge)
     958                 :       1158 :         continue;
     959                 :        160 :       if (pb.reachable_from_p (sibling->m_dest))
     960                 :            :         {
     961                 :         27 :           if (get_logger ())
     962                 :          0 :             get_logger ()->log ("  edge EN: %i -> EN: %i is insignificant as"
     963                 :            :                                 " EN: %i is also reachable via"
     964                 :            :                                 " EN: %i -> EN: %i",
     965                 :          0 :                                 eedge.m_src->m_index, eedge.m_dest->m_index,
     966                 :          0 :                                 pb.get_diag_node ()->m_index,
     967                 :          0 :                                 sibling->m_src->m_index,
     968                 :            :                                 sibling->m_dest->m_index);
     969                 :         27 :           return false;
     970                 :            :         }
     971                 :            :     }
     972                 :            : 
     973                 :            :   return true;
     974                 :            : }
     975                 :            : 
     976                 :            : /* Subroutine of diagnostic_manager::add_events_for_eedge
     977                 :            :    where EEDGE has an underlying superedge i.e. a CFG edge,
     978                 :            :    or an interprocedural call/return.
     979                 :            :    Add any events for the superedge to EMISSION_PATH.  */
     980                 :            : 
     981                 :            : void
     982                 :       1219 : diagnostic_manager::add_events_for_superedge (const path_builder &pb,
     983                 :            :                                               const exploded_edge &eedge,
     984                 :            :                                               checker_path *emission_path)
     985                 :            :   const
     986                 :            : {
     987                 :       1219 :   gcc_assert (eedge.m_sedge);
     988                 :            : 
     989                 :            :   /* Don't add events for insignificant edges at verbosity levels below 3.  */
     990                 :       1219 :   if (m_verbosity < 3)
     991                 :       1182 :     if (!significant_edge_p (pb, eedge))
     992                 :            :       return;
     993                 :            : 
     994                 :       1192 :   const exploded_node *src_node = eedge.m_src;
     995                 :       1192 :   const program_point &src_point = src_node->get_point ();
     996                 :       1192 :   const exploded_node *dst_node = eedge.m_dest;
     997                 :       1192 :   const program_point &dst_point = dst_node->get_point ();
     998                 :       1192 :   const int src_stack_depth = src_point.get_stack_depth ();
     999                 :       1192 :   const int dst_stack_depth = dst_point.get_stack_depth ();
    1000                 :       1192 :   const gimple *last_stmt = src_point.get_supernode ()->get_last_stmt ();
    1001                 :            : 
    1002                 :       1192 :   switch (eedge.m_sedge->m_kind)
    1003                 :            :     {
    1004                 :        956 :     case SUPEREDGE_CFG_EDGE:
    1005                 :        956 :       {
    1006                 :        956 :         emission_path->add_event
    1007                 :        956 :           (new start_cfg_edge_event (eedge,
    1008                 :            :                                (last_stmt
    1009                 :            :                                 ? last_stmt->location
    1010                 :            :                                 : UNKNOWN_LOCATION),
    1011                 :        956 :                                src_point.get_fndecl (),
    1012                 :       1912 :                                src_stack_depth));
    1013                 :        956 :         emission_path->add_event
    1014                 :        956 :           (new end_cfg_edge_event (eedge,
    1015                 :        956 :                                    dst_point.get_supernode ()->get_start_location (),
    1016                 :        956 :                                    dst_point.get_fndecl (),
    1017                 :        956 :                                    dst_stack_depth));
    1018                 :            :       }
    1019                 :        956 :       break;
    1020                 :            : 
    1021                 :        149 :     case SUPEREDGE_CALL:
    1022                 :        149 :       {
    1023                 :        149 :         emission_path->add_event
    1024                 :        149 :           (new call_event (eedge,
    1025                 :            :                            (last_stmt
    1026                 :            :                             ? last_stmt->location
    1027                 :            :                             : UNKNOWN_LOCATION),
    1028                 :        149 :                            src_point.get_fndecl (),
    1029                 :        149 :                            src_stack_depth));
    1030                 :            :       }
    1031                 :        149 :       break;
    1032                 :            : 
    1033                 :          0 :     case SUPEREDGE_INTRAPROCEDURAL_CALL:
    1034                 :          0 :       {
    1035                 :            :         /* TODO: add a subclass for this, or generate events for the
    1036                 :            :            summary.  */
    1037                 :          0 :         emission_path->add_event
    1038                 :          0 :           (new debug_event ((last_stmt
    1039                 :            :                              ? last_stmt->location
    1040                 :            :                              : UNKNOWN_LOCATION),
    1041                 :          0 :                             src_point.get_fndecl (),
    1042                 :            :                             src_stack_depth,
    1043                 :          0 :                             "call summary"));
    1044                 :            :       }
    1045                 :          0 :       break;
    1046                 :            : 
    1047                 :         87 :     case SUPEREDGE_RETURN:
    1048                 :         87 :       {
    1049                 :         87 :         const return_superedge *return_edge
    1050                 :         87 :           = as_a <const return_superedge *> (eedge.m_sedge);
    1051                 :            : 
    1052                 :         87 :         const gcall *call_stmt = return_edge->get_call_stmt ();
    1053                 :         87 :         emission_path->add_event
    1054                 :         87 :           (new return_event (eedge,
    1055                 :            :                              (call_stmt
    1056                 :            :                               ? call_stmt->location
    1057                 :            :                               : UNKNOWN_LOCATION),
    1058                 :         87 :                              dst_point.get_fndecl (),
    1059                 :         87 :                              dst_stack_depth));
    1060                 :            :       }
    1061                 :         87 :       break;
    1062                 :            :     }
    1063                 :            : }
    1064                 :            : 
    1065                 :            : /* Prune PATH, based on the verbosity level, to the most pertinent
    1066                 :            :    events for a diagnostic that involves VAR ending in state STATE
    1067                 :            :    (for state machine SM).
    1068                 :            : 
    1069                 :            :    PATH is updated in place, and the redundant checker_events are deleted.
    1070                 :            : 
    1071                 :            :    As well as deleting events, call record_critical_state on events in
    1072                 :            :    which state critical to the pending_diagnostic is being handled; see
    1073                 :            :    the comment for diagnostic_manager::prune_for_sm_diagnostic.  */
    1074                 :            : 
    1075                 :            : void
    1076                 :        307 : diagnostic_manager::prune_path (checker_path *path,
    1077                 :            :                                 const state_machine *sm,
    1078                 :            :                                 tree var,
    1079                 :            :                                 state_machine::state_t state) const
    1080                 :            : {
    1081                 :        614 :   LOG_FUNC (get_logger ());
    1082                 :        307 :   path->maybe_log (get_logger (), "path");
    1083                 :        307 :   prune_for_sm_diagnostic (path, sm, var, state);
    1084                 :        307 :   prune_interproc_events (path);
    1085                 :        307 :   finish_pruning (path);
    1086                 :        307 :   path->maybe_log (get_logger (), "pruned");
    1087                 :        307 : }
    1088                 :            : 
    1089                 :            : /* A cheap test to determine if EXPR can be the expression of interest in
    1090                 :            :    an sm-diagnostic, so that we can reject cases where we have a non-lvalue.
    1091                 :            :    We don't have always have a model when calling this, so we can't use
    1092                 :            :    tentative_region_model_context, so there can be false positives.  */
    1093                 :            : 
    1094                 :            : static bool
    1095                 :       4762 : can_be_expr_of_interest_p (tree expr)
    1096                 :            : {
    1097                 :          0 :   if (!expr)
    1098                 :            :     return false;
    1099                 :            : 
    1100                 :            :   /* Reject constants.  */
    1101                 :          0 :   if (CONSTANT_CLASS_P (expr))
    1102                 :          0 :     return false;
    1103                 :            : 
    1104                 :            :   /* Otherwise assume that it can be an lvalue.  */
    1105                 :            :   return true;
    1106                 :            : }
    1107                 :            : 
    1108                 :            : /* First pass of diagnostic_manager::prune_path: apply verbosity level,
    1109                 :            :    pruning unrelated state change events.
    1110                 :            : 
    1111                 :            :    Iterate backwards through PATH, skipping state change events that aren't
    1112                 :            :    VAR but update the pertinent VAR when state-copying occurs.
    1113                 :            : 
    1114                 :            :    As well as deleting events, call record_critical_state on events in
    1115                 :            :    which state critical to the pending_diagnostic is being handled, so
    1116                 :            :    that the event's get_desc vfunc can potentially supply a more precise
    1117                 :            :    description of the event to the user.
    1118                 :            :    e.g. improving
    1119                 :            :      "calling 'foo' from 'bar'"
    1120                 :            :    to
    1121                 :            :      "passing possibly-NULL pointer 'ptr' to 'foo' from 'bar' as param 1"
    1122                 :            :    when the diagnostic relates to later dereferencing 'ptr'.  */
    1123                 :            : 
    1124                 :            : void
    1125                 :        307 : diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
    1126                 :            :                                              const state_machine *sm,
    1127                 :            :                                              tree var,
    1128                 :            :                                              state_machine::state_t state) const
    1129                 :            : {
    1130                 :        307 :   update_for_unsuitable_sm_exprs (&var);
    1131                 :            : 
    1132                 :        614 :   int idx = path->num_events () - 1;
    1133                 :       9883 :   while (idx >= 0 && idx < (signed)path->num_events ())
    1134                 :            :     {
    1135                 :       4788 :       checker_event *base_event = path->get_checker_event (idx);
    1136                 :       4788 :       if (get_logger ())
    1137                 :            :         {
    1138                 :          0 :           if (sm)
    1139                 :            :             {
    1140                 :          0 :               if (var)
    1141                 :          0 :                 log ("considering event %i, with var: %qE, state: %qs",
    1142                 :            :                      idx, var, sm->get_state_name (state));
    1143                 :            :               else
    1144                 :          0 :                 log ("considering event %i, with global state: %qs",
    1145                 :            :                      idx, sm->get_state_name (state));
    1146                 :            :             }
    1147                 :            :           else
    1148                 :          0 :             log ("considering event %i", idx);
    1149                 :            :         }
    1150                 :       4788 :       gcc_assert (var == NULL || can_be_expr_of_interest_p (var));
    1151                 :       4788 :       switch (base_event->m_kind)
    1152                 :            :         {
    1153                 :          0 :         default:
    1154                 :          0 :           gcc_unreachable ();
    1155                 :            : 
    1156                 :          0 :         case EK_DEBUG:
    1157                 :          0 :           if (m_verbosity < 4)
    1158                 :            :             {
    1159                 :          0 :               log ("filtering event %i: debug event", idx);
    1160                 :          0 :               path->delete_event (idx);
    1161                 :            :             }
    1162                 :            :           break;
    1163                 :            : 
    1164                 :            :         case EK_CUSTOM:
    1165                 :            :           /* Don't filter custom events.  */
    1166                 :            :           break;
    1167                 :            : 
    1168                 :       1334 :         case EK_STMT:
    1169                 :       1334 :           {
    1170                 :            :             /* If this stmt is the origin of "var", update var.  */
    1171                 :       1334 :             if (var)
    1172                 :            :               {
    1173                 :       1202 :                 statement_event *stmt_event = (statement_event *)base_event;
    1174                 :       2404 :                 tree new_var = get_any_origin (stmt_event->m_stmt, var,
    1175                 :       1202 :                                                stmt_event->m_dst_state);
    1176                 :       1202 :                 if (new_var)
    1177                 :            :                   {
    1178                 :          2 :                     log ("event %i: switching var of interest from %qE to %qE",
    1179                 :            :                          idx, var, new_var);
    1180                 :          2 :                     var = new_var;
    1181                 :            :                   }
    1182                 :            :               }
    1183                 :       1334 :             if (m_verbosity < 4)
    1184                 :            :               {
    1185                 :       1334 :                 log ("filtering event %i: statement event", idx);
    1186                 :       1334 :                 path->delete_event (idx);
    1187                 :            :               }
    1188                 :            :           }
    1189                 :            :           break;
    1190                 :            : 
    1191                 :        464 :         case EK_FUNCTION_ENTRY:
    1192                 :        464 :           if (m_verbosity < 1)
    1193                 :            :             {
    1194                 :          8 :               log ("filtering event %i: function entry", idx);
    1195                 :          8 :               path->delete_event (idx);
    1196                 :            :             }
    1197                 :            :           break;
    1198                 :            : 
    1199                 :        815 :         case EK_STATE_CHANGE:
    1200                 :        815 :           {
    1201                 :        815 :             state_change_event *state_change = (state_change_event *)base_event;
    1202                 :            :             /* Use region IDs to compare var with the state_change's m_var,
    1203                 :            :                bulletproofing against cases where they can't have lvalues by
    1204                 :            :                using tentative_region_model_context.  */
    1205                 :        815 :             tentative_region_model_context ctxt;
    1206                 :        815 :             region_id state_var_rid
    1207                 :        815 :               = state_change->get_lvalue (state_change->m_var, &ctxt);
    1208                 :        815 :             region_id var_rid = state_change->get_lvalue (var, &ctxt);
    1209                 :        815 :             if (state_var_rid == var_rid && !ctxt.had_errors_p ())
    1210                 :            :               {
    1211                 :        359 :                 if (state_change->m_origin)
    1212                 :            :                   {
    1213                 :         38 :                     log ("event %i: switching var of interest from %qE to %qE",
    1214                 :            :                          idx, var, state_change->m_origin);
    1215                 :         38 :                     var = state_change->m_origin;
    1216                 :         38 :                     update_for_unsuitable_sm_exprs (&var);
    1217                 :            :                   }
    1218                 :        359 :                 log ("event %i: switching state of interest from %qs to %qs",
    1219                 :            :                      idx, sm->get_state_name (state_change->m_to),
    1220                 :            :                      sm->get_state_name (state_change->m_from));
    1221                 :        359 :                 state = state_change->m_from;
    1222                 :            :               }
    1223                 :        456 :             else if (m_verbosity < 4)
    1224                 :            :               {
    1225                 :        456 :                 if (var)
    1226                 :        424 :                   log ("filtering event %i:"
    1227                 :            :                        " state change to %qE unrelated to %qE",
    1228                 :            :                        idx, state_change->m_var, var);
    1229                 :            :                 else
    1230                 :         32 :                   log ("filtering event %i: state change to %qE",
    1231                 :            :                        idx, state_change->m_var);
    1232                 :        456 :                 if (ctxt.had_errors_p ())
    1233                 :          1 :                   log ("context had errors");
    1234                 :        456 :                 path->delete_event (idx);
    1235                 :            :               }
    1236                 :            :           }
    1237                 :        815 :           break;
    1238                 :            : 
    1239                 :        956 :         case EK_START_CFG_EDGE:
    1240                 :        956 :           {
    1241                 :        956 :             cfg_edge_event *event = (cfg_edge_event *)base_event;
    1242                 :        956 :             const cfg_superedge& cfg_superedge
    1243                 :        956 :               = event->get_cfg_superedge ();
    1244                 :        956 :             const supernode *dest = event->m_sedge->m_dest;
    1245                 :            :             /* Do we have an SSA_NAME defined via a phi node in
    1246                 :            :                the dest CFG node?  */
    1247                 :        956 :             if (var && TREE_CODE (var) == SSA_NAME)
    1248                 :        635 :               if (SSA_NAME_DEF_STMT (var)->bb == dest->m_bb)
    1249                 :            :                 {
    1250                 :        185 :                   if (gphi *phi
    1251                 :        185 :                       = dyn_cast <gphi *> (SSA_NAME_DEF_STMT (var)))
    1252                 :            :                     {
    1253                 :            :                       /* Update var based on its phi node.  */
    1254                 :         19 :                       tree old_var = var;
    1255                 :         19 :                       var = cfg_superedge.get_phi_arg (phi);
    1256                 :         19 :                       log ("updating from %qE to %qE based on phi node",
    1257                 :            :                            old_var, var);
    1258                 :         19 :                       if (get_logger ())
    1259                 :            :                         {
    1260                 :          0 :                           pretty_printer pp;
    1261                 :          0 :                           pp_gimple_stmt_1 (&pp, phi, 0, (dump_flags_t)0);
    1262                 :          0 :                           log ("  phi: %s", pp_formatted_text (&pp));
    1263                 :            :                         }
    1264                 :            :                       /* If we've chosen a bad exploded_path, then the
    1265                 :            :                          phi arg might be a constant.  Fail gracefully for
    1266                 :            :                          this case.  */
    1267                 :         19 :                       update_for_unsuitable_sm_exprs (&var);
    1268                 :            :                     }
    1269                 :            :                 }
    1270                 :            : 
    1271                 :            :             /* TODO: is this edge significant to var?
    1272                 :            :                See if var can be in other states in the dest, but not
    1273                 :            :                in other states in the src?
    1274                 :            :                Must have multiple sibling edges.  */
    1275                 :            : 
    1276                 :        956 :             if (event->should_filter_p (m_verbosity))
    1277                 :            :               {
    1278                 :        799 :                 log ("filtering event %i: CFG edge", idx);
    1279                 :        799 :                 path->delete_event (idx);
    1280                 :            :                 /* Also delete the corresponding EK_END_CFG_EDGE.  */
    1281                 :        799 :                 gcc_assert (path->get_checker_event (idx)->m_kind
    1282                 :            :                             == EK_END_CFG_EDGE);
    1283                 :        799 :                 path->delete_event (idx);
    1284                 :            :               }
    1285                 :            :           }
    1286                 :            :           break;
    1287                 :            : 
    1288                 :            :         case EK_END_CFG_EDGE:
    1289                 :            :           /* These come in pairs with EK_START_CFG_EDGE events and are
    1290                 :            :              filtered when their start event is filtered.  */
    1291                 :            :           break;
    1292                 :            : 
    1293                 :        149 :         case EK_CALL_EDGE:
    1294                 :        149 :           {
    1295                 :        149 :             call_event *event = (call_event *)base_event;
    1296                 :        149 :             const callgraph_superedge& cg_superedge
    1297                 :        149 :               = event->get_callgraph_superedge ();
    1298                 :        149 :             callsite_expr expr;
    1299                 :        149 :             tree caller_var
    1300                 :        149 :               = cg_superedge.map_expr_from_callee_to_caller (var, &expr);
    1301                 :        149 :             if (caller_var)
    1302                 :            :               {
    1303                 :         84 :                 log ("event %i:"
    1304                 :            :                      " switching var of interest"
    1305                 :            :                      " from %qE in callee to %qE in caller",
    1306                 :            :                      idx, var, caller_var);
    1307                 :         84 :                 var = caller_var;
    1308                 :         84 :                 if (expr.param_p ())
    1309                 :         62 :                   event->record_critical_state (var, state);
    1310                 :         84 :                 update_for_unsuitable_sm_exprs (&var);
    1311                 :            :               }
    1312                 :            :           }
    1313                 :        149 :           break;
    1314                 :            : 
    1315                 :         87 :         case EK_RETURN_EDGE:
    1316                 :            :           // TODO: potentially update var/state based on return value,
    1317                 :            :           // args etc
    1318                 :         87 :           {
    1319                 :         87 :             if (var)
    1320                 :            :               {
    1321                 :         82 :                 return_event *event = (return_event *)base_event;
    1322                 :         82 :                 const callgraph_superedge& cg_superedge
    1323                 :         82 :                   = event->get_callgraph_superedge ();
    1324                 :         82 :                 callsite_expr expr;
    1325                 :         82 :                 tree callee_var
    1326                 :         82 :                   = cg_superedge.map_expr_from_caller_to_callee (var, &expr);
    1327                 :         82 :                 if (callee_var)
    1328                 :            :                   {
    1329                 :         45 :                     log ("event %i:"
    1330                 :            :                          " switching var of interest"
    1331                 :            :                          " from %qE in caller to %qE in callee",
    1332                 :            :                          idx, var, callee_var);
    1333                 :         45 :                     var = callee_var;
    1334                 :         45 :                     if (expr.return_value_p ())
    1335                 :         22 :                       event->record_critical_state (var, state);
    1336                 :         45 :                     update_for_unsuitable_sm_exprs (&var);
    1337                 :            :                   }
    1338                 :            :               }
    1339                 :            :           }
    1340                 :            :           break;
    1341                 :            : 
    1342                 :            :         case EK_SETJMP:
    1343                 :            :           /* TODO: only show setjmp_events that matter i.e. those for which
    1344                 :            :              there is a later rewind event using them.  */
    1345                 :            :         case EK_REWIND_FROM_LONGJMP:
    1346                 :            :         case EK_REWIND_TO_SETJMP:
    1347                 :            :           break;
    1348                 :            : 
    1349                 :            :         case EK_WARNING:
    1350                 :            :           /* Always show the final "warning" event in the path.  */
    1351                 :            :           break;
    1352                 :            :         }
    1353                 :       4788 :       idx--;
    1354                 :            :     }
    1355                 :        307 : }
    1356                 :            : 
    1357                 :            : /* Subroutine of diagnostic_manager::prune_for_sm_diagnostic.
    1358                 :            :    If *EXPR is not suitable to be the expression of interest in
    1359                 :            :    an sm-diagnostic, set *EXPR to NULL and log.  */
    1360                 :            : 
    1361                 :            : void
    1362                 :        493 : diagnostic_manager::update_for_unsuitable_sm_exprs (tree *expr) const
    1363                 :            : {
    1364                 :        493 :   gcc_assert (expr);
    1365                 :        493 :   if (*expr && !can_be_expr_of_interest_p (*expr))
    1366                 :            :     {
    1367                 :          8 :       log ("new var %qE is unsuitable; setting var to NULL", *expr);
    1368                 :          8 :       *expr = NULL_TREE;
    1369                 :            :     }
    1370                 :        493 : }
    1371                 :            : 
    1372                 :            : /* Second pass of diagnostic_manager::prune_path: remove redundant
    1373                 :            :    interprocedural information.
    1374                 :            : 
    1375                 :            :    For example, given:
    1376                 :            :      (1)- calling "f2" from "f1"
    1377                 :            :      (2)--- entry to "f2"
    1378                 :            :      (3)--- calling "f3" from "f2"
    1379                 :            :      (4)----- entry to "f3"
    1380                 :            :      (5)--- returning to "f2" to "f3"
    1381                 :            :      (6)- returning to "f1" to "f2"
    1382                 :            :    with no other intervening events, then none of these events are
    1383                 :            :    likely to be interesting to the user.
    1384                 :            : 
    1385                 :            :    Prune [..., call, function-entry, return, ...] triples repeatedly
    1386                 :            :    until nothing has changed.  For the example above, this would
    1387                 :            :    remove events (3, 4, 5), and then remove events (1, 2, 6).  */
    1388                 :            : 
    1389                 :            : void
    1390                 :        307 : diagnostic_manager::prune_interproc_events (checker_path *path) const
    1391                 :            : {
    1392                 :        307 :   bool changed = false;
    1393                 :        333 :   do
    1394                 :            :     {
    1395                 :        333 :       changed = false;
    1396                 :        666 :       int idx = path->num_events () - 1;
    1397                 :       1852 :       while (idx >= 0)
    1398                 :            :         {
    1399                 :            :           /* Prune [..., call, function-entry, return, ...] triples.  */
    1400                 :       1519 :           if (idx + 2 < (signed)path->num_events ()
    1401                 :        838 :               && path->get_checker_event (idx)->is_call_p ()
    1402                 :        124 :               && path->get_checker_event (idx + 1)->is_function_entry_p ()
    1403                 :       1641 :               && path->get_checker_event (idx + 2)->is_return_p ())
    1404                 :            :             {
    1405                 :         31 :               if (get_logger ())
    1406                 :            :                 {
    1407                 :          0 :                   label_text desc
    1408                 :          0 :                     (path->get_checker_event (idx)->get_desc (false));
    1409                 :          0 :                   log ("filtering events %i-%i:"
    1410                 :            :                        " irrelevant call/entry/return: %s",
    1411                 :            :                        idx, idx + 2, desc.m_buffer);
    1412                 :          0 :                   desc.maybe_free ();
    1413                 :            :                 }
    1414                 :         31 :               path->delete_event (idx + 2);
    1415                 :         31 :               path->delete_event (idx + 1);
    1416                 :         31 :               path->delete_event (idx);
    1417                 :         31 :               changed = true;
    1418                 :         31 :               idx--;
    1419                 :         31 :               continue;
    1420                 :            :             }
    1421                 :            : 
    1422                 :            :           /* Prune [..., call, return, ...] pairs
    1423                 :            :              (for -fanalyzer-verbosity=0).  */
    1424                 :       1488 :           if (idx + 1 < (signed)path->num_events ()
    1425                 :       1136 :               && path->get_checker_event (idx)->is_call_p ()
    1426                 :       1625 :               && path->get_checker_event (idx + 1)->is_return_p ())
    1427                 :            :             {
    1428                 :          1 :               if (get_logger ())
    1429                 :            :                 {
    1430                 :          0 :                   label_text desc
    1431                 :          0 :                     (path->get_checker_event (idx)->get_desc (false));
    1432                 :          0 :                   log ("filtering events %i-%i:"
    1433                 :            :                        " irrelevant call/return: %s",
    1434                 :            :                        idx, idx + 1, desc.m_buffer);
    1435                 :          0 :                   desc.maybe_free ();
    1436                 :            :                 }
    1437                 :          1 :               path->delete_event (idx + 1);
    1438                 :          1 :               path->delete_event (idx);
    1439                 :          1 :               changed = true;
    1440                 :          1 :               idx--;
    1441                 :          1 :               continue;
    1442                 :            :             }
    1443                 :            : 
    1444                 :       1487 :           idx--;
    1445                 :            :         }
    1446                 :            : 
    1447                 :            :     }
    1448                 :            :   while (changed);
    1449                 :        307 : }
    1450                 :            : 
    1451                 :            : /* Final pass of diagnostic_manager::prune_path.
    1452                 :            : 
    1453                 :            :    If all we're left with is in one function, then filter function entry
    1454                 :            :    events.  */
    1455                 :            : 
    1456                 :            : void
    1457                 :        307 : diagnostic_manager::finish_pruning (checker_path *path) const
    1458                 :            : {
    1459                 :        307 :   if (!path->interprocedural_p ())
    1460                 :            :     {
    1461                 :        454 :       int idx = path->num_events () - 1;
    1462                 :       1577 :       while (idx >= 0 && idx < (signed)path->num_events ())
    1463                 :            :         {
    1464                 :        675 :           checker_event *base_event = path->get_checker_event (idx);
    1465                 :        675 :           if (base_event->m_kind == EK_FUNCTION_ENTRY)
    1466                 :            :             {
    1467                 :        226 :               log ("filtering event %i:"
    1468                 :            :                    " function entry for purely intraprocedural path", idx);
    1469                 :        226 :               path->delete_event (idx);
    1470                 :            :             }
    1471                 :        675 :           idx--;
    1472                 :            :         }
    1473                 :            :     }
    1474                 :        307 : }
    1475                 :            : 
    1476                 :            : } // namespace ana
    1477                 :            : 
    1478                 :            : #endif /* #if ENABLE_ANALYZER */

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.