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