1*4c3eb207Smrg /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2*4c3eb207Smrg Copyright (C) 2019-2020 Free Software Foundation, Inc.
3*4c3eb207Smrg Contributed by David Malcolm <dmalcolm@redhat.com>.
4*4c3eb207Smrg
5*4c3eb207Smrg This file is part of GCC.
6*4c3eb207Smrg
7*4c3eb207Smrg GCC is free software; you can redistribute it and/or modify it
8*4c3eb207Smrg under the terms of the GNU General Public License as published by
9*4c3eb207Smrg the Free Software Foundation; either version 3, or (at your option)
10*4c3eb207Smrg any later version.
11*4c3eb207Smrg
12*4c3eb207Smrg GCC is distributed in the hope that it will be useful, but
13*4c3eb207Smrg WITHOUT ANY WARRANTY; without even the implied warranty of
14*4c3eb207Smrg MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15*4c3eb207Smrg General Public License for more details.
16*4c3eb207Smrg
17*4c3eb207Smrg You should have received a copy of the GNU General Public License
18*4c3eb207Smrg along with GCC; see the file COPYING3. If not see
19*4c3eb207Smrg <http://www.gnu.org/licenses/>. */
20*4c3eb207Smrg
21*4c3eb207Smrg #include "config.h"
22*4c3eb207Smrg #include "system.h"
23*4c3eb207Smrg #include "coretypes.h"
24*4c3eb207Smrg #include "tree.h"
25*4c3eb207Smrg #include "function.h"
26*4c3eb207Smrg #include "basic-block.h"
27*4c3eb207Smrg #include "gimple.h"
28*4c3eb207Smrg #include "gimple-pretty-print.h"
29*4c3eb207Smrg #include "fold-const.h"
30*4c3eb207Smrg #include "function.h"
31*4c3eb207Smrg #include "diagnostic-path.h"
32*4c3eb207Smrg #include "options.h"
33*4c3eb207Smrg #include "cgraph.h"
34*4c3eb207Smrg #include "function.h"
35*4c3eb207Smrg #include "cfg.h"
36*4c3eb207Smrg #include "digraph.h"
37*4c3eb207Smrg #include "alloc-pool.h"
38*4c3eb207Smrg #include "fibonacci_heap.h"
39*4c3eb207Smrg #include "diagnostic-event-id.h"
40*4c3eb207Smrg #include "shortest-paths.h"
41*4c3eb207Smrg #include "analyzer/analyzer.h"
42*4c3eb207Smrg #include "analyzer/analyzer-logging.h"
43*4c3eb207Smrg #include "analyzer/sm.h"
44*4c3eb207Smrg #include "sbitmap.h"
45*4c3eb207Smrg #include "bitmap.h"
46*4c3eb207Smrg #include "tristate.h"
47*4c3eb207Smrg #include "ordered-hash-map.h"
48*4c3eb207Smrg #include "selftest.h"
49*4c3eb207Smrg #include "analyzer/region-model.h"
50*4c3eb207Smrg #include "analyzer/program-state.h"
51*4c3eb207Smrg #include "analyzer/checker-path.h"
52*4c3eb207Smrg #include "gimple-iterator.h"
53*4c3eb207Smrg #include "analyzer/supergraph.h"
54*4c3eb207Smrg #include "analyzer/pending-diagnostic.h"
55*4c3eb207Smrg #include "analyzer/diagnostic-manager.h"
56*4c3eb207Smrg #include "analyzer/constraint-manager.h"
57*4c3eb207Smrg #include "analyzer/diagnostic-manager.h"
58*4c3eb207Smrg #include "analyzer/checker-path.h"
59*4c3eb207Smrg #include "analyzer/call-string.h"
60*4c3eb207Smrg #include "analyzer/program-point.h"
61*4c3eb207Smrg #include "analyzer/exploded-graph.h"
62*4c3eb207Smrg
63*4c3eb207Smrg #if ENABLE_ANALYZER
64*4c3eb207Smrg
65*4c3eb207Smrg namespace ana {
66*4c3eb207Smrg
67*4c3eb207Smrg /* Get a string for EK. */
68*4c3eb207Smrg
69*4c3eb207Smrg const char *
event_kind_to_string(enum event_kind ek)70*4c3eb207Smrg event_kind_to_string (enum event_kind ek)
71*4c3eb207Smrg {
72*4c3eb207Smrg switch (ek)
73*4c3eb207Smrg {
74*4c3eb207Smrg default:
75*4c3eb207Smrg gcc_unreachable ();
76*4c3eb207Smrg case EK_DEBUG:
77*4c3eb207Smrg return "EK_DEBUG";
78*4c3eb207Smrg case EK_CUSTOM:
79*4c3eb207Smrg return "EK_CUSTOM";
80*4c3eb207Smrg case EK_STMT:
81*4c3eb207Smrg return "EK_STMT";
82*4c3eb207Smrg case EK_FUNCTION_ENTRY:
83*4c3eb207Smrg return "EK_FUNCTION_ENTRY";
84*4c3eb207Smrg case EK_STATE_CHANGE:
85*4c3eb207Smrg return "EK_STATE_CHANGE";
86*4c3eb207Smrg case EK_START_CFG_EDGE:
87*4c3eb207Smrg return "EK_START_CFG_EDGE";
88*4c3eb207Smrg case EK_END_CFG_EDGE:
89*4c3eb207Smrg return "EK_END_CFG_EDGE";
90*4c3eb207Smrg case EK_CALL_EDGE:
91*4c3eb207Smrg return "EK_CALL_EDGE";
92*4c3eb207Smrg case EK_RETURN_EDGE:
93*4c3eb207Smrg return "EK_RETURN_EDGE";
94*4c3eb207Smrg case EK_SETJMP:
95*4c3eb207Smrg return "EK_SETJMP";
96*4c3eb207Smrg case EK_REWIND_FROM_LONGJMP:
97*4c3eb207Smrg return "EK_REWIND_FROM_LONGJMP";
98*4c3eb207Smrg case EK_REWIND_TO_SETJMP:
99*4c3eb207Smrg return "EK_REWIND_TO_SETJMP";
100*4c3eb207Smrg case EK_WARNING:
101*4c3eb207Smrg return "EK_WARNING";
102*4c3eb207Smrg }
103*4c3eb207Smrg }
104*4c3eb207Smrg
105*4c3eb207Smrg /* class checker_event : public diagnostic_event. */
106*4c3eb207Smrg
107*4c3eb207Smrg /* Dump this event to PP (for debugging/logging purposes). */
108*4c3eb207Smrg
109*4c3eb207Smrg void
dump(pretty_printer * pp) const110*4c3eb207Smrg checker_event::dump (pretty_printer *pp) const
111*4c3eb207Smrg {
112*4c3eb207Smrg label_text event_desc (get_desc (false));
113*4c3eb207Smrg pp_printf (pp, "\"%s\" (depth %i, m_loc=%x)",
114*4c3eb207Smrg event_desc.m_buffer,
115*4c3eb207Smrg get_stack_depth (),
116*4c3eb207Smrg get_location ());
117*4c3eb207Smrg event_desc.maybe_free ();
118*4c3eb207Smrg }
119*4c3eb207Smrg
120*4c3eb207Smrg /* Hook for being notified when this event has its final id EMISSION_ID
121*4c3eb207Smrg and is about to emitted for PD.
122*4c3eb207Smrg
123*4c3eb207Smrg Base implementation of checker_event::prepare_for_emission vfunc;
124*4c3eb207Smrg subclasses that override this should chain up to it.
125*4c3eb207Smrg
126*4c3eb207Smrg Record PD and EMISSION_ID, and call the get_desc vfunc, so that any
127*4c3eb207Smrg side-effects of the call to get_desc take place before
128*4c3eb207Smrg pending_diagnostic::emit is called.
129*4c3eb207Smrg
130*4c3eb207Smrg For example, state_change_event::get_desc can call
131*4c3eb207Smrg pending_diagnostic::describe_state_change; free_of_non_heap can use this
132*4c3eb207Smrg to tweak the message (TODO: would be neater to simply capture the
133*4c3eb207Smrg pertinent data within the sm-state). */
134*4c3eb207Smrg
135*4c3eb207Smrg void
prepare_for_emission(checker_path *,pending_diagnostic * pd,diagnostic_event_id_t emission_id)136*4c3eb207Smrg checker_event::prepare_for_emission (checker_path *,
137*4c3eb207Smrg pending_diagnostic *pd,
138*4c3eb207Smrg diagnostic_event_id_t emission_id)
139*4c3eb207Smrg {
140*4c3eb207Smrg m_pending_diagnostic = pd;
141*4c3eb207Smrg m_emission_id = emission_id;
142*4c3eb207Smrg
143*4c3eb207Smrg label_text desc = get_desc (false);
144*4c3eb207Smrg desc.maybe_free ();
145*4c3eb207Smrg }
146*4c3eb207Smrg
147*4c3eb207Smrg /* class debug_event : public checker_event. */
148*4c3eb207Smrg
149*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
150*4c3eb207Smrg debug_event.
151*4c3eb207Smrg Use the saved string as the event's description. */
152*4c3eb207Smrg
153*4c3eb207Smrg label_text
get_desc(bool) const154*4c3eb207Smrg debug_event::get_desc (bool) const
155*4c3eb207Smrg {
156*4c3eb207Smrg return label_text::borrow (m_desc);
157*4c3eb207Smrg }
158*4c3eb207Smrg
159*4c3eb207Smrg /* class custom_event : public checker_event. */
160*4c3eb207Smrg
161*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
162*4c3eb207Smrg custom_event.
163*4c3eb207Smrg Use the saved string as the event's description. */
164*4c3eb207Smrg
165*4c3eb207Smrg label_text
get_desc(bool) const166*4c3eb207Smrg custom_event::get_desc (bool) const
167*4c3eb207Smrg {
168*4c3eb207Smrg return label_text::borrow (m_desc);
169*4c3eb207Smrg }
170*4c3eb207Smrg
171*4c3eb207Smrg /* class statement_event : public checker_event. */
172*4c3eb207Smrg
173*4c3eb207Smrg /* statement_event's ctor. */
174*4c3eb207Smrg
statement_event(const gimple * stmt,tree fndecl,int depth,const program_state & dst_state)175*4c3eb207Smrg statement_event::statement_event (const gimple *stmt, tree fndecl, int depth,
176*4c3eb207Smrg const program_state &dst_state)
177*4c3eb207Smrg : checker_event (EK_STMT, gimple_location (stmt), fndecl, depth),
178*4c3eb207Smrg m_stmt (stmt),
179*4c3eb207Smrg m_dst_state (dst_state)
180*4c3eb207Smrg {
181*4c3eb207Smrg }
182*4c3eb207Smrg
183*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
184*4c3eb207Smrg statement_event.
185*4c3eb207Smrg Use the statement's dump form as the event's description. */
186*4c3eb207Smrg
187*4c3eb207Smrg label_text
get_desc(bool) const188*4c3eb207Smrg statement_event::get_desc (bool) const
189*4c3eb207Smrg {
190*4c3eb207Smrg pretty_printer pp;
191*4c3eb207Smrg pp_string (&pp, "stmt: ");
192*4c3eb207Smrg pp_gimple_stmt_1 (&pp, m_stmt, 0, (dump_flags_t)0);
193*4c3eb207Smrg return label_text::take (xstrdup (pp_formatted_text (&pp)));
194*4c3eb207Smrg }
195*4c3eb207Smrg
196*4c3eb207Smrg /* class function_entry_event : public checker_event. */
197*4c3eb207Smrg
198*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
199*4c3eb207Smrg function_entry_event.
200*4c3eb207Smrg
201*4c3eb207Smrg Use a string such as "entry to 'foo'" as the event's description. */
202*4c3eb207Smrg
203*4c3eb207Smrg label_text
get_desc(bool can_colorize) const204*4c3eb207Smrg function_entry_event::get_desc (bool can_colorize) const
205*4c3eb207Smrg {
206*4c3eb207Smrg return make_label_text (can_colorize, "entry to %qE", m_fndecl);
207*4c3eb207Smrg }
208*4c3eb207Smrg
209*4c3eb207Smrg /* class state_change_event : public checker_event. */
210*4c3eb207Smrg
211*4c3eb207Smrg /* state_change_event's ctor. */
212*4c3eb207Smrg
state_change_event(const supernode * node,const gimple * stmt,int stack_depth,const state_machine & sm,tree var,state_machine::state_t from,state_machine::state_t to,tree origin,const program_state & dst_state)213*4c3eb207Smrg state_change_event::state_change_event (const supernode *node,
214*4c3eb207Smrg const gimple *stmt,
215*4c3eb207Smrg int stack_depth,
216*4c3eb207Smrg const state_machine &sm,
217*4c3eb207Smrg tree var,
218*4c3eb207Smrg state_machine::state_t from,
219*4c3eb207Smrg state_machine::state_t to,
220*4c3eb207Smrg tree origin,
221*4c3eb207Smrg const program_state &dst_state)
222*4c3eb207Smrg : checker_event (EK_STATE_CHANGE,
223*4c3eb207Smrg stmt->location, node->m_fun->decl,
224*4c3eb207Smrg stack_depth),
225*4c3eb207Smrg m_node (node), m_stmt (stmt), m_sm (sm),
226*4c3eb207Smrg m_var (var), m_from (from), m_to (to),
227*4c3eb207Smrg m_origin (origin),
228*4c3eb207Smrg m_dst_state (dst_state)
229*4c3eb207Smrg {
230*4c3eb207Smrg }
231*4c3eb207Smrg
232*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
233*4c3eb207Smrg state_change_event.
234*4c3eb207Smrg
235*4c3eb207Smrg Attempt to generate a nicer human-readable description.
236*4c3eb207Smrg For greatest precision-of-wording, give the pending diagnostic
237*4c3eb207Smrg a chance to describe this state change (in terms of the
238*4c3eb207Smrg diagnostic).
239*4c3eb207Smrg Note that we only have a pending_diagnostic set on the event once
240*4c3eb207Smrg the diagnostic is about to being emitted, so the description for
241*4c3eb207Smrg an event can change. */
242*4c3eb207Smrg
243*4c3eb207Smrg label_text
get_desc(bool can_colorize) const244*4c3eb207Smrg state_change_event::get_desc (bool can_colorize) const
245*4c3eb207Smrg {
246*4c3eb207Smrg if (m_pending_diagnostic)
247*4c3eb207Smrg {
248*4c3eb207Smrg label_text custom_desc
249*4c3eb207Smrg = m_pending_diagnostic->describe_state_change
250*4c3eb207Smrg (evdesc::state_change (can_colorize, m_var, m_origin,
251*4c3eb207Smrg m_from, m_to, m_emission_id, *this));
252*4c3eb207Smrg if (custom_desc.m_buffer)
253*4c3eb207Smrg {
254*4c3eb207Smrg if (flag_analyzer_verbose_state_changes)
255*4c3eb207Smrg {
256*4c3eb207Smrg /* Append debug version. */
257*4c3eb207Smrg label_text result;
258*4c3eb207Smrg if (m_origin)
259*4c3eb207Smrg result = make_label_text
260*4c3eb207Smrg (can_colorize,
261*4c3eb207Smrg "%s (state of %qE: %qs -> %qs, origin: %qE)",
262*4c3eb207Smrg custom_desc.m_buffer,
263*4c3eb207Smrg m_var,
264*4c3eb207Smrg m_sm.get_state_name (m_from),
265*4c3eb207Smrg m_sm.get_state_name (m_to),
266*4c3eb207Smrg m_origin);
267*4c3eb207Smrg else
268*4c3eb207Smrg result = make_label_text
269*4c3eb207Smrg (can_colorize,
270*4c3eb207Smrg "%s (state of %qE: %qs -> %qs, origin: NULL)",
271*4c3eb207Smrg custom_desc.m_buffer,
272*4c3eb207Smrg m_var,
273*4c3eb207Smrg m_sm.get_state_name (m_from),
274*4c3eb207Smrg m_sm.get_state_name (m_to));
275*4c3eb207Smrg custom_desc.maybe_free ();
276*4c3eb207Smrg return result;
277*4c3eb207Smrg }
278*4c3eb207Smrg else
279*4c3eb207Smrg return custom_desc;
280*4c3eb207Smrg }
281*4c3eb207Smrg }
282*4c3eb207Smrg
283*4c3eb207Smrg /* Fallback description. */
284*4c3eb207Smrg if (m_var)
285*4c3eb207Smrg {
286*4c3eb207Smrg if (m_origin)
287*4c3eb207Smrg return make_label_text
288*4c3eb207Smrg (can_colorize,
289*4c3eb207Smrg "state of %qE: %qs -> %qs (origin: %qE)",
290*4c3eb207Smrg m_var,
291*4c3eb207Smrg m_sm.get_state_name (m_from),
292*4c3eb207Smrg m_sm.get_state_name (m_to),
293*4c3eb207Smrg m_origin);
294*4c3eb207Smrg else
295*4c3eb207Smrg return make_label_text
296*4c3eb207Smrg (can_colorize,
297*4c3eb207Smrg "state of %qE: %qs -> %qs (origin: NULL)",
298*4c3eb207Smrg m_var,
299*4c3eb207Smrg m_sm.get_state_name (m_from),
300*4c3eb207Smrg m_sm.get_state_name (m_to));
301*4c3eb207Smrg }
302*4c3eb207Smrg else
303*4c3eb207Smrg {
304*4c3eb207Smrg gcc_assert (m_origin == NULL_TREE);
305*4c3eb207Smrg return make_label_text
306*4c3eb207Smrg (can_colorize,
307*4c3eb207Smrg "global state: %qs -> %qs",
308*4c3eb207Smrg m_sm.get_state_name (m_from),
309*4c3eb207Smrg m_sm.get_state_name (m_to));
310*4c3eb207Smrg }
311*4c3eb207Smrg }
312*4c3eb207Smrg
313*4c3eb207Smrg /* class superedge_event : public checker_event. */
314*4c3eb207Smrg
315*4c3eb207Smrg /* Get the callgraph_superedge for this superedge_event, which must be
316*4c3eb207Smrg for an interprocedural edge, rather than a CFG edge. */
317*4c3eb207Smrg
318*4c3eb207Smrg const callgraph_superedge&
get_callgraph_superedge() const319*4c3eb207Smrg superedge_event::get_callgraph_superedge () const
320*4c3eb207Smrg {
321*4c3eb207Smrg gcc_assert (m_sedge->m_kind != SUPEREDGE_CFG_EDGE);
322*4c3eb207Smrg return *m_sedge->dyn_cast_callgraph_superedge ();
323*4c3eb207Smrg }
324*4c3eb207Smrg
325*4c3eb207Smrg /* Determine if this event should be filtered at the given verbosity
326*4c3eb207Smrg level. */
327*4c3eb207Smrg
328*4c3eb207Smrg bool
should_filter_p(int verbosity) const329*4c3eb207Smrg superedge_event::should_filter_p (int verbosity) const
330*4c3eb207Smrg {
331*4c3eb207Smrg switch (m_sedge->m_kind)
332*4c3eb207Smrg {
333*4c3eb207Smrg case SUPEREDGE_CFG_EDGE:
334*4c3eb207Smrg {
335*4c3eb207Smrg if (verbosity < 2)
336*4c3eb207Smrg return true;
337*4c3eb207Smrg
338*4c3eb207Smrg if (verbosity < 4)
339*4c3eb207Smrg {
340*4c3eb207Smrg /* Filter events with empty descriptions. This ought to filter
341*4c3eb207Smrg FALLTHRU, but retain true/false/switch edges. */
342*4c3eb207Smrg label_text desc = get_desc (false);
343*4c3eb207Smrg gcc_assert (desc.m_buffer);
344*4c3eb207Smrg if (desc.m_buffer[0] == '\0')
345*4c3eb207Smrg return true;
346*4c3eb207Smrg desc.maybe_free ();
347*4c3eb207Smrg }
348*4c3eb207Smrg }
349*4c3eb207Smrg break;
350*4c3eb207Smrg
351*4c3eb207Smrg default:
352*4c3eb207Smrg break;
353*4c3eb207Smrg }
354*4c3eb207Smrg return false;
355*4c3eb207Smrg }
356*4c3eb207Smrg
357*4c3eb207Smrg /* superedge_event's ctor. */
358*4c3eb207Smrg
superedge_event(enum event_kind kind,const exploded_edge & eedge,location_t loc,tree fndecl,int depth)359*4c3eb207Smrg superedge_event::superedge_event (enum event_kind kind,
360*4c3eb207Smrg const exploded_edge &eedge,
361*4c3eb207Smrg location_t loc, tree fndecl, int depth)
362*4c3eb207Smrg : checker_event (kind, loc, fndecl, depth),
363*4c3eb207Smrg m_eedge (eedge), m_sedge (eedge.m_sedge),
364*4c3eb207Smrg m_var (NULL_TREE), m_critical_state (0)
365*4c3eb207Smrg {
366*4c3eb207Smrg }
367*4c3eb207Smrg
368*4c3eb207Smrg /* class cfg_edge_event : public superedge_event. */
369*4c3eb207Smrg
370*4c3eb207Smrg /* Get the cfg_superedge for this cfg_edge_event. */
371*4c3eb207Smrg
372*4c3eb207Smrg const cfg_superedge &
get_cfg_superedge() const373*4c3eb207Smrg cfg_edge_event::get_cfg_superedge () const
374*4c3eb207Smrg {
375*4c3eb207Smrg return *m_sedge->dyn_cast_cfg_superedge ();
376*4c3eb207Smrg }
377*4c3eb207Smrg
378*4c3eb207Smrg /* cfg_edge_event's ctor. */
379*4c3eb207Smrg
cfg_edge_event(enum event_kind kind,const exploded_edge & eedge,location_t loc,tree fndecl,int depth)380*4c3eb207Smrg cfg_edge_event::cfg_edge_event (enum event_kind kind,
381*4c3eb207Smrg const exploded_edge &eedge,
382*4c3eb207Smrg location_t loc, tree fndecl, int depth)
383*4c3eb207Smrg : superedge_event (kind, eedge, loc, fndecl, depth)
384*4c3eb207Smrg {
385*4c3eb207Smrg gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CFG_EDGE);
386*4c3eb207Smrg }
387*4c3eb207Smrg
388*4c3eb207Smrg /* class start_cfg_edge_event : public cfg_edge_event. */
389*4c3eb207Smrg
390*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
391*4c3eb207Smrg start_cfg_edge_event.
392*4c3eb207Smrg
393*4c3eb207Smrg If -fanalyzer-verbose-edges, then generate low-level descriptions, such
394*4c3eb207Smrg as
395*4c3eb207Smrg "taking 'true' edge SN:7 -> SN:8".
396*4c3eb207Smrg
397*4c3eb207Smrg Otherwise, generate strings using the label of the underlying CFG if
398*4c3eb207Smrg any, such as:
399*4c3eb207Smrg "following 'true' branch..." or
400*4c3eb207Smrg "following 'case 3' branch..."
401*4c3eb207Smrg "following 'default' branch..."
402*4c3eb207Smrg
403*4c3eb207Smrg For conditionals, attempt to supply a description of the condition that
404*4c3eb207Smrg holds, such as:
405*4c3eb207Smrg "following 'false' branch (when 'ptr' is non-NULL)..."
406*4c3eb207Smrg
407*4c3eb207Smrg Failing that, return an empty description (which will lead to this event
408*4c3eb207Smrg being filtered). */
409*4c3eb207Smrg
410*4c3eb207Smrg label_text
get_desc(bool can_colorize) const411*4c3eb207Smrg start_cfg_edge_event::get_desc (bool can_colorize) const
412*4c3eb207Smrg {
413*4c3eb207Smrg bool user_facing = !flag_analyzer_verbose_edges;
414*4c3eb207Smrg char *edge_desc = m_sedge->get_description (user_facing);
415*4c3eb207Smrg if (user_facing)
416*4c3eb207Smrg {
417*4c3eb207Smrg if (edge_desc && strlen (edge_desc) > 0)
418*4c3eb207Smrg {
419*4c3eb207Smrg label_text cond_desc = maybe_describe_condition (can_colorize);
420*4c3eb207Smrg label_text result;
421*4c3eb207Smrg if (cond_desc.m_buffer)
422*4c3eb207Smrg {
423*4c3eb207Smrg result = make_label_text (can_colorize,
424*4c3eb207Smrg "following %qs branch (%s)...",
425*4c3eb207Smrg edge_desc, cond_desc.m_buffer);
426*4c3eb207Smrg cond_desc.maybe_free ();
427*4c3eb207Smrg }
428*4c3eb207Smrg else
429*4c3eb207Smrg {
430*4c3eb207Smrg result = make_label_text (can_colorize,
431*4c3eb207Smrg "following %qs branch...",
432*4c3eb207Smrg edge_desc);
433*4c3eb207Smrg }
434*4c3eb207Smrg free (edge_desc);
435*4c3eb207Smrg return result;
436*4c3eb207Smrg }
437*4c3eb207Smrg else
438*4c3eb207Smrg {
439*4c3eb207Smrg free (edge_desc);
440*4c3eb207Smrg return label_text::borrow ("");
441*4c3eb207Smrg }
442*4c3eb207Smrg }
443*4c3eb207Smrg else
444*4c3eb207Smrg {
445*4c3eb207Smrg if (strlen (edge_desc) > 0)
446*4c3eb207Smrg {
447*4c3eb207Smrg label_text result
448*4c3eb207Smrg = make_label_text (can_colorize,
449*4c3eb207Smrg "taking %qs edge SN:%i -> SN:%i",
450*4c3eb207Smrg edge_desc,
451*4c3eb207Smrg m_sedge->m_src->m_index,
452*4c3eb207Smrg m_sedge->m_dest->m_index);
453*4c3eb207Smrg free (edge_desc);
454*4c3eb207Smrg return result;
455*4c3eb207Smrg }
456*4c3eb207Smrg else
457*4c3eb207Smrg {
458*4c3eb207Smrg free (edge_desc);
459*4c3eb207Smrg return make_label_text (can_colorize,
460*4c3eb207Smrg "taking edge SN:%i -> SN:%i",
461*4c3eb207Smrg m_sedge->m_src->m_index,
462*4c3eb207Smrg m_sedge->m_dest->m_index);
463*4c3eb207Smrg }
464*4c3eb207Smrg }
465*4c3eb207Smrg }
466*4c3eb207Smrg
467*4c3eb207Smrg /* Attempt to generate a description of any condition that holds at this edge.
468*4c3eb207Smrg
469*4c3eb207Smrg The intent is to make the user-facing messages more clear, especially for
470*4c3eb207Smrg cases where there's a single or double-negative, such as
471*4c3eb207Smrg when describing the false branch of an inverted condition.
472*4c3eb207Smrg
473*4c3eb207Smrg For example, rather than printing just:
474*4c3eb207Smrg
475*4c3eb207Smrg | if (!ptr)
476*4c3eb207Smrg | ~
477*4c3eb207Smrg | |
478*4c3eb207Smrg | (1) following 'false' branch...
479*4c3eb207Smrg
480*4c3eb207Smrg it's clearer to spell out the condition that holds:
481*4c3eb207Smrg
482*4c3eb207Smrg | if (!ptr)
483*4c3eb207Smrg | ~
484*4c3eb207Smrg | |
485*4c3eb207Smrg | (1) following 'false' branch (when 'ptr' is non-NULL)...
486*4c3eb207Smrg ^^^^^^^^^^^^^^^^^^^^^^
487*4c3eb207Smrg
488*4c3eb207Smrg In the above example, this function would generate the highlighted
489*4c3eb207Smrg string: "when 'ptr' is non-NULL".
490*4c3eb207Smrg
491*4c3eb207Smrg If the edge is not a condition, or it's not clear that a description of
492*4c3eb207Smrg the condition would be helpful to the user, return NULL. */
493*4c3eb207Smrg
494*4c3eb207Smrg label_text
maybe_describe_condition(bool can_colorize) const495*4c3eb207Smrg start_cfg_edge_event::maybe_describe_condition (bool can_colorize) const
496*4c3eb207Smrg {
497*4c3eb207Smrg const cfg_superedge& cfg_sedge = get_cfg_superedge ();
498*4c3eb207Smrg
499*4c3eb207Smrg if (cfg_sedge.true_value_p () || cfg_sedge.false_value_p ())
500*4c3eb207Smrg {
501*4c3eb207Smrg const gimple *last_stmt = m_sedge->m_src->get_last_stmt ();
502*4c3eb207Smrg if (const gcond *cond_stmt = dyn_cast <const gcond *> (last_stmt))
503*4c3eb207Smrg {
504*4c3eb207Smrg enum tree_code op = gimple_cond_code (cond_stmt);
505*4c3eb207Smrg tree lhs = gimple_cond_lhs (cond_stmt);
506*4c3eb207Smrg tree rhs = gimple_cond_rhs (cond_stmt);
507*4c3eb207Smrg if (cfg_sedge.false_value_p ())
508*4c3eb207Smrg op = invert_tree_comparison (op, false /* honor_nans */);
509*4c3eb207Smrg return maybe_describe_condition (can_colorize,
510*4c3eb207Smrg lhs, op, rhs);
511*4c3eb207Smrg }
512*4c3eb207Smrg }
513*4c3eb207Smrg return label_text::borrow (NULL);
514*4c3eb207Smrg }
515*4c3eb207Smrg
516*4c3eb207Smrg /* Subroutine of maybe_describe_condition above.
517*4c3eb207Smrg
518*4c3eb207Smrg Attempt to generate a user-facing description of the condition
519*4c3eb207Smrg LHS OP RHS, but only if it is likely to make it easier for the
520*4c3eb207Smrg user to understand a condition. */
521*4c3eb207Smrg
522*4c3eb207Smrg label_text
maybe_describe_condition(bool can_colorize,tree lhs,enum tree_code op,tree rhs)523*4c3eb207Smrg start_cfg_edge_event::maybe_describe_condition (bool can_colorize,
524*4c3eb207Smrg tree lhs,
525*4c3eb207Smrg enum tree_code op,
526*4c3eb207Smrg tree rhs)
527*4c3eb207Smrg {
528*4c3eb207Smrg /* In theory we could just build a tree via
529*4c3eb207Smrg fold_build2 (op, boolean_type_node, lhs, rhs)
530*4c3eb207Smrg and print it with %qE on it, but this leads to warts such as
531*4c3eb207Smrg parenthesizing vars, such as '(i) <= 9', and uses of '<unknown>'. */
532*4c3eb207Smrg
533*4c3eb207Smrg /* Special-case: describe testing the result of strcmp, as figuring
534*4c3eb207Smrg out what the "true" or "false" path is can be confusing to the user. */
535*4c3eb207Smrg if (TREE_CODE (lhs) == SSA_NAME
536*4c3eb207Smrg && zerop (rhs))
537*4c3eb207Smrg {
538*4c3eb207Smrg if (gcall *call = dyn_cast <gcall *> (SSA_NAME_DEF_STMT (lhs)))
539*4c3eb207Smrg if (is_special_named_call_p (call, "strcmp", 2))
540*4c3eb207Smrg {
541*4c3eb207Smrg if (op == EQ_EXPR)
542*4c3eb207Smrg return label_text::borrow ("when the strings are equal");
543*4c3eb207Smrg if (op == NE_EXPR)
544*4c3eb207Smrg return label_text::borrow ("when the strings are non-equal");
545*4c3eb207Smrg }
546*4c3eb207Smrg }
547*4c3eb207Smrg
548*4c3eb207Smrg /* Only attempt to generate text for sufficiently simple expressions. */
549*4c3eb207Smrg if (!should_print_expr_p (lhs))
550*4c3eb207Smrg return label_text::borrow (NULL);
551*4c3eb207Smrg if (!should_print_expr_p (rhs))
552*4c3eb207Smrg return label_text::borrow (NULL);
553*4c3eb207Smrg
554*4c3eb207Smrg /* Special cases for pointer comparisons against NULL. */
555*4c3eb207Smrg if (POINTER_TYPE_P (TREE_TYPE (lhs))
556*4c3eb207Smrg && POINTER_TYPE_P (TREE_TYPE (rhs))
557*4c3eb207Smrg && zerop (rhs))
558*4c3eb207Smrg {
559*4c3eb207Smrg if (op == EQ_EXPR)
560*4c3eb207Smrg return make_label_text (can_colorize, "when %qE is NULL",
561*4c3eb207Smrg lhs);
562*4c3eb207Smrg if (op == NE_EXPR)
563*4c3eb207Smrg return make_label_text (can_colorize, "when %qE is non-NULL",
564*4c3eb207Smrg lhs);
565*4c3eb207Smrg }
566*4c3eb207Smrg
567*4c3eb207Smrg return make_label_text (can_colorize, "when %<%E %s %E%>",
568*4c3eb207Smrg lhs, op_symbol_code (op), rhs);
569*4c3eb207Smrg }
570*4c3eb207Smrg
571*4c3eb207Smrg /* Subroutine of maybe_describe_condition.
572*4c3eb207Smrg
573*4c3eb207Smrg Return true if EXPR is we will get suitable user-facing output
574*4c3eb207Smrg from %E on it. */
575*4c3eb207Smrg
576*4c3eb207Smrg bool
should_print_expr_p(tree expr)577*4c3eb207Smrg start_cfg_edge_event::should_print_expr_p (tree expr)
578*4c3eb207Smrg {
579*4c3eb207Smrg if (TREE_CODE (expr) == SSA_NAME)
580*4c3eb207Smrg {
581*4c3eb207Smrg if (SSA_NAME_VAR (expr))
582*4c3eb207Smrg return should_print_expr_p (SSA_NAME_VAR (expr));
583*4c3eb207Smrg else
584*4c3eb207Smrg return false;
585*4c3eb207Smrg }
586*4c3eb207Smrg
587*4c3eb207Smrg if (DECL_P (expr))
588*4c3eb207Smrg return true;
589*4c3eb207Smrg
590*4c3eb207Smrg if (CONSTANT_CLASS_P (expr))
591*4c3eb207Smrg return true;
592*4c3eb207Smrg
593*4c3eb207Smrg return false;
594*4c3eb207Smrg }
595*4c3eb207Smrg
596*4c3eb207Smrg /* class call_event : public superedge_event. */
597*4c3eb207Smrg
598*4c3eb207Smrg /* call_event's ctor. */
599*4c3eb207Smrg
call_event(const exploded_edge & eedge,location_t loc,tree fndecl,int depth)600*4c3eb207Smrg call_event::call_event (const exploded_edge &eedge,
601*4c3eb207Smrg location_t loc, tree fndecl, int depth)
602*4c3eb207Smrg : superedge_event (EK_CALL_EDGE, eedge, loc, fndecl, depth)
603*4c3eb207Smrg {
604*4c3eb207Smrg gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_CALL);
605*4c3eb207Smrg }
606*4c3eb207Smrg
607*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
608*4c3eb207Smrg call_event.
609*4c3eb207Smrg
610*4c3eb207Smrg If this call event passes critical state for an sm-based warning,
611*4c3eb207Smrg allow the diagnostic to generate a precise description, such as:
612*4c3eb207Smrg
613*4c3eb207Smrg "passing freed pointer 'ptr' in call to 'foo' from 'bar'"
614*4c3eb207Smrg
615*4c3eb207Smrg Otherwise, generate a description of the form
616*4c3eb207Smrg "calling 'foo' from 'bar'". */
617*4c3eb207Smrg
618*4c3eb207Smrg label_text
get_desc(bool can_colorize) const619*4c3eb207Smrg call_event::get_desc (bool can_colorize) const
620*4c3eb207Smrg {
621*4c3eb207Smrg if (m_critical_state && m_pending_diagnostic)
622*4c3eb207Smrg {
623*4c3eb207Smrg gcc_assert (m_var);
624*4c3eb207Smrg label_text custom_desc
625*4c3eb207Smrg = m_pending_diagnostic->describe_call_with_state
626*4c3eb207Smrg (evdesc::call_with_state (can_colorize,
627*4c3eb207Smrg m_sedge->m_src->m_fun->decl,
628*4c3eb207Smrg m_sedge->m_dest->m_fun->decl,
629*4c3eb207Smrg m_var,
630*4c3eb207Smrg m_critical_state));
631*4c3eb207Smrg if (custom_desc.m_buffer)
632*4c3eb207Smrg return custom_desc;
633*4c3eb207Smrg }
634*4c3eb207Smrg
635*4c3eb207Smrg return make_label_text (can_colorize,
636*4c3eb207Smrg "calling %qE from %qE",
637*4c3eb207Smrg m_sedge->m_dest->m_fun->decl,
638*4c3eb207Smrg m_sedge->m_src->m_fun->decl);
639*4c3eb207Smrg }
640*4c3eb207Smrg
641*4c3eb207Smrg /* Override of checker_event::is_call_p for calls. */
642*4c3eb207Smrg
643*4c3eb207Smrg bool
is_call_p() const644*4c3eb207Smrg call_event::is_call_p () const
645*4c3eb207Smrg {
646*4c3eb207Smrg return true;
647*4c3eb207Smrg }
648*4c3eb207Smrg
649*4c3eb207Smrg /* class return_event : public superedge_event. */
650*4c3eb207Smrg
651*4c3eb207Smrg /* return_event's ctor. */
652*4c3eb207Smrg
return_event(const exploded_edge & eedge,location_t loc,tree fndecl,int depth)653*4c3eb207Smrg return_event::return_event (const exploded_edge &eedge,
654*4c3eb207Smrg location_t loc, tree fndecl, int depth)
655*4c3eb207Smrg : superedge_event (EK_RETURN_EDGE, eedge, loc, fndecl, depth)
656*4c3eb207Smrg {
657*4c3eb207Smrg gcc_assert (eedge.m_sedge->m_kind == SUPEREDGE_RETURN);
658*4c3eb207Smrg }
659*4c3eb207Smrg
660*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
661*4c3eb207Smrg return_event.
662*4c3eb207Smrg
663*4c3eb207Smrg If this return event returns critical state for an sm-based warning,
664*4c3eb207Smrg allow the diagnostic to generate a precise description, such as:
665*4c3eb207Smrg
666*4c3eb207Smrg "possible of NULL to 'foo' from 'bar'"
667*4c3eb207Smrg
668*4c3eb207Smrg Otherwise, generate a description of the form
669*4c3eb207Smrg "returning to 'foo' from 'bar'. */
670*4c3eb207Smrg
671*4c3eb207Smrg label_text
get_desc(bool can_colorize) const672*4c3eb207Smrg return_event::get_desc (bool can_colorize) const
673*4c3eb207Smrg {
674*4c3eb207Smrg /* For greatest precision-of-wording, if this is returning the
675*4c3eb207Smrg state involved in the pending diagnostic, give the pending
676*4c3eb207Smrg diagnostic a chance to describe this return (in terms of
677*4c3eb207Smrg itself). */
678*4c3eb207Smrg if (m_critical_state && m_pending_diagnostic)
679*4c3eb207Smrg {
680*4c3eb207Smrg label_text custom_desc
681*4c3eb207Smrg = m_pending_diagnostic->describe_return_of_state
682*4c3eb207Smrg (evdesc::return_of_state (can_colorize,
683*4c3eb207Smrg m_sedge->m_dest->m_fun->decl,
684*4c3eb207Smrg m_sedge->m_src->m_fun->decl,
685*4c3eb207Smrg m_critical_state));
686*4c3eb207Smrg if (custom_desc.m_buffer)
687*4c3eb207Smrg return custom_desc;
688*4c3eb207Smrg }
689*4c3eb207Smrg return make_label_text (can_colorize,
690*4c3eb207Smrg "returning to %qE from %qE",
691*4c3eb207Smrg m_sedge->m_dest->m_fun->decl,
692*4c3eb207Smrg m_sedge->m_src->m_fun->decl);
693*4c3eb207Smrg }
694*4c3eb207Smrg
695*4c3eb207Smrg /* Override of checker_event::is_return_p for returns. */
696*4c3eb207Smrg
697*4c3eb207Smrg bool
is_return_p() const698*4c3eb207Smrg return_event::is_return_p () const
699*4c3eb207Smrg {
700*4c3eb207Smrg return true;
701*4c3eb207Smrg }
702*4c3eb207Smrg
703*4c3eb207Smrg /* class setjmp_event : public checker_event. */
704*4c3eb207Smrg
705*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
706*4c3eb207Smrg setjmp_event. */
707*4c3eb207Smrg
708*4c3eb207Smrg label_text
get_desc(bool can_colorize) const709*4c3eb207Smrg setjmp_event::get_desc (bool can_colorize) const
710*4c3eb207Smrg {
711*4c3eb207Smrg return make_label_text (can_colorize,
712*4c3eb207Smrg "%qs called here",
713*4c3eb207Smrg get_user_facing_name (m_setjmp_call));
714*4c3eb207Smrg }
715*4c3eb207Smrg
716*4c3eb207Smrg /* Implementation of checker_event::prepare_for_emission vfunc for setjmp_event.
717*4c3eb207Smrg
718*4c3eb207Smrg Record this setjmp's event ID into the path, so that rewind events can
719*4c3eb207Smrg use it. */
720*4c3eb207Smrg
721*4c3eb207Smrg void
prepare_for_emission(checker_path * path,pending_diagnostic * pd,diagnostic_event_id_t emission_id)722*4c3eb207Smrg setjmp_event::prepare_for_emission (checker_path *path,
723*4c3eb207Smrg pending_diagnostic *pd,
724*4c3eb207Smrg diagnostic_event_id_t emission_id)
725*4c3eb207Smrg {
726*4c3eb207Smrg checker_event::prepare_for_emission (path, pd, emission_id);
727*4c3eb207Smrg path->record_setjmp_event (m_enode, emission_id);
728*4c3eb207Smrg }
729*4c3eb207Smrg
730*4c3eb207Smrg /* class rewind_event : public checker_event. */
731*4c3eb207Smrg
732*4c3eb207Smrg /* Get the fndecl containing the site of the longjmp call. */
733*4c3eb207Smrg
734*4c3eb207Smrg tree
get_longjmp_caller() const735*4c3eb207Smrg rewind_event::get_longjmp_caller () const
736*4c3eb207Smrg {
737*4c3eb207Smrg return m_eedge->m_src->get_function ()->decl;
738*4c3eb207Smrg }
739*4c3eb207Smrg
740*4c3eb207Smrg /* Get the fndecl containing the site of the setjmp call. */
741*4c3eb207Smrg
742*4c3eb207Smrg tree
get_setjmp_caller() const743*4c3eb207Smrg rewind_event::get_setjmp_caller () const
744*4c3eb207Smrg {
745*4c3eb207Smrg return m_eedge->m_dest->get_function ()->decl;
746*4c3eb207Smrg }
747*4c3eb207Smrg
748*4c3eb207Smrg /* rewind_event's ctor. */
749*4c3eb207Smrg
rewind_event(const exploded_edge * eedge,enum event_kind kind,location_t loc,tree fndecl,int depth,const rewind_info_t * rewind_info)750*4c3eb207Smrg rewind_event::rewind_event (const exploded_edge *eedge,
751*4c3eb207Smrg enum event_kind kind,
752*4c3eb207Smrg location_t loc, tree fndecl, int depth,
753*4c3eb207Smrg const rewind_info_t *rewind_info)
754*4c3eb207Smrg : checker_event (kind, loc, fndecl, depth),
755*4c3eb207Smrg m_rewind_info (rewind_info),
756*4c3eb207Smrg m_eedge (eedge)
757*4c3eb207Smrg {
758*4c3eb207Smrg gcc_assert (m_eedge->m_custom_info == m_rewind_info);
759*4c3eb207Smrg }
760*4c3eb207Smrg
761*4c3eb207Smrg /* class rewind_from_longjmp_event : public rewind_event. */
762*4c3eb207Smrg
763*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
764*4c3eb207Smrg rewind_from_longjmp_event. */
765*4c3eb207Smrg
766*4c3eb207Smrg label_text
get_desc(bool can_colorize) const767*4c3eb207Smrg rewind_from_longjmp_event::get_desc (bool can_colorize) const
768*4c3eb207Smrg {
769*4c3eb207Smrg const char *src_name
770*4c3eb207Smrg = get_user_facing_name (m_rewind_info->get_longjmp_call ());
771*4c3eb207Smrg
772*4c3eb207Smrg if (get_longjmp_caller () == get_setjmp_caller ())
773*4c3eb207Smrg /* Special-case: purely intraprocedural rewind. */
774*4c3eb207Smrg return make_label_text (can_colorize,
775*4c3eb207Smrg "rewinding within %qE from %qs...",
776*4c3eb207Smrg get_longjmp_caller (),
777*4c3eb207Smrg src_name);
778*4c3eb207Smrg else
779*4c3eb207Smrg return make_label_text (can_colorize,
780*4c3eb207Smrg "rewinding from %qs in %qE...",
781*4c3eb207Smrg src_name,
782*4c3eb207Smrg get_longjmp_caller ());
783*4c3eb207Smrg }
784*4c3eb207Smrg
785*4c3eb207Smrg /* class rewind_to_setjmp_event : public rewind_event. */
786*4c3eb207Smrg
787*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
788*4c3eb207Smrg rewind_to_setjmp_event. */
789*4c3eb207Smrg
790*4c3eb207Smrg label_text
get_desc(bool can_colorize) const791*4c3eb207Smrg rewind_to_setjmp_event::get_desc (bool can_colorize) const
792*4c3eb207Smrg {
793*4c3eb207Smrg const char *dst_name
794*4c3eb207Smrg = get_user_facing_name (m_rewind_info->get_setjmp_call ());
795*4c3eb207Smrg
796*4c3eb207Smrg /* If we can, identify the ID of the setjmp_event. */
797*4c3eb207Smrg if (m_original_setjmp_event_id.known_p ())
798*4c3eb207Smrg {
799*4c3eb207Smrg if (get_longjmp_caller () == get_setjmp_caller ())
800*4c3eb207Smrg /* Special-case: purely intraprocedural rewind. */
801*4c3eb207Smrg return make_label_text (can_colorize,
802*4c3eb207Smrg "...to %qs (saved at %@)",
803*4c3eb207Smrg dst_name,
804*4c3eb207Smrg &m_original_setjmp_event_id);
805*4c3eb207Smrg else
806*4c3eb207Smrg return make_label_text (can_colorize,
807*4c3eb207Smrg "...to %qs in %qE (saved at %@)",
808*4c3eb207Smrg dst_name,
809*4c3eb207Smrg get_setjmp_caller (),
810*4c3eb207Smrg &m_original_setjmp_event_id);
811*4c3eb207Smrg }
812*4c3eb207Smrg else
813*4c3eb207Smrg {
814*4c3eb207Smrg if (get_longjmp_caller () == get_setjmp_caller ())
815*4c3eb207Smrg /* Special-case: purely intraprocedural rewind. */
816*4c3eb207Smrg return make_label_text (can_colorize,
817*4c3eb207Smrg "...to %qs",
818*4c3eb207Smrg dst_name,
819*4c3eb207Smrg get_setjmp_caller ());
820*4c3eb207Smrg else
821*4c3eb207Smrg return make_label_text (can_colorize,
822*4c3eb207Smrg "...to %qs in %qE",
823*4c3eb207Smrg dst_name,
824*4c3eb207Smrg get_setjmp_caller ());
825*4c3eb207Smrg }
826*4c3eb207Smrg }
827*4c3eb207Smrg
828*4c3eb207Smrg /* Implementation of checker_event::prepare_for_emission vfunc for
829*4c3eb207Smrg rewind_to_setjmp_event.
830*4c3eb207Smrg
831*4c3eb207Smrg Attempt to look up the setjmp event ID that recorded the jmp_buf
832*4c3eb207Smrg for this rewind. */
833*4c3eb207Smrg
834*4c3eb207Smrg void
prepare_for_emission(checker_path * path,pending_diagnostic * pd,diagnostic_event_id_t emission_id)835*4c3eb207Smrg rewind_to_setjmp_event::prepare_for_emission (checker_path *path,
836*4c3eb207Smrg pending_diagnostic *pd,
837*4c3eb207Smrg diagnostic_event_id_t emission_id)
838*4c3eb207Smrg {
839*4c3eb207Smrg checker_event::prepare_for_emission (path, pd, emission_id);
840*4c3eb207Smrg path->get_setjmp_event (m_rewind_info->get_enode_origin (),
841*4c3eb207Smrg &m_original_setjmp_event_id);
842*4c3eb207Smrg }
843*4c3eb207Smrg
844*4c3eb207Smrg /* class warning_event : public checker_event. */
845*4c3eb207Smrg
846*4c3eb207Smrg /* Implementation of diagnostic_event::get_desc vfunc for
847*4c3eb207Smrg warning_event.
848*4c3eb207Smrg
849*4c3eb207Smrg If the pending diagnostic implements describe_final_event, use it,
850*4c3eb207Smrg generating a precise description e.g.
851*4c3eb207Smrg "second 'free' here; first 'free' was at (7)"
852*4c3eb207Smrg
853*4c3eb207Smrg Otherwise generate a generic description. */
854*4c3eb207Smrg
855*4c3eb207Smrg label_text
get_desc(bool can_colorize) const856*4c3eb207Smrg warning_event::get_desc (bool can_colorize) const
857*4c3eb207Smrg {
858*4c3eb207Smrg if (m_pending_diagnostic)
859*4c3eb207Smrg {
860*4c3eb207Smrg label_text ev_desc
861*4c3eb207Smrg = m_pending_diagnostic->describe_final_event
862*4c3eb207Smrg (evdesc::final_event (can_colorize, m_var, m_state));
863*4c3eb207Smrg if (ev_desc.m_buffer)
864*4c3eb207Smrg {
865*4c3eb207Smrg if (m_sm && flag_analyzer_verbose_state_changes)
866*4c3eb207Smrg {
867*4c3eb207Smrg label_text result
868*4c3eb207Smrg = make_label_text (can_colorize,
869*4c3eb207Smrg "%s (%qE is in state %qs)",
870*4c3eb207Smrg ev_desc.m_buffer,
871*4c3eb207Smrg m_var,m_sm->get_state_name (m_state));
872*4c3eb207Smrg ev_desc.maybe_free ();
873*4c3eb207Smrg return result;
874*4c3eb207Smrg }
875*4c3eb207Smrg else
876*4c3eb207Smrg return ev_desc;
877*4c3eb207Smrg }
878*4c3eb207Smrg }
879*4c3eb207Smrg
880*4c3eb207Smrg if (m_sm)
881*4c3eb207Smrg return make_label_text (can_colorize,
882*4c3eb207Smrg "here (%qE is in state %qs)",
883*4c3eb207Smrg m_var,
884*4c3eb207Smrg m_sm->get_state_name (m_state));
885*4c3eb207Smrg else
886*4c3eb207Smrg return label_text::borrow ("here");
887*4c3eb207Smrg }
888*4c3eb207Smrg
889*4c3eb207Smrg /* Print a single-line representation of this path to PP. */
890*4c3eb207Smrg
891*4c3eb207Smrg void
dump(pretty_printer * pp) const892*4c3eb207Smrg checker_path::dump (pretty_printer *pp) const
893*4c3eb207Smrg {
894*4c3eb207Smrg pp_character (pp, '[');
895*4c3eb207Smrg
896*4c3eb207Smrg checker_event *e;
897*4c3eb207Smrg int i;
898*4c3eb207Smrg FOR_EACH_VEC_ELT (m_events, i, e)
899*4c3eb207Smrg {
900*4c3eb207Smrg if (i > 0)
901*4c3eb207Smrg pp_string (pp, ", ");
902*4c3eb207Smrg label_text event_desc (e->get_desc (false));
903*4c3eb207Smrg pp_printf (pp, "\"%s\"", event_desc.m_buffer);
904*4c3eb207Smrg event_desc.maybe_free ();
905*4c3eb207Smrg }
906*4c3eb207Smrg pp_character (pp, ']');
907*4c3eb207Smrg }
908*4c3eb207Smrg
909*4c3eb207Smrg /* Print a multiline form of this path to LOGGER, prefixing it with DESC. */
910*4c3eb207Smrg
911*4c3eb207Smrg void
maybe_log(logger * logger,const char * desc) const912*4c3eb207Smrg checker_path::maybe_log (logger *logger, const char *desc) const
913*4c3eb207Smrg {
914*4c3eb207Smrg if (!logger)
915*4c3eb207Smrg return;
916*4c3eb207Smrg logger->start_log_line ();
917*4c3eb207Smrg logger->log_partial ("%s: ", desc);
918*4c3eb207Smrg dump (logger->get_printer ());
919*4c3eb207Smrg logger->end_log_line ();
920*4c3eb207Smrg for (unsigned i = 0; i < m_events.length (); i++)
921*4c3eb207Smrg {
922*4c3eb207Smrg logger->start_log_line ();
923*4c3eb207Smrg logger->log_partial ("%s[%i]: %s ", desc, i,
924*4c3eb207Smrg event_kind_to_string (m_events[i]->m_kind));
925*4c3eb207Smrg m_events[i]->dump (logger->get_printer ());
926*4c3eb207Smrg logger->end_log_line ();
927*4c3eb207Smrg }
928*4c3eb207Smrg }
929*4c3eb207Smrg
930*4c3eb207Smrg /* Print a multiline form of this path to STDERR. */
931*4c3eb207Smrg
932*4c3eb207Smrg DEBUG_FUNCTION void
debug() const933*4c3eb207Smrg checker_path::debug () const
934*4c3eb207Smrg {
935*4c3eb207Smrg checker_event *e;
936*4c3eb207Smrg int i;
937*4c3eb207Smrg FOR_EACH_VEC_ELT (m_events, i, e)
938*4c3eb207Smrg {
939*4c3eb207Smrg label_text event_desc (e->get_desc (false));
940*4c3eb207Smrg fprintf (stderr,
941*4c3eb207Smrg "[%i]: %s \"%s\"\n",
942*4c3eb207Smrg i,
943*4c3eb207Smrg event_kind_to_string (m_events[i]->m_kind),
944*4c3eb207Smrg event_desc.m_buffer);
945*4c3eb207Smrg event_desc.maybe_free ();
946*4c3eb207Smrg }
947*4c3eb207Smrg }
948*4c3eb207Smrg
949*4c3eb207Smrg /* Add a warning_event to the end of this path. */
950*4c3eb207Smrg
951*4c3eb207Smrg void
add_final_event(const state_machine * sm,const exploded_node * enode,const gimple * stmt,tree var,state_machine::state_t state)952*4c3eb207Smrg checker_path::add_final_event (const state_machine *sm,
953*4c3eb207Smrg const exploded_node *enode, const gimple *stmt,
954*4c3eb207Smrg tree var, state_machine::state_t state)
955*4c3eb207Smrg {
956*4c3eb207Smrg checker_event *end_of_path
957*4c3eb207Smrg = new warning_event (stmt->location,
958*4c3eb207Smrg enode->get_function ()->decl,
959*4c3eb207Smrg enode->get_stack_depth (),
960*4c3eb207Smrg sm, var, state);
961*4c3eb207Smrg add_event (end_of_path);
962*4c3eb207Smrg }
963*4c3eb207Smrg
964*4c3eb207Smrg } // namespace ana
965*4c3eb207Smrg
966*4c3eb207Smrg #endif /* #if ENABLE_ANALYZER */
967