]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/checker-path.h
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / checker-path.h
CommitLineData
757bf1df 1/* Subclasses of diagnostic_path and diagnostic_event for analyzer diagnostics.
7adcbafe 2 Copyright (C) 2019-2022 Free Software Foundation, Inc.
757bf1df
DM
3 Contributed by David Malcolm <dmalcolm@redhat.com>.
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it
8under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 3, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
21#ifndef GCC_ANALYZER_CHECKER_PATH_H
22#define GCC_ANALYZER_CHECKER_PATH_H
23
75038aa6
DM
24namespace ana {
25
757bf1df
DM
26/* An enum for discriminating between the concrete subclasses of
27 checker_event. */
28
29enum event_kind
30{
31 EK_DEBUG,
32 EK_CUSTOM,
33 EK_STMT,
34 EK_FUNCTION_ENTRY,
35 EK_STATE_CHANGE,
36 EK_START_CFG_EDGE,
37 EK_END_CFG_EDGE,
38 EK_CALL_EDGE,
39 EK_RETURN_EDGE,
eb06fdd4
DM
40 EK_START_CONSOLIDATED_CFG_EDGES,
41 EK_END_CONSOLIDATED_CFG_EDGES,
757bf1df
DM
42 EK_SETJMP,
43 EK_REWIND_FROM_LONGJMP,
44 EK_REWIND_TO_SETJMP,
45 EK_WARNING
46};
47
48extern const char *event_kind_to_string (enum event_kind ek);
49
50/* Event subclasses.
51
52 The class hierarchy looks like this (using indentation to show
53 inheritance, and with event_kinds shown for the concrete subclasses):
54
55 diagnostic_event
56 checker_event
57 debug_event (EK_DEBUG)
58 custom_event (EK_CUSTOM)
86606d2a 59 precanned_custom_event
757bf1df
DM
60 statement_event (EK_STMT)
61 function_entry_event (EK_FUNCTION_ENTRY)
62 state_change_event (EK_STATE_CHANGE)
63 superedge_event
64 cfg_edge_event
65 start_cfg_edge_event (EK_START_CFG_EDGE)
66 end_cfg_edge_event (EK_END_CFG_EDGE)
67 call_event (EK_CALL_EDGE)
68 return_edge (EK_RETURN_EDGE)
eb06fdd4
DM
69 start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
70 end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
757bf1df
DM
71 setjmp_event (EK_SETJMP)
72 rewind_event
73 rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
74 rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
75 warning_event (EK_WARNING). */
76
77/* Abstract subclass of diagnostic_event; the base class for use in
78 checker_path (the analyzer's diagnostic_path subclass). */
79
80class checker_event : public diagnostic_event
81{
82public:
83 checker_event (enum event_kind kind,
84 location_t loc, tree fndecl, int depth)
85 : m_kind (kind), m_loc (loc), m_fndecl (fndecl), m_depth (depth),
86 m_pending_diagnostic (NULL), m_emission_id ()
87 {
88 }
89
90 /* Implementation of diagnostic_event. */
91
92 location_t get_location () const FINAL OVERRIDE { return m_loc; }
93 tree get_fndecl () const FINAL OVERRIDE { return m_fndecl; }
94 int get_stack_depth () const FINAL OVERRIDE { return m_depth; }
95
96 /* Additional functionality. */
97
757bf1df
DM
98 virtual void prepare_for_emission (checker_path *,
99 pending_diagnostic *pd,
100 diagnostic_event_id_t emission_id);
101 virtual bool is_call_p () const { return false; }
102 virtual bool is_function_entry_p () const { return false; }
103 virtual bool is_return_p () const { return false; }
104
8069928d
DM
105 /* For use with %@. */
106 const diagnostic_event_id_t *get_id_ptr () const
107 {
108 return &m_emission_id;
109 }
110
757bf1df
DM
111 void dump (pretty_printer *pp) const;
112
66dde7bc
DM
113 void set_location (location_t loc) { m_loc = loc; }
114
757bf1df
DM
115 public:
116 const enum event_kind m_kind;
117 protected:
118 location_t m_loc;
119 tree m_fndecl;
120 int m_depth;
121 pending_diagnostic *m_pending_diagnostic;
122 diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
123};
124
125/* A concrete event subclass for a purely textual event, for use in
126 debugging path creation and filtering. */
127
128class debug_event : public checker_event
129{
130public:
131 debug_event (location_t loc, tree fndecl, int depth,
132 const char *desc)
133 : checker_event (EK_DEBUG, loc, fndecl, depth),
134 m_desc (xstrdup (desc))
135 {
136 }
137 ~debug_event ()
138 {
139 free (m_desc);
140 }
141
142 label_text get_desc (bool) const FINAL OVERRIDE;
143
757bf1df
DM
144private:
145 char *m_desc;
146};
147
86606d2a 148/* An abstract event subclass for custom events. These are not filtered,
757bf1df
DM
149 as they are likely to be pertinent to the diagnostic. */
150
151class custom_event : public checker_event
152{
86606d2a
DM
153protected:
154 custom_event (location_t loc, tree fndecl, int depth)
155 : checker_event (EK_CUSTOM, loc, fndecl, depth)
156 {
157 }
158};
159
160/* A concrete custom_event subclass with a precanned message. */
161
162class precanned_custom_event : public custom_event
163{
757bf1df 164public:
86606d2a
DM
165 precanned_custom_event (location_t loc, tree fndecl, int depth,
166 const char *desc)
167 : custom_event (loc, fndecl, depth),
757bf1df
DM
168 m_desc (xstrdup (desc))
169 {
170 }
86606d2a 171 ~precanned_custom_event ()
757bf1df
DM
172 {
173 free (m_desc);
174 }
175
176 label_text get_desc (bool) const FINAL OVERRIDE;
177
757bf1df
DM
178private:
179 char *m_desc;
180};
181
182/* A concrete event subclass describing the execution of a gimple statement,
183 for use at high verbosity levels when debugging paths. */
184
185class statement_event : public checker_event
186{
187public:
188 statement_event (const gimple *stmt, tree fndecl, int depth,
189 const program_state &dst_state);
190
191 label_text get_desc (bool) const FINAL OVERRIDE;
192
757bf1df
DM
193 const gimple * const m_stmt;
194 const program_state m_dst_state;
195};
196
197/* An event subclass describing the entry to a function. */
198
199class function_entry_event : public checker_event
200{
201public:
202 function_entry_event (location_t loc, tree fndecl, int depth)
203 : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
204 {
205 }
206
207 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
208
757bf1df
DM
209 bool is_function_entry_p () const FINAL OVERRIDE { return true; }
210};
211
212/* Subclass of checker_event describing a state change. */
213
214class state_change_event : public checker_event
215{
216public:
217 state_change_event (const supernode *node, const gimple *stmt,
218 int stack_depth,
219 const state_machine &sm,
808f4dfe 220 const svalue *sval,
757bf1df
DM
221 state_machine::state_t from,
222 state_machine::state_t to,
808f4dfe 223 const svalue *origin,
757bf1df
DM
224 const program_state &dst_state);
225
226 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
227
808f4dfe 228 function *get_dest_function () const
757bf1df 229 {
808f4dfe 230 return m_dst_state.get_current_function ();
757bf1df
DM
231 }
232
233 const supernode *m_node;
234 const gimple *m_stmt;
235 const state_machine &m_sm;
808f4dfe 236 const svalue *m_sval;
757bf1df
DM
237 state_machine::state_t m_from;
238 state_machine::state_t m_to;
808f4dfe 239 const svalue *m_origin;
757bf1df
DM
240 program_state m_dst_state;
241};
242
243/* Subclass of checker_event; parent class for subclasses that relate to
244 a superedge. */
245
246class superedge_event : public checker_event
247{
248public:
249 /* Mark this edge event as being either an interprocedural call or
250 return in which VAR is in STATE, and that this is critical to the
251 diagnostic (so that get_desc can attempt to get a better description
252 from any pending_diagnostic). */
253 void record_critical_state (tree var, state_machine::state_t state)
254 {
255 m_var = var;
256 m_critical_state = state;
257 }
258
259 const callgraph_superedge& get_callgraph_superedge () const;
260
261 bool should_filter_p (int verbosity) const;
262
263 protected:
264 superedge_event (enum event_kind kind, const exploded_edge &eedge,
265 location_t loc, tree fndecl, int depth);
266
267 public:
268 const exploded_edge &m_eedge;
269 const superedge *m_sedge;
270 tree m_var;
271 state_machine::state_t m_critical_state;
272};
273
274/* An abstract event subclass for when a CFG edge is followed; it has two
275 subclasses, representing the start of the edge and the end of the
276 edge, which come in pairs. */
277
278class cfg_edge_event : public superedge_event
279{
280public:
281 const cfg_superedge& get_cfg_superedge () const;
282
283 protected:
284 cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
285 location_t loc, tree fndecl, int depth);
286};
287
288/* A concrete event subclass for the start of a CFG edge
289 e.g. "following 'false' branch...'. */
290
291class start_cfg_edge_event : public cfg_edge_event
292{
293public:
294 start_cfg_edge_event (const exploded_edge &eedge,
295 location_t loc, tree fndecl, int depth)
296 : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc, fndecl, depth)
297 {
298 }
299
300 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
301
757bf1df
DM
302 private:
303 label_text maybe_describe_condition (bool can_colorize) const;
304
305 static label_text maybe_describe_condition (bool can_colorize,
306 tree lhs,
307 enum tree_code op,
308 tree rhs);
309 static bool should_print_expr_p (tree);
310};
311
312/* A concrete event subclass for the end of a CFG edge
313 e.g. "...to here'. */
314
315class end_cfg_edge_event : public cfg_edge_event
316{
317public:
318 end_cfg_edge_event (const exploded_edge &eedge,
319 location_t loc, tree fndecl, int depth)
320 : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc, fndecl, depth)
321 {
322 }
323
324 label_text get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
325 {
326 return label_text::borrow ("...to here");
327 }
757bf1df
DM
328};
329
330/* A concrete event subclass for an interprocedural call. */
331
332class call_event : public superedge_event
333{
334public:
335 call_event (const exploded_edge &eedge,
336 location_t loc, tree fndecl, int depth);
337
338 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
339
757bf1df 340 bool is_call_p () const FINAL OVERRIDE;
aef703cf
AS
341
342 const supernode *m_src_snode;
343 const supernode *m_dest_snode;
757bf1df
DM
344};
345
346/* A concrete event subclass for an interprocedural return. */
347
348class return_event : public superedge_event
349{
350public:
351 return_event (const exploded_edge &eedge,
352 location_t loc, tree fndecl, int depth);
353
354 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
355
757bf1df 356 bool is_return_p () const FINAL OVERRIDE;
aef703cf
AS
357
358 const supernode *m_src_snode;
359 const supernode *m_dest_snode;
757bf1df
DM
360};
361
eb06fdd4
DM
362/* A concrete event subclass for the start of a consolidated run of CFG
363 edges all either TRUE or FALSE e.g. "following 'false' branch...'. */
364
365class start_consolidated_cfg_edges_event : public checker_event
366{
367public:
368 start_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth,
369 bool edge_sense)
370 : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth),
371 m_edge_sense (edge_sense)
372 {
373 }
374
375 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
376
377 private:
378 bool m_edge_sense;
379};
380
381/* A concrete event subclass for the end of a consolidated run of
382 CFG edges e.g. "...to here'. */
383
384class end_consolidated_cfg_edges_event : public checker_event
385{
386public:
387 end_consolidated_cfg_edges_event (location_t loc, tree fndecl, int depth)
388 : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc, fndecl, depth)
389 {
390 }
391
392 label_text get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
393 {
394 return label_text::borrow ("...to here");
395 }
396};
397
342e14ff 398/* A concrete event subclass for a setjmp or sigsetjmp call. */
757bf1df
DM
399
400class setjmp_event : public checker_event
401{
402public:
403 setjmp_event (location_t loc, const exploded_node *enode,
342e14ff 404 tree fndecl, int depth, const gcall *setjmp_call)
757bf1df 405 : checker_event (EK_SETJMP, loc, fndecl, depth),
342e14ff 406 m_enode (enode), m_setjmp_call (setjmp_call)
757bf1df
DM
407 {
408 }
409
757bf1df
DM
410 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
411
412 void prepare_for_emission (checker_path *path,
413 pending_diagnostic *pd,
414 diagnostic_event_id_t emission_id) FINAL OVERRIDE;
415
416private:
417 const exploded_node *m_enode;
342e14ff 418 const gcall *m_setjmp_call;
757bf1df
DM
419};
420
342e14ff
DM
421/* An abstract event subclass for rewinding from a longjmp to a setjmp
422 (or siglongjmp to sigsetjmp).
423
757bf1df
DM
424 Base class for two from/to subclasses, showing the two halves of the
425 rewind. */
426
427class rewind_event : public checker_event
428{
429public:
430 tree get_longjmp_caller () const;
431 tree get_setjmp_caller () const;
432 const exploded_edge *get_eedge () const { return m_eedge; }
433
434 protected:
435 rewind_event (const exploded_edge *eedge,
436 enum event_kind kind,
342e14ff
DM
437 location_t loc, tree fndecl, int depth,
438 const rewind_info_t *rewind_info);
439 const rewind_info_t *m_rewind_info;
757bf1df
DM
440
441 private:
442 const exploded_edge *m_eedge;
443};
444
445/* A concrete event subclass for rewinding from a longjmp to a setjmp,
342e14ff 446 showing the longjmp (or siglongjmp). */
757bf1df
DM
447
448class rewind_from_longjmp_event : public rewind_event
449{
450public:
451 rewind_from_longjmp_event (const exploded_edge *eedge,
342e14ff
DM
452 location_t loc, tree fndecl, int depth,
453 const rewind_info_t *rewind_info)
454 : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc, fndecl, depth,
455 rewind_info)
757bf1df
DM
456 {
457 }
458
459 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
757bf1df
DM
460};
461
462/* A concrete event subclass for rewinding from a longjmp to a setjmp,
342e14ff 463 showing the setjmp (or sigsetjmp). */
757bf1df
DM
464
465class rewind_to_setjmp_event : public rewind_event
466{
467public:
468 rewind_to_setjmp_event (const exploded_edge *eedge,
469 location_t loc, tree fndecl, int depth,
470 const rewind_info_t *rewind_info)
342e14ff
DM
471 : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc, fndecl, depth,
472 rewind_info)
757bf1df
DM
473 {
474 }
475
476 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
477
757bf1df
DM
478 void prepare_for_emission (checker_path *path,
479 pending_diagnostic *pd,
480 diagnostic_event_id_t emission_id) FINAL OVERRIDE;
481
482private:
483 diagnostic_event_id_t m_original_setjmp_event_id;
757bf1df
DM
484};
485
486/* Concrete subclass of checker_event for use at the end of a path:
487 a repeat of the warning message at the end of the path (perhaps with
488 references to pertinent events that occurred on the way), at the point
489 where the problem occurs. */
490
491class warning_event : public checker_event
492{
493public:
494 warning_event (location_t loc, tree fndecl, int depth,
495 const state_machine *sm,
496 tree var, state_machine::state_t state)
497 : checker_event (EK_WARNING, loc, fndecl, depth),
498 m_sm (sm), m_var (var), m_state (state)
499 {
500 }
501
502 label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
503
757bf1df
DM
504private:
505 const state_machine *m_sm;
506 tree m_var;
507 state_machine::state_t m_state;
508};
509
510/* Subclass of diagnostic_path for analyzer diagnostics. */
511
512class checker_path : public diagnostic_path
513{
514public:
515 checker_path () : diagnostic_path () {}
516
517 /* Implementation of diagnostic_path vfuncs. */
518
519 unsigned num_events () const FINAL OVERRIDE
520 {
521 return m_events.length ();
522 }
523
524 const diagnostic_event & get_event (int idx) const FINAL OVERRIDE
525 {
526 return *m_events[idx];
527 }
528
e2a538b1
DM
529 checker_event *get_checker_event (int idx)
530 {
531 return m_events[idx];
532 }
533
757bf1df
DM
534 void dump (pretty_printer *pp) const;
535 void debug () const;
536
537 void maybe_log (logger *logger, const char *desc) const;
538
539 void add_event (checker_event *event)
540 {
541 m_events.safe_push (event);
542 }
543
544 void delete_event (int idx)
545 {
546 checker_event *event = m_events[idx];
547 m_events.ordered_remove (idx);
548 delete event;
549 }
550
eb06fdd4
DM
551 void delete_events (unsigned start_idx, unsigned len)
552 {
553 for (unsigned i = start_idx; i < start_idx + len; i++)
554 delete m_events[i];
555 m_events.block_remove (start_idx, len);
556 }
557
558 void replace_event (unsigned idx, checker_event *new_event)
559 {
560 delete m_events[idx];
561 m_events[idx] = new_event;
562 }
563
757bf1df
DM
564 void add_final_event (const state_machine *sm,
565 const exploded_node *enode, const gimple *stmt,
566 tree var, state_machine::state_t state);
567
568 /* After all event-pruning, a hook for notifying each event what
569 its ID will be. The events are notified in order, allowing
570 for later events to refer to the IDs of earlier events in
571 their descriptions. */
572 void prepare_for_emission (pending_diagnostic *pd)
573 {
574 checker_event *e;
575 int i;
576 FOR_EACH_VEC_ELT (m_events, i, e)
577 e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
578 }
579
66dde7bc
DM
580 void fixup_locations (pending_diagnostic *pd);
581
757bf1df
DM
582 void record_setjmp_event (const exploded_node *enode,
583 diagnostic_event_id_t setjmp_emission_id)
584 {
585 m_setjmp_event_ids.put (enode, setjmp_emission_id);
586 }
587
588 bool get_setjmp_event (const exploded_node *enode,
589 diagnostic_event_id_t *out_emission_id)
590 {
591 if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
592 {
593 *out_emission_id = *emission_id;
594 return true;
595 }
596 return false;
597 }
598
eb06fdd4
DM
599 bool cfg_edge_pair_at_p (unsigned idx) const;
600
e2a538b1
DM
601private:
602 DISABLE_COPY_AND_ASSIGN(checker_path);
603
757bf1df
DM
604 /* The events that have occurred along this path. */
605 auto_delete_vec<checker_event> m_events;
606
607 /* During prepare_for_emission (and after), the setjmp_event for each
608 exploded_node *, so that rewind events can refer to them in their
609 descriptions. */
610 hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
611};
612
75038aa6
DM
613} // namespace ana
614
757bf1df 615#endif /* GCC_ANALYZER_CHECKER_PATH_H */