analyzer: cleanups to checker_path
[platform/upstream/gcc.git] / gcc / analyzer / checker-path.h
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>.
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 /* An enum for discriminating between the concrete subclasses of
25    checker_event.  */
26
27 enum event_kind
28 {
29   EK_DEBUG,
30   EK_CUSTOM,
31   EK_STMT,
32   EK_FUNCTION_ENTRY,
33   EK_STATE_CHANGE,
34   EK_START_CFG_EDGE,
35   EK_END_CFG_EDGE,
36   EK_CALL_EDGE,
37   EK_RETURN_EDGE,
38   EK_SETJMP,
39   EK_REWIND_FROM_LONGJMP,
40   EK_REWIND_TO_SETJMP,
41   EK_WARNING
42 };
43
44 extern const char *event_kind_to_string (enum event_kind ek);
45
46 /* Event subclasses.
47
48    The class hierarchy looks like this (using indentation to show
49    inheritance, and with event_kinds shown for the concrete subclasses):
50
51    diagnostic_event
52      checker_event
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)
58        superedge_event
59          cfg_edge_event
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)
65        rewind_event
66          rewind_from_longjmp_event (EK_REWIND_FROM_LONGJMP)
67          rewind_to_setjmp_event (EK_REWIND_TO_SETJMP)
68        warning_event (EK_WARNING).  */
69
70 /* Abstract subclass of diagnostic_event; the base class for use in
71    checker_path (the analyzer's diagnostic_path subclass).  */
72
73 class checker_event : public diagnostic_event
74 {
75 public:
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 ()
80   {
81   }
82
83   /* Implementation of diagnostic_event.  */
84
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; }
88
89   /* Additional functionality.  */
90
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; }
97
98   void dump (pretty_printer *pp) const;
99
100  public:
101   const enum event_kind m_kind;
102  protected:
103   location_t m_loc;
104   tree m_fndecl;
105   int m_depth;
106   pending_diagnostic *m_pending_diagnostic;
107   diagnostic_event_id_t m_emission_id; // only set once all pruning has occurred
108 };
109
110 /* A concrete event subclass for a purely textual event, for use in
111    debugging path creation and filtering.  */
112
113 class debug_event : public checker_event
114 {
115 public:
116   debug_event (location_t loc, tree fndecl, int depth,
117               const char *desc)
118   : checker_event (EK_DEBUG, loc, fndecl, depth),
119     m_desc (xstrdup (desc))
120   {
121   }
122   ~debug_event ()
123   {
124     free (m_desc);
125   }
126
127   label_text get_desc (bool) const FINAL OVERRIDE;
128
129 private:
130   char *m_desc;
131 };
132
133 /* A concrete event subclass for custom events.  These are not filtered,
134    as they are likely to be pertinent to the diagnostic.  */
135
136 class custom_event : public checker_event
137 {
138 public:
139   custom_event (location_t loc, tree fndecl, int depth,
140                 const char *desc)
141   : checker_event (EK_CUSTOM, loc, fndecl, depth),
142     m_desc (xstrdup (desc))
143   {
144   }
145   ~custom_event ()
146   {
147     free (m_desc);
148   }
149
150   label_text get_desc (bool) const FINAL OVERRIDE;
151
152 private:
153   char *m_desc;
154 };
155
156 /* A concrete event subclass describing the execution of a gimple statement,
157    for use at high verbosity levels when debugging paths.  */
158
159 class statement_event : public checker_event
160 {
161 public:
162   statement_event (const gimple *stmt, tree fndecl, int depth,
163                    const program_state &dst_state);
164
165   label_text get_desc (bool) const FINAL OVERRIDE;
166
167   const gimple * const m_stmt;
168   const program_state m_dst_state;
169 };
170
171 /* An event subclass describing the entry to a function.  */
172
173 class function_entry_event : public checker_event
174 {
175 public:
176   function_entry_event (location_t loc, tree fndecl, int depth)
177   : checker_event (EK_FUNCTION_ENTRY, loc, fndecl, depth)
178   {
179   }
180
181   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
182
183   bool is_function_entry_p () const FINAL OVERRIDE { return true; }
184 };
185
186 /* Subclass of checker_event describing a state change.  */
187
188 class state_change_event : public checker_event
189 {
190 public:
191   state_change_event (const supernode *node, const gimple *stmt,
192                       int stack_depth,
193                       const state_machine &sm,
194                       tree var,
195                       state_machine::state_t from,
196                       state_machine::state_t to,
197                       tree origin,
198                       const program_state &dst_state);
199
200   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
201
202   region_id get_lvalue (tree expr) const
203   {
204     return m_dst_state.m_region_model->get_lvalue (expr, NULL);
205   }
206
207   const supernode *m_node;
208   const gimple *m_stmt;
209   const state_machine &m_sm;
210   tree m_var;
211   state_machine::state_t m_from;
212   state_machine::state_t m_to;
213   tree m_origin;
214   program_state m_dst_state;
215 };
216
217 /* Subclass of checker_event; parent class for subclasses that relate to
218    a superedge.  */
219
220 class superedge_event : public checker_event
221 {
222 public:
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)
228   {
229     m_var = var;
230     m_critical_state = state;
231   }
232
233   const callgraph_superedge& get_callgraph_superedge () const;
234
235   bool should_filter_p (int verbosity) const;
236
237  protected:
238   superedge_event (enum event_kind kind, const exploded_edge &eedge,
239                    location_t loc, tree fndecl, int depth);
240
241  public:
242   const exploded_edge &m_eedge;
243   const superedge *m_sedge;
244   tree m_var;
245   state_machine::state_t m_critical_state;
246 };
247
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.  */
251
252 class cfg_edge_event : public superedge_event
253 {
254 public:
255   const cfg_superedge& get_cfg_superedge () const;
256
257  protected:
258   cfg_edge_event (enum event_kind kind, const exploded_edge &eedge,
259                   location_t loc, tree fndecl, int depth);
260 };
261
262 /* A concrete event subclass for the start of a CFG edge
263    e.g. "following 'false' branch...'.  */
264
265 class start_cfg_edge_event : public cfg_edge_event
266 {
267 public:
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)
271   {
272   }
273
274   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
275
276  private:
277   label_text maybe_describe_condition (bool can_colorize) const;
278
279   static label_text maybe_describe_condition (bool can_colorize,
280                                               tree lhs,
281                                               enum tree_code op,
282                                               tree rhs);
283   static bool should_print_expr_p (tree);
284 };
285
286 /* A concrete event subclass for the end of a CFG edge
287    e.g. "...to here'.  */
288
289 class end_cfg_edge_event : public cfg_edge_event
290 {
291 public:
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)
295   {
296   }
297
298   label_text get_desc (bool /*can_colorize*/) const FINAL OVERRIDE
299   {
300     return label_text::borrow ("...to here");
301   }
302 };
303
304 /* A concrete event subclass for an interprocedural call.  */
305
306 class call_event : public superedge_event
307 {
308 public:
309   call_event (const exploded_edge &eedge,
310               location_t loc, tree fndecl, int depth);
311
312   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
313
314   bool is_call_p () const FINAL OVERRIDE;
315 };
316
317 /* A concrete event subclass for an interprocedural return.  */
318
319 class return_event : public superedge_event
320 {
321 public:
322   return_event (const exploded_edge &eedge,
323                 location_t loc, tree fndecl, int depth);
324
325   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
326
327   bool is_return_p () const FINAL OVERRIDE;
328 };
329
330 /* A concrete event subclass for a setjmp call.  */
331
332 class setjmp_event : public checker_event
333 {
334 public:
335   setjmp_event (location_t loc, const exploded_node *enode,
336                 tree fndecl, int depth)
337   : checker_event (EK_SETJMP, loc, fndecl, depth),
338     m_enode (enode)
339   {
340   }
341
342   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
343
344   void prepare_for_emission (checker_path *path,
345                              pending_diagnostic *pd,
346                              diagnostic_event_id_t emission_id) FINAL OVERRIDE;
347
348 private:
349   const exploded_node *m_enode;
350 };
351
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
354    rewind.  */
355
356 class rewind_event : public checker_event
357 {
358 public:
359   tree get_longjmp_caller () const;
360   tree get_setjmp_caller () const;
361   const exploded_edge *get_eedge () const { return m_eedge; }
362
363  protected:
364   rewind_event (const exploded_edge *eedge,
365                 enum event_kind kind,
366                 location_t loc, tree fndecl, int depth);
367
368  private:
369   const exploded_edge *m_eedge;
370 };
371
372 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
373    showing the longjmp.  */
374
375 class rewind_from_longjmp_event : public rewind_event
376 {
377 public:
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)
381   {
382   }
383
384   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
385 };
386
387 /* A concrete event subclass for rewinding from a longjmp to a setjmp,
388    showing the setjmp.  */
389
390 class rewind_to_setjmp_event : public rewind_event
391 {
392 public:
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)
398   {
399   }
400
401   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
402
403   void prepare_for_emission (checker_path *path,
404                              pending_diagnostic *pd,
405                              diagnostic_event_id_t emission_id) FINAL OVERRIDE;
406
407 private:
408   diagnostic_event_id_t m_original_setjmp_event_id;
409   const rewind_info_t *m_rewind_info;
410 };
411
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.  */
416
417 class warning_event : public checker_event
418 {
419 public:
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)
425   {
426   }
427
428   label_text get_desc (bool can_colorize) const FINAL OVERRIDE;
429
430 private:
431   const state_machine *m_sm;
432   tree m_var;
433   state_machine::state_t m_state;
434 };
435
436 /* Subclass of diagnostic_path for analyzer diagnostics.  */
437
438 class checker_path : public diagnostic_path
439 {
440 public:
441   checker_path () : diagnostic_path () {}
442
443   /* Implementation of diagnostic_path vfuncs.  */
444
445   unsigned num_events () const FINAL OVERRIDE
446   {
447     return m_events.length ();
448   }
449
450   const diagnostic_event & get_event (int idx) const FINAL OVERRIDE
451   {
452     return *m_events[idx];
453   }
454
455   checker_event *get_checker_event (int idx)
456   {
457     return m_events[idx];
458   }
459
460   void dump (pretty_printer *pp) const;
461   void debug () const;
462
463   void maybe_log (logger *logger, const char *desc) const;
464
465   void add_event (checker_event *event)
466   {
467     m_events.safe_push (event);
468   }
469
470   void delete_event (int idx)
471   {
472     checker_event *event = m_events[idx];
473     m_events.ordered_remove (idx);
474     delete event;
475   }
476
477   void add_final_event (const state_machine *sm,
478                         const exploded_node *enode, const gimple *stmt,
479                         tree var, state_machine::state_t state);
480
481   /* After all event-pruning, a hook for notifying each event what
482      its ID will be.  The events are notified in order, allowing
483      for later events to refer to the IDs of earlier events in
484      their descriptions.  */
485   void prepare_for_emission (pending_diagnostic *pd)
486   {
487     checker_event *e;
488     int i;
489     FOR_EACH_VEC_ELT (m_events, i, e)
490       e->prepare_for_emission (this, pd, diagnostic_event_id_t (i));
491   }
492
493   void record_setjmp_event (const exploded_node *enode,
494                             diagnostic_event_id_t setjmp_emission_id)
495   {
496     m_setjmp_event_ids.put (enode, setjmp_emission_id);
497   }
498
499   bool get_setjmp_event (const exploded_node *enode,
500                          diagnostic_event_id_t *out_emission_id)
501   {
502     if (diagnostic_event_id_t *emission_id = m_setjmp_event_ids.get (enode))
503       {
504         *out_emission_id = *emission_id;
505         return true;
506       }
507     return false;
508   }
509
510 private:
511   DISABLE_COPY_AND_ASSIGN(checker_path);
512
513   /* The events that have occurred along this path.  */
514   auto_delete_vec<checker_event> m_events;
515
516   /* During prepare_for_emission (and after), the setjmp_event for each
517      exploded_node *, so that rewind events can refer to them in their
518      descriptions.  */
519   hash_map <const exploded_node *, diagnostic_event_id_t> m_setjmp_event_ids;
520 };
521
522 #endif /* GCC_ANALYZER_CHECKER_PATH_H */