analyzer: introduce struct event_loc_info
[platform/upstream/gcc.git] / gcc / analyzer / pending-diagnostic.h
1 /* Classes 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_PENDING_DIAGNOSTIC_H
22 #define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
23
24 #include "diagnostic-path.h"
25 #include "analyzer/sm.h"
26
27 namespace ana {
28
29 /* A bundle of information about things that are of interest to a
30    pending_diagnostic.
31
32    For now, merely the set of regions that are pertinent to the
33    diagnostic, so that we can notify the user about when they
34    were created.  */
35
36 struct interesting_t
37 {
38   void add_region_creation (const region *reg);
39
40   void dump_to_pp (pretty_printer *pp, bool simple) const;
41
42   auto_vec<const region *> m_region_creation;
43 };
44
45 /* Various bundles of information used for generating more precise
46    messages for events within a diagnostic_path, for passing to the
47    various "describe_*" vfuncs of pending_diagnostic.  See those
48    for more information.  */
49
50 namespace evdesc {
51
52 struct event_desc
53 {
54   event_desc (bool colorize) : m_colorize (colorize) {}
55
56   label_text formatted_print (const char *fmt, ...) const
57     ATTRIBUTE_GCC_DIAG(2,3);
58
59   bool m_colorize;
60 };
61
62 /* For use by pending_diagnostic::describe_state_change.  */
63
64 struct state_change : public event_desc
65 {
66   state_change (bool colorize,
67                 tree expr,
68                 tree origin,
69                 state_machine::state_t old_state,
70                 state_machine::state_t new_state,
71                 diagnostic_event_id_t event_id,
72                 const state_change_event &event)
73   : event_desc (colorize),
74     m_expr (expr), m_origin (origin),
75     m_old_state (old_state), m_new_state (new_state),
76     m_event_id (event_id), m_event (event)
77   {}
78
79   bool is_global_p () const { return m_expr == NULL_TREE; }
80
81   tree m_expr;
82   tree m_origin;
83   state_machine::state_t m_old_state;
84   state_machine::state_t m_new_state;
85   diagnostic_event_id_t m_event_id;
86   const state_change_event &m_event;
87 };
88
89 /* For use by pending_diagnostic::describe_call_with_state.  */
90
91 struct call_with_state : public event_desc
92 {
93   call_with_state (bool colorize,
94                    tree caller_fndecl, tree callee_fndecl,
95                    tree expr, state_machine::state_t state)
96   : event_desc (colorize),
97     m_caller_fndecl (caller_fndecl),
98     m_callee_fndecl (callee_fndecl),
99     m_expr (expr),
100     m_state (state)
101   {
102   }
103
104   tree m_caller_fndecl;
105   tree m_callee_fndecl;
106   tree m_expr;
107   state_machine::state_t m_state;
108 };
109
110 /* For use by pending_diagnostic::describe_return_of_state.  */
111
112 struct return_of_state : public event_desc
113 {
114   return_of_state (bool colorize,
115                    tree caller_fndecl, tree callee_fndecl,
116                    state_machine::state_t state)
117   : event_desc (colorize),
118     m_caller_fndecl (caller_fndecl),
119     m_callee_fndecl (callee_fndecl),
120     m_state (state)
121   {
122   }
123
124   tree m_caller_fndecl;
125   tree m_callee_fndecl;
126   state_machine::state_t m_state;
127 };
128
129 /* For use by pending_diagnostic::describe_final_event.  */
130
131 struct final_event : public event_desc
132 {
133   final_event (bool colorize,
134                tree expr, state_machine::state_t state)
135   : event_desc (colorize),
136     m_expr (expr), m_state (state)
137   {}
138
139   tree m_expr;
140   state_machine::state_t m_state;
141 };
142
143 } /* end of namespace evdesc */
144
145 /* An abstract base class for capturing information about a diagnostic in
146    a form that is ready to emit at a later point (or be rejected).
147    Each kind of diagnostic will have a concrete subclass of
148    pending_diagnostic.
149
150    Normally, gcc diagnostics are emitted using va_list, which can't be
151    portably stored for later use, so we have to use an "emit" virtual
152    function.
153
154    This class also supports comparison, so that multiple pending_diagnostic
155    instances can be de-duplicated.
156
157    As well as emitting a diagnostic, the class has various "precision of
158    wording" virtual functions, for generating descriptions for events
159    within a diagnostic_path.  These are optional, but implementing these
160    allows for more precise wordings than the more generic
161    implementation.  */
162
163 class pending_diagnostic
164 {
165  public:
166   virtual ~pending_diagnostic () {}
167
168   /* Vfunc to get the command-line option used when emitting the diagnostic,
169      or zero if there is none.
170      Used by diagnostic_manager for early rejection of diagnostics (to avoid
171      having to generate feasible execution paths for them).  */
172   virtual int get_controlling_option () const = 0;
173
174   /* Vfunc for emitting the diagnostic.  The rich_location will have been
175      populated with a diagnostic_path.
176      Return true if a diagnostic is actually emitted.  */
177   virtual bool emit (rich_location *) = 0;
178
179   /* Hand-coded RTTI: get an ID for the subclass.  */
180   virtual const char *get_kind () const = 0;
181
182   /* A vfunc for identifying "use of uninitialized value".  */
183   virtual bool use_of_uninit_p () const { return false; }
184
185   /* Compare for equality with OTHER, which might be of a different
186      subclass.  */
187
188   bool equal_p (const pending_diagnostic &other) const
189   {
190     /* Check for pointer equality on the IDs from get_kind.  */
191     if (get_kind () != other.get_kind ())
192       return false;
193     /* Call vfunc now we know they have the same ID: */
194     return subclass_equal_p (other);
195   }
196
197   /* A vfunc for testing for equality, where we've already
198      checked they have the same ID.  See pending_diagnostic_subclass
199      below for a convenience subclass for implementing this.  */
200   virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
201
202   /* Return true if T1 and T2 are "the same" for the purposes of
203      diagnostic deduplication.  */
204   static bool same_tree_p (tree t1, tree t2);
205
206   /* Vfunc for fixing up locations, e.g. to avoid unwinding
207      inside specific macros.  PRIMARY is true for the primary location
208      for the diagnostic, and FALSE for events in their paths.  */
209   virtual location_t fixup_location (location_t loc, bool primary) const;
210
211   /* Precision-of-wording vfunc for describing a critical state change
212      within the diagnostic_path.
213
214      For example, a double-free diagnostic might use the descriptions:
215      - "first 'free' happens here"
216      - "second 'free' happens here"
217      for the pertinent events, whereas a use-after-free might use the
218      descriptions:
219      - "freed here"
220      - "use after free here"
221      Note how in both cases the first event is a "free": the best
222      description to use depends on the diagnostic.  */
223
224   virtual label_text describe_state_change (const evdesc::state_change &)
225   {
226     /* Default no-op implementation.  */
227     return label_text ();
228   }
229
230   /* Vfunc for implementing diagnostic_event::get_meaning for
231      state_change_event.  */
232   virtual diagnostic_event::meaning
233   get_meaning_for_state_change (const evdesc::state_change &) const
234   {
235     /* Default no-op implementation.  */
236     return diagnostic_event::meaning ();
237   }
238
239   /* Precision-of-wording vfunc for describing an interprocedural call
240      carrying critial state for the diagnostic, from caller to callee.
241
242      For example a double-free diagnostic might use:
243      - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
244      to make it clearer how the freed value moves from caller to
245      callee.  */
246
247   virtual label_text describe_call_with_state (const evdesc::call_with_state &)
248   {
249     /* Default no-op implementation.  */
250     return label_text ();
251   }
252
253   /* Precision-of-wording vfunc for describing an interprocedural return
254      within the diagnostic_path that carries critial state for the
255      diagnostic, from callee back to caller.
256
257      For example, a deref-of-unchecked-malloc diagnostic might use:
258      - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
259      to make it clearer how the unchecked value moves from callee
260      back to caller.  */
261
262   virtual label_text describe_return_of_state (const evdesc::return_of_state &)
263   {
264     /* Default no-op implementation.  */
265     return label_text ();
266   }
267
268   /* Precision-of-wording vfunc for describing the final event within a
269      diagnostic_path.
270
271      For example a double-free diagnostic might use:
272       - "second 'free' here; first 'free' was at (3)"
273      and a use-after-free might use
274       - "use after 'free' here; memory was freed at (2)".  */
275
276   virtual label_text describe_final_event (const evdesc::final_event &)
277   {
278     /* Default no-op implementation.  */
279     return label_text ();
280   }
281
282   /* End of precision-of-wording vfuncs.  */
283
284   /* Vfunc for adding a function_entry_event to a checker_path, so that e.g.
285      the infinite recursion diagnostic can add a custom event subclass
286      that annotates recursively entering a function.  */
287
288   virtual void
289   add_function_entry_event (const exploded_edge &eedge,
290                             checker_path *emission_path);
291
292   /* Vfunc for extending/overriding creation of the events for an
293      exploded_edge that corresponds to a superedge, allowing for custom
294      events to be created that are pertinent to a particular
295      pending_diagnostic subclass.
296
297      For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
298      custom event showing when the pertinent stack frame is popped
299      (and thus the point at which the jmp_buf becomes invalid).  */
300
301   virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
302                                                       checker_path *)
303   {
304     return false;
305   }
306
307   /* Vfunc for adding a call_event to a checker_path, so that e.g.
308      the varargs diagnostics can add a custom event subclass that annotates
309      the variadic arguments.  */
310   virtual void add_call_event (const exploded_edge &,
311                                checker_path *);
312
313   /* Vfunc for adding any events for the creation of regions identified
314      by the mark_interesting_stuff vfunc.
315      See the comment for class region_creation_event.  */
316   virtual void add_region_creation_events (const region *reg,
317                                            tree capacity,
318                                            const event_loc_info &loc_info,
319                                            checker_path &emission_path);
320
321   /* Vfunc for adding the final warning_event to a checker_path, so that e.g.
322      the infinite recursion diagnostic can have its diagnostic appear at
323      the callsite, but the final event in the path be at the entrypoint
324      of the called function.  */
325   virtual void add_final_event (const state_machine *sm,
326                                 const exploded_node *enode,
327                                 const gimple *stmt,
328                                 tree var, state_machine::state_t state,
329                                 checker_path *emission_path);
330
331   /* Vfunc for determining that this pending_diagnostic supercedes OTHER,
332      and that OTHER should therefore not be emitted.
333      They have already been tested for being at the same stmt.  */
334
335   virtual bool
336   supercedes_p (const pending_diagnostic &other ATTRIBUTE_UNUSED) const
337   {
338     return false;
339   }
340
341   /* Vfunc for registering additional information of interest to this
342      diagnostic.  */
343
344   virtual void mark_interesting_stuff (interesting_t *)
345   {
346     /* Default no-op implementation.  */
347   }
348 };
349
350 /* A template to make it easier to make subclasses of pending_diagnostic.
351
352    This uses the curiously-recurring template pattern, to implement
353    pending_diagnostic::subclass_equal_p by casting and calling
354    the operator==
355
356    This assumes that BASE_OTHER has already been checked to have
357    been of the same subclass (which pending_diagnostic::equal_p does).  */
358
359 template <class Subclass>
360 class pending_diagnostic_subclass : public pending_diagnostic
361 {
362  public:
363   bool subclass_equal_p (const pending_diagnostic &base_other) const
364     final override
365   {
366     const Subclass &other = (const Subclass &)base_other;
367     return *(const Subclass*)this == other;
368   }
369 };
370
371 /* An abstract base class for capturing additional notes that are to be
372    emitted with a diagnostic.  */
373
374 class pending_note
375 {
376 public:
377   virtual ~pending_note () {}
378
379   /* Hand-coded RTTI: get an ID for the subclass.  */
380   virtual const char *get_kind () const = 0;
381
382   /* Vfunc for emitting the note.  */
383   virtual void emit () const = 0;
384
385   bool equal_p (const pending_note &other) const
386   {
387     /* Check for pointer equality on the IDs from get_kind.  */
388     if (get_kind () != other.get_kind ())
389       return false;
390     /* Call vfunc now we know they have the same ID: */
391     return subclass_equal_p (other);
392   }
393
394   /* A vfunc for testing for equality, where we've already
395      checked they have the same ID.  See pending_note_subclass
396      below for a convenience subclass for implementing this.  */
397   virtual bool subclass_equal_p (const pending_note &other) const = 0;
398 };
399
400 /* Analogous to pending_diagnostic_subclass, but for pending_note.  */
401
402 template <class Subclass>
403 class pending_note_subclass : public pending_note
404 {
405  public:
406   bool subclass_equal_p (const pending_note &base_other) const
407     final override
408   {
409     const Subclass &other = (const Subclass &)base_other;
410     return *(const Subclass*)this == other;
411   }
412 };
413
414 } // namespace ana
415
416 #endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */