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