1 /* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
2 Copyright (C) 2019-2020 Free Software Foundation, Inc.
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3, or (at your option)
12 GCC is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_ANALYZER_CHECKER_PATH_H
22 #define GCC_ANALYZER_CHECKER_PATH_H
24 /* An enum for discriminating between the concrete subclasses of
39 EK_REWIND_FROM_LONGJMP
,
44 extern const char *event_kind_to_string (enum event_kind ek
);
48 The class hierarchy looks like this (using indentation to show
49 inheritance, and with event_kinds shown for the concrete subclasses):
53 debug_event (EK_DEBUG)
54 custom_event (EK_CUSTOM)
55 statement_event (EK_STMT)
56 function_entry_event (EK_FUNCTION_ENTRY)
57 state_change_event (EK_STATE_CHANGE)
60 start_cfg_edge_event (EK_START_CFG_EDGE)
61 end_cfg_edge_event (EK_END_CFG_EDGE)
62 call_event (EK_CALL_EDGE)
63 return_edge (EK_RETURN_EDGE)
64 setjmp_event (EK_SETJMP)
66 rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
67 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
68 warning_event (EK_WARNING). */
70 /* Abstract subclass of diagnostic_event; the base class for use in
71 checker_path (the analyzer's diagnostic_path subclass). */
73 class checker_event
: public diagnostic_event
76 checker_event (enum event_kind kind
,
77 location_t loc
, tree fndecl
, int depth
)
78 : m_kind (kind
), m_loc (loc
), m_fndecl (fndecl
), m_depth (depth
),
79 m_pending_diagnostic (NULL
), m_emission_id ()
83 /* Implementation of diagnostic_event. */
85 location_t
get_location () const FINAL OVERRIDE
{ return m_loc
; }
86 tree
get_fndecl () const FINAL OVERRIDE
{ return m_fndecl
; }
87 int get_stack_depth () const FINAL OVERRIDE
{ return m_depth
; }
89 /* Additional functionality. */
91 virtual void prepare_for_emission (checker_path
*,
92 pending_diagnostic
*pd
,
93 diagnostic_event_id_t emission_id
);
94 virtual bool is_call_p () const { return false; }
95 virtual bool is_function_entry_p () const { return false; }
96 virtual bool is_return_p () const { return false; }
98 void dump (pretty_printer
*pp
) const;
101 const enum event_kind m_kind
;
106 pending_diagnostic
*m_pending_diagnostic
;
107 diagnostic_event_id_t m_emission_id
; // only set once all pruning has occurred
110 /* A concrete event subclass for a purely textual event, for use in
111 debugging path creation and filtering. */
113 class debug_event
: public checker_event
116 debug_event (location_t loc
, tree fndecl
, int depth
,
118 : checker_event (EK_DEBUG
, loc
, fndecl
, depth
),
119 m_desc (xstrdup (desc
))
127 label_text
get_desc (bool) const FINAL OVERRIDE
;
133 /* A concrete event subclass for custom events. These are not filtered,
134 as they are likely to be pertinent to the diagnostic. */
136 class custom_event
: public checker_event
139 custom_event (location_t loc
, tree fndecl
, int depth
,
141 : checker_event (EK_CUSTOM
, loc
, fndecl
, depth
),
142 m_desc (xstrdup (desc
))
150 label_text
get_desc (bool) const FINAL OVERRIDE
;
156 /* A concrete event subclass describing the execution of a gimple statement,
157 for use at high verbosity levels when debugging paths. */
159 class statement_event
: public checker_event
162 statement_event (const gimple
*stmt
, tree fndecl
, int depth
,
163 const program_state
&dst_state
);
165 label_text
get_desc (bool) const FINAL OVERRIDE
;
167 const gimple
* const m_stmt
;
168 const program_state m_dst_state
;
171 /* An event subclass describing the entry to a function. */
173 class function_entry_event
: public checker_event
176 function_entry_event (location_t loc
, tree fndecl
, int depth
)
177 : checker_event (EK_FUNCTION_ENTRY
, loc
, fndecl
, depth
)
181 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
183 bool is_function_entry_p () const FINAL OVERRIDE
{ return true; }
186 /* Subclass of checker_event describing a state change. */
188 class state_change_event
: public checker_event
191 state_change_event (const supernode
*node
, const gimple
*stmt
,
193 const state_machine
&sm
,
195 state_machine::state_t from
,
196 state_machine::state_t to
,
198 const program_state
&dst_state
);
200 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
202 region_id
get_lvalue (tree expr
) const
204 return m_dst_state
.m_region_model
->get_lvalue (expr
, NULL
);
207 const supernode
*m_node
;
208 const gimple
*m_stmt
;
209 const state_machine
&m_sm
;
211 state_machine::state_t m_from
;
212 state_machine::state_t m_to
;
214 program_state m_dst_state
;
217 /* Subclass of checker_event; parent class for subclasses that relate to
220 class superedge_event
: public checker_event
223 /* Mark this edge event as being either an interprocedural call or
224 return in which VAR is in STATE, and that this is critical to the
225 diagnostic (so that get_desc can attempt to get a better description
226 from any pending_diagnostic). */
227 void record_critical_state (tree var
, state_machine::state_t state
)
230 m_critical_state
= state
;
233 const callgraph_superedge
& get_callgraph_superedge () const;
235 bool should_filter_p (int verbosity
) const;
238 superedge_event (enum event_kind kind
, const exploded_edge
&eedge
,
239 location_t loc
, tree fndecl
, int depth
);
242 const exploded_edge
&m_eedge
;
243 const superedge
*m_sedge
;
245 state_machine::state_t m_critical_state
;
248 /* An abstract event subclass for when a CFG edge is followed; it has two
249 subclasses, representing the start of the edge and the end of the
250 edge, which come in pairs. */
252 class cfg_edge_event
: public superedge_event
255 const cfg_superedge
& get_cfg_superedge () const;
258 cfg_edge_event (enum event_kind kind
, const exploded_edge
&eedge
,
259 location_t loc
, tree fndecl
, int depth
);
262 /* A concrete event subclass for the start of a CFG edge
263 e.g. "following 'false' branch...'. */
265 class start_cfg_edge_event
: public cfg_edge_event
268 start_cfg_edge_event (const exploded_edge
&eedge
,
269 location_t loc
, tree fndecl
, int depth
)
270 : cfg_edge_event (EK_START_CFG_EDGE
, eedge
, loc
, fndecl
, depth
)
274 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
277 label_text
maybe_describe_condition (bool can_colorize
) const;
279 static label_text
maybe_describe_condition (bool can_colorize
,
283 static bool should_print_expr_p (tree
);
286 /* A concrete event subclass for the end of a CFG edge
287 e.g. "...to here'. */
289 class end_cfg_edge_event
: public cfg_edge_event
292 end_cfg_edge_event (const exploded_edge
&eedge
,
293 location_t loc
, tree fndecl
, int depth
)
294 : cfg_edge_event (EK_END_CFG_EDGE
, eedge
, loc
, fndecl
, depth
)
298 label_text
get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
300 return label_text::borrow ("...to here");
304 /* A concrete event subclass for an interprocedural call. */
306 class call_event
: public superedge_event
309 call_event (const exploded_edge
&eedge
,
310 location_t loc
, tree fndecl
, int depth
);
312 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
314 bool is_call_p () const FINAL OVERRIDE
;
317 /* A concrete event subclass for an interprocedural return. */
319 class return_event
: public superedge_event
322 return_event (const exploded_edge
&eedge
,
323 location_t loc
, tree fndecl
, int depth
);
325 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
327 bool is_return_p () const FINAL OVERRIDE
;
330 /* A concrete event subclass for a setjmp call. */
332 class setjmp_event
: public checker_event
335 setjmp_event (location_t loc
, const exploded_node
*enode
,
336 tree fndecl
, int depth
)
337 : checker_event (EK_SETJMP
, loc
, fndecl
, depth
),
342 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
344 void prepare_for_emission (checker_path
*path
,
345 pending_diagnostic
*pd
,
346 diagnostic_event_id_t emission_id
) FINAL OVERRIDE
;
349 const exploded_node
*m_enode
;
352 /* An abstract event subclass for rewinding from a longjmp to a setjmp.
353 Base class for two from/to subclasses, showing the two halves of the
356 class rewind_event
: public checker_event
359 tree
get_longjmp_caller () const;
360 tree
get_setjmp_caller () const;
361 const exploded_edge
*get_eedge () const { return m_eedge
; }
364 rewind_event (const exploded_edge
*eedge
,
365 enum event_kind kind
,
366 location_t loc
, tree fndecl
, int depth
);
369 const exploded_edge
*m_eedge
;
372 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
373 showing the longjmp. */
375 class rewind_from_longjmp_event
: public rewind_event
378 rewind_from_longjmp_event (const exploded_edge
*eedge
,
379 location_t loc
, tree fndecl
, int depth
)
380 : rewind_event (eedge
, EK_REWIND_FROM_LONGJMP
, loc
, fndecl
, depth
)
384 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
387 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
388 showing the setjmp. */
390 class rewind_to_setjmp_event
: public rewind_event
393 rewind_to_setjmp_event (const exploded_edge
*eedge
,
394 location_t loc
, tree fndecl
, int depth
,
395 const rewind_info_t
*rewind_info
)
396 : rewind_event (eedge
, EK_REWIND_TO_SETJMP
, loc
, fndecl
, depth
),
397 m_rewind_info (rewind_info
)
401 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
403 void prepare_for_emission (checker_path
*path
,
404 pending_diagnostic
*pd
,
405 diagnostic_event_id_t emission_id
) FINAL OVERRIDE
;
408 diagnostic_event_id_t m_original_setjmp_event_id
;
409 const rewind_info_t
*m_rewind_info
;
412 /* Concrete subclass of checker_event for use at the end of a path:
413 a repeat of the warning message at the end of the path (perhaps with
414 references to pertinent events that occurred on the way), at the point
415 where the problem occurs. */
417 class warning_event
: public checker_event
420 warning_event (location_t loc
, tree fndecl
, int depth
,
421 const state_machine
*sm
,
422 tree var
, state_machine::state_t state
)
423 : checker_event (EK_WARNING
, loc
, fndecl
, depth
),
424 m_sm (sm
), m_var (var
), m_state (state
)
428 label_text
get_desc (bool can_colorize
) const FINAL OVERRIDE
;
431 const state_machine
*m_sm
;
433 state_machine::state_t m_state
;
436 /* Subclass of diagnostic_path for analyzer diagnostics. */
438 class checker_path
: public diagnostic_path
441 checker_path () : diagnostic_path () {}
443 /* Implementation of diagnostic_path vfuncs. */
445 unsigned num_events () const FINAL OVERRIDE
447 return m_events
.length ();
450 const diagnostic_event
& get_event (int idx
) const FINAL OVERRIDE
452 return *m_events
[idx
];
455 void dump (pretty_printer
*pp
) const;
458 void maybe_log (logger
*logger
, const char *desc
) const;
460 void add_event (checker_event
*event
)
462 m_events
.safe_push (event
);
465 void delete_event (int idx
)
467 checker_event
*event
= m_events
[idx
];
468 m_events
.ordered_remove (idx
);
472 void add_final_event (const state_machine
*sm
,
473 const exploded_node
*enode
, const gimple
*stmt
,
474 tree var
, state_machine::state_t state
);
476 /* After all event-pruning, a hook for notifying each event what
477 its ID will be. The events are notified in order, allowing
478 for later events to refer to the IDs of earlier events in
479 their descriptions. */
480 void prepare_for_emission (pending_diagnostic
*pd
)
484 FOR_EACH_VEC_ELT (m_events
, i
, e
)
485 e
->prepare_for_emission (this, pd
, diagnostic_event_id_t (i
));
488 void record_setjmp_event (const exploded_node
*enode
,
489 diagnostic_event_id_t setjmp_emission_id
)
491 m_setjmp_event_ids
.put (enode
, setjmp_emission_id
);
494 bool get_setjmp_event (const exploded_node
*enode
,
495 diagnostic_event_id_t
*out_emission_id
)
497 if (diagnostic_event_id_t
*emission_id
= m_setjmp_event_ids
.get (enode
))
499 *out_emission_id
= *emission_id
;
505 /* The events that have occurred along this path. */
506 auto_delete_vec
<checker_event
> m_events
;
508 /* During prepare_for_emission (and after), the setjmp_event for each
509 exploded_node *, so that rewind events can refer to them in their
511 hash_map
<const exploded_node
*, diagnostic_event_id_t
> m_setjmp_event_ids
;
514 #endif /* GCC_ANALYZER_CHECKER_PATH_H */