analyzer: introduce struct event_loc_info
[platform/upstream/gcc.git] / gcc / analyzer / checker-event.h
1 /* Subclasses of 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_EVENT_H
22 #define GCC_ANALYZER_CHECKER_EVENT_H
23
24 #include "tree-logical-location.h"
25 #include "analyzer/program-state.h"
26
27 namespace ana {
28
29 /* A bundle of location information for a checker_event.  */
30
31 struct event_loc_info
32 {
33   event_loc_info (location_t loc, tree fndecl, int depth)
34   : m_loc (loc), m_fndecl (fndecl), m_depth (depth)
35   {}
36
37   location_t m_loc;
38   tree m_fndecl;
39   int m_depth;
40 };
41
42 /* An enum for discriminating between the concrete subclasses of
43    checker_event.  */
44
45 enum event_kind
46 {
47   EK_DEBUG,
48   EK_CUSTOM,
49   EK_STMT,
50   EK_REGION_CREATION,
51   EK_FUNCTION_ENTRY,
52   EK_STATE_CHANGE,
53   EK_START_CFG_EDGE,
54   EK_END_CFG_EDGE,
55   EK_CALL_EDGE,
56   EK_RETURN_EDGE,
57   EK_START_CONSOLIDATED_CFG_EDGES,
58   EK_END_CONSOLIDATED_CFG_EDGES,
59   EK_INLINED_CALL,
60   EK_SETJMP,
61   EK_REWIND_FROM_LONGJMP,
62   EK_REWIND_TO_SETJMP,
63   EK_WARNING
64 };
65
66 extern const char *event_kind_to_string (enum event_kind ek);
67
68 /* Event subclasses.
69
70    The class hierarchy looks like this (using indentation to show
71    inheritance, and with event_kinds shown for the concrete subclasses):
72
73    diagnostic_event
74      checker_event
75        debug_event (EK_DEBUG)
76        custom_event (EK_CUSTOM)
77          precanned_custom_event
78        statement_event (EK_STMT)
79        region_creation_event (EK_REGION_CREATION)
80        function_entry_event (EK_FUNCTION_ENTRY)
81        state_change_event (EK_STATE_CHANGE)
82        superedge_event
83          cfg_edge_event
84            start_cfg_edge_event (EK_START_CFG_EDGE)
85            end_cfg_edge_event (EK_END_CFG_EDGE)
86          call_event (EK_CALL_EDGE)
87          return_edge (EK_RETURN_EDGE)
88        start_consolidated_cfg_edges_event (EK_START_CONSOLIDATED_CFG_EDGES)
89        end_consolidated_cfg_edges_event (EK_END_CONSOLIDATED_CFG_EDGES)
90        inlined_call_event (EK_INLINED_CALL)
91        setjmp_event (EK_SETJMP)
92        rewind_event
93          rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
94          rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
95        warning_event (EK_WARNING).  */
96
97 /* Abstract subclass of diagnostic_event; the base class for use in
98    checker_path (the analyzer's diagnostic_path subclass).  */
99
100 class checker_event : public diagnostic_event
101 {
102 public:
103   /* Implementation of diagnostic_event.  */
104
105   location_t get_location () const final override { return m_loc; }
106   tree get_fndecl () const final override { return m_effective_fndecl; }
107   int get_stack_depth () const final override { return m_effective_depth; }
108   const logical_location *get_logical_location () const final override
109   {
110     if (m_effective_fndecl)
111       return &m_logical_loc;
112     else
113       return NULL;
114   }
115   meaning get_meaning () const override;
116
117   /* Additional functionality.  */
118
119   int get_original_stack_depth () const { return m_original_depth; }
120
121   virtual void prepare_for_emission (checker_path *,
122                                      pending_diagnostic *pd,
123                                      diagnostic_event_id_t emission_id);
124   virtual bool is_call_p () const { return false; }
125   virtual bool is_function_entry_p () const  { return false; }
126   virtual bool is_return_p () const  { return false; }
127
128   /* For use with %@.  */
129   const diagnostic_event_id_t *get_id_ptr () const
130   {
131     return &m_emission_id;
132   }
133
134   void dump (pretty_printer *pp) const;
135   void debug () const;
136
137   void set_location (location_t loc) { m_loc = loc; }
138
139 protected:
140   checker_event (enum event_kind kind,
141                  const event_loc_info &loc_info);
142
143  public:
144   const enum event_kind m_kind;
145  protected:
146   location_t m_loc;
147   tree m_original_fndecl;
148   tree m_effective_fndecl;
149   int m_original_depth;
150   int m_effective_depth;
151   pending_diagnostic *m_pending_diagnostic;
152   diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
153   tree_logical_location m_logical_loc;
154 };
155
156 /* A concrete event subclass for a purely textual event, for use in
157    debugging path creation and filtering.  */
158
159 class debug_event : public checker_event
160 {
161 public:
162
163   debug_event (const event_loc_info &loc_info,
164                const char *desc)
165   : checker_event (EK_DEBUG, loc_info),
166     m_desc (xstrdup (desc))
167   {
168   }
169   ~debug_event ()
170   {
171     free (m_desc);
172   }
173
174   label_text get_desc (bool) const final override;
175
176 private:
177   char *m_desc;
178 };
179
180 /* An abstract event subclass for custom events.  These are not filtered,
181    as they are likely to be pertinent to the diagnostic.  */
182
183 class custom_event : public checker_event
184 {
185 protected:
186   custom_event (const event_loc_info &loc_info)
187   : checker_event (EK_CUSTOM, loc_info)
188   {
189   }
190 };
191
192 /* A concrete custom_event subclass with a precanned message.  */
193
194 class precanned_custom_event : public custom_event
195 {
196 public:
197   precanned_custom_event (const event_loc_info &loc_info,
198                           const char *desc)
199   : custom_event (loc_info),
200     m_desc (xstrdup (desc))
201   {
202   }
203   ~precanned_custom_event ()
204   {
205     free (m_desc);
206   }
207
208   label_text get_desc (bool) const final override;
209
210 private:
211   char *m_desc;
212 };
213
214 /* A concrete event subclass describing the execution of a gimple statement,
215    for use at high verbosity levels when debugging paths.  */
216
217 class statement_event : public checker_event
218 {
219 public:
220   statement_event (const gimple *stmt, tree fndecl, int depth,
221                    const program_state &dst_state);
222
223   label_text get_desc (bool) const final override;
224
225   const gimple * const m_stmt;
226   const program_state m_dst_state;
227 };
228
229 /* An abstract event subclass describing the creation of a region that
230    is significant for a diagnostic.
231
232    There are too many combinations to express region creation in one message,
233    so we emit multiple region_creation_event instances when each pertinent
234    region is created.
235
236    The events are created by pending_diagnostic's add_region_creation_events
237    vfunc, which by default creates a region_creation_event_memory_space, and
238    if a capacity is known, a region_creation_event_capacity, giving e.g.:
239      (1) region created on stack here
240      (2) capacity: 100 bytes
241    but this vfunc can be overridden to create other events if other wordings
242    are more appropriate foa a given pending_diagnostic.  */
243
244 class region_creation_event : public checker_event
245 {
246 protected:
247   region_creation_event (const event_loc_info &loc_info);
248 };
249
250 /* Concrete subclass of region_creation_event.
251    Generates a message based on the memory space of the region
252    e.g. "region created on stack here".  */
253
254 class region_creation_event_memory_space : public region_creation_event
255 {
256 public:
257   region_creation_event_memory_space (enum memory_space mem_space,
258                                       const event_loc_info &loc_info)
259   : region_creation_event (loc_info),
260     m_mem_space (mem_space)
261   {
262   }
263
264   label_text get_desc (bool can_colorize) const final override;
265
266 private:
267   enum memory_space m_mem_space;
268 };
269
270 /* Concrete subclass of region_creation_event.
271    Generates a message based on the capacity of the region
272    e.g. "capacity: 100 bytes".  */
273
274 class region_creation_event_capacity : public region_creation_event
275 {
276 public:
277   region_creation_event_capacity (tree capacity,
278                                   const event_loc_info &loc_info)
279   : region_creation_event (loc_info),
280     m_capacity (capacity)
281   {
282     gcc_assert (m_capacity);
283   }
284
285   label_text get_desc (bool can_colorize) const final override;
286
287 private:
288   tree m_capacity;
289 };
290
291 /* Concrete subclass of region_creation_event.
292    Generates a message based on the capacity of the region
293    e.g. "allocated 100 bytes here".  */
294
295 class region_creation_event_allocation_size : public region_creation_event
296 {
297 public:
298   region_creation_event_allocation_size (tree capacity,
299                                          const event_loc_info &loc_info)
300   : region_creation_event (loc_info),
301     m_capacity (capacity)
302   {}
303
304   label_text get_desc (bool can_colorize) const final override;
305
306 private:
307   tree m_capacity;
308 };
309
310 /* Concrete subclass of region_creation_event.
311    Generates a debug message intended for analyzer developers.  */
312
313 class region_creation_event_debug : public region_creation_event
314 {
315 public:
316   region_creation_event_debug (const region *reg, tree capacity,
317                                const event_loc_info &loc_info)
318   : region_creation_event (loc_info),
319     m_reg (reg), m_capacity (capacity)
320   {
321   }
322
323   label_text get_desc (bool can_colorize) const final override;
324
325 private:
326   const region *m_reg;
327   tree m_capacity;
328 };
329
330 /* An event subclass describing the entry to a function.  */
331
332 class function_entry_event : public checker_event
333 {
334 public:
335   function_entry_event (const event_loc_info &loc_info)
336   : checker_event (EK_FUNCTION_ENTRY, loc_info)
337   {
338   }
339
340   function_entry_event (const program_point &dst_point);
341
342   label_text get_desc (bool can_colorize) const override;
343   meaning get_meaning () const override;
344
345   bool is_function_entry_p () const final override { return true; }
346 };
347
348 /* Subclass of checker_event describing a state change.  */
349
350 class state_change_event : public checker_event
351 {
352 public:
353   state_change_event (const supernode *node, const gimple *stmt,
354                       int stack_depth,
355                       const state_machine &sm,
356                       const svalue *sval,
357                       state_machine::state_t from,
358                       state_machine::state_t to,
359                       const svalue *origin,
360                       const program_state &dst_state);
361
362   label_text get_desc (bool can_colorize) const final override;
363   meaning get_meaning () const override;
364
365   function *get_dest_function () const
366   {
367     return m_dst_state.get_current_function ();
368   }
369
370   const supernode *m_node;
371   const gimple *m_stmt;
372   const state_machine &m_sm;
373   const svalue *m_sval;
374   state_machine::state_t m_from;
375   state_machine::state_t m_to;
376   const svalue *m_origin;
377   program_state m_dst_state;
378 };
379
380 /* Subclass of checker_event; parent class for subclasses that relate to
381    a superedge.  */
382
383 class superedge_event : public checker_event
384 {
385 public:
386   /* Mark this edge event as being either an interprocedural call or
387      return in which VAR is in STATE, and that this is critical to the
388      diagnostic (so that get_desc can attempt to get a better description
389      from any pending_diagnostic).  */
390   void record_critical_state (tree var, state_machine::state_t state)
391   {
392     m_var = var;
393     m_critical_state = state;
394   }
395
396   const callgraph_superedge& get_callgraph_superedge () const;
397
398   bool should_filter_p (int verbosity) const;
399
400  protected:
401   superedge_event (enum event_kind kind, const exploded_edge &eedge,
402                    const event_loc_info &loc_info);
403
404  public:
405   const exploded_edge &m_eedge;
406   const superedge *m_sedge;
407   tree m_var;
408   state_machine::state_t m_critical_state;
409 };
410
411 /* An abstract event subclass for when a CFG edge is followed; it has two
412    subclasses, representing the start of the edge and the end of the
413    edge, which come in pairs.  */
414
415 class cfg_edge_event : public superedge_event
416 {
417 public:
418   meaning get_meaning () const override;
419
420   const cfg_superedge& get_cfg_superedge () const;
421
422  protected:
423   cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
424                   const event_loc_info &loc_info);
425 };
426
427 /* A concrete event subclass for the start of a CFG edge
428    e.g. "following 'false' branch...'.  */
429
430 class start_cfg_edge_event : public cfg_edge_event
431 {
432 public:
433   start_cfg_edge_event (const exploded_edge &eedge,
434                         const event_loc_info &loc_info)
435   : cfg_edge_event (EK_START_CFG_EDGE, eedge, loc_info)
436   {
437   }
438
439   label_text get_desc (bool can_colorize) const final override;
440
441  private:
442   label_text maybe_describe_condition (bool can_colorize) const;
443
444   static label_text maybe_describe_condition (bool can_colorize,
445                                               tree lhs,
446                                               enum tree_code op,
447                                               tree rhs);
448   static bool should_print_expr_p (tree);
449 };
450
451 /* A concrete event subclass for the end of a CFG edge
452    e.g. "...to here'.  */
453
454 class end_cfg_edge_event : public cfg_edge_event
455 {
456 public:
457   end_cfg_edge_event (const exploded_edge &eedge,
458                       const event_loc_info &loc_info)
459   : cfg_edge_event (EK_END_CFG_EDGE, eedge, loc_info)
460   {
461   }
462
463   label_text get_desc (bool /*can_colorize*/) const final override
464   {
465     return label_text::borrow ("...to here");
466   }
467 };
468
469 /* A concrete event subclass for an interprocedural call.  */
470
471 class call_event : public superedge_event
472 {
473 public:
474   call_event (const exploded_edge &eedge,
475               const event_loc_info &loc_info);
476
477   label_text get_desc (bool can_colorize) const override;
478   meaning get_meaning () const override;
479
480   bool is_call_p () const final override;
481
482 protected:
483   tree get_caller_fndecl () const;
484   tree get_callee_fndecl () const;
485
486   const supernode *m_src_snode;
487   const supernode *m_dest_snode;
488 };
489
490 /* A concrete event subclass for an interprocedural return.  */
491
492 class return_event : public superedge_event
493 {
494 public:
495   return_event (const exploded_edge &eedge,
496                 const event_loc_info &loc_info);
497
498   label_text get_desc (bool can_colorize) const final override;
499   meaning get_meaning () const override;
500
501   bool is_return_p () const final override;
502
503   const supernode *m_src_snode;
504   const supernode *m_dest_snode;
505 };
506
507 /* A concrete event subclass for the start of a consolidated run of CFG
508    edges all either TRUE or FALSE e.g. "following 'false' branch...'.  */
509
510 class start_consolidated_cfg_edges_event : public checker_event
511 {
512 public:
513   start_consolidated_cfg_edges_event (const event_loc_info &loc_info,
514                                       bool edge_sense)
515   : checker_event (EK_START_CONSOLIDATED_CFG_EDGES, loc_info),
516     m_edge_sense (edge_sense)
517   {
518   }
519
520   label_text get_desc (bool can_colorize) const final override;
521   meaning get_meaning () const override;
522
523  private:
524   bool m_edge_sense;
525 };
526
527 /* A concrete event subclass for the end of a consolidated run of
528    CFG edges e.g. "...to here'.  */
529
530 class end_consolidated_cfg_edges_event : public checker_event
531 {
532 public:
533   end_consolidated_cfg_edges_event (const event_loc_info &loc_info)
534   : checker_event (EK_END_CONSOLIDATED_CFG_EDGES, loc_info)
535   {
536   }
537
538   label_text get_desc (bool /*can_colorize*/) const final override
539   {
540     return label_text::borrow ("...to here");
541   }
542 };
543
544 /* A concrete event subclass for describing an inlined call event
545    e.g. "inlined call to 'callee' from 'caller'".  */
546
547 class inlined_call_event : public checker_event
548 {
549 public:
550   inlined_call_event (location_t loc,
551                       tree apparent_callee_fndecl,
552                       tree apparent_caller_fndecl,
553                       int actual_depth,
554                       int stack_depth_adjustment)
555   : checker_event (EK_INLINED_CALL,
556                    event_loc_info (loc,
557                                    apparent_caller_fndecl,
558                                    actual_depth + stack_depth_adjustment)),
559     m_apparent_callee_fndecl (apparent_callee_fndecl),
560     m_apparent_caller_fndecl (apparent_caller_fndecl)
561   {
562     gcc_assert (LOCATION_BLOCK (loc) == NULL);
563   }
564
565   label_text get_desc (bool /*can_colorize*/) const final override;
566   meaning get_meaning () const override;
567
568 private:
569   tree m_apparent_callee_fndecl;
570   tree m_apparent_caller_fndecl;
571 };
572
573 /* A concrete event subclass for a setjmp or sigsetjmp call.  */
574
575 class setjmp_event : public checker_event
576 {
577 public:
578   setjmp_event (const event_loc_info &loc_info,
579                 const exploded_node *enode,
580                 const gcall *setjmp_call)
581   : checker_event (EK_SETJMP, loc_info),
582     m_enode (enode), m_setjmp_call (setjmp_call)
583   {
584   }
585
586   label_text get_desc (bool can_colorize) const final override;
587
588   void prepare_for_emission (checker_path *path,
589                              pending_diagnostic *pd,
590                              diagnostic_event_id_t emission_id) final override;
591
592 private:
593   const exploded_node *m_enode;
594   const gcall *m_setjmp_call;
595 };
596
597 /* An abstract event subclass for rewinding from a longjmp to a setjmp
598    (or siglongjmp to sigsetjmp).
599
600    Base class for two from/to subclasses, showing the two halves of the
601    rewind.  */
602
603 class rewind_event : public checker_event
604 {
605 public:
606   tree get_longjmp_caller () const;
607   tree get_setjmp_caller () const;
608   const exploded_edge *get_eedge () const { return m_eedge; }
609
610  protected:
611   rewind_event (const exploded_edge *eedge,
612                 enum event_kind kind,
613                 const event_loc_info &loc_info,
614                 const rewind_info_t *rewind_info);
615   const rewind_info_t *m_rewind_info;
616
617  private:
618   const exploded_edge *m_eedge;
619 };
620
621 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
622    showing the longjmp (or siglongjmp).  */
623
624 class rewind_from_longjmp_event : public rewind_event
625 {
626 public:
627   rewind_from_longjmp_event (const exploded_edge *eedge,
628                              const event_loc_info &loc_info,
629                              const rewind_info_t *rewind_info)
630   : rewind_event (eedge, EK_REWIND_FROM_LONGJMP, loc_info,
631                   rewind_info)
632   {
633   }
634
635   label_text get_desc (bool can_colorize) const final override;
636 };
637
638 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
639    showing the setjmp (or sigsetjmp).  */
640
641 class rewind_to_setjmp_event : public rewind_event
642 {
643 public:
644   rewind_to_setjmp_event (const exploded_edge *eedge,
645                           const event_loc_info &loc_info,
646                           const rewind_info_t *rewind_info)
647   : rewind_event (eedge, EK_REWIND_TO_SETJMP, loc_info,
648                   rewind_info)
649   {
650   }
651
652   label_text get_desc (bool can_colorize) const final override;
653
654   void prepare_for_emission (checker_path *path,
655                              pending_diagnostic *pd,
656                              diagnostic_event_id_t emission_id) final override;
657
658 private:
659   diagnostic_event_id_t m_original_setjmp_event_id;
660 };
661
662 /* Concrete subclass of checker_event for use at the end of a path:
663    a repeat of the warning message at the end of the path (perhaps with
664    references to pertinent events that occurred on the way), at the point
665    where the problem occurs.  */
666
667 class warning_event : public checker_event
668 {
669 public:
670   warning_event (const event_loc_info &loc_info,
671                  const state_machine *sm,
672                  tree var, state_machine::state_t state)
673   : checker_event (EK_WARNING, loc_info),
674     m_sm (sm), m_var (var), m_state (state)
675   {
676   }
677
678   label_text get_desc (bool can_colorize) const final override;
679   meaning get_meaning () const override;
680
681 private:
682   const state_machine *m_sm;
683   tree m_var;
684   state_machine::state_t m_state;
685 };
686
687 } // namespace ana
688
689 #endif /* GCC_ANALYZER_CHECKER_EVENT_H */