]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/analyzer/pending-diagnostic.h
Update copyright years.
[thirdparty/gcc.git] / gcc / analyzer / pending-diagnostic.h
CommitLineData
757bf1df 1/* Classes for analyzer diagnostics.
99dee823 2 Copyright (C) 2019-2021 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_PENDING_DIAGNOSTIC_H
22#define GCC_ANALYZER_PENDING_DIAGNOSTIC_H
23
75038aa6
DM
24namespace ana {
25
757bf1df
DM
26/* Various bundles of information used for generating more precise
27 messages for events within a diagnostic_path, for passing to the
28 various "describe_*" vfuncs of pending_diagnostic. See those
29 for more information. */
30
31namespace evdesc {
32
33struct event_desc
34{
35 event_desc (bool colorize) : m_colorize (colorize) {}
36
37 label_text formatted_print (const char *fmt, ...) const
38 ATTRIBUTE_GCC_DIAG(2,3);
39
40 bool m_colorize;
41};
42
43/* For use by pending_diagnostic::describe_state_change. */
44
45struct state_change : public event_desc
46{
47 state_change (bool colorize,
48 tree expr,
49 tree origin,
50 state_machine::state_t old_state,
51 state_machine::state_t new_state,
52 diagnostic_event_id_t event_id,
53 const state_change_event &event)
54 : event_desc (colorize),
55 m_expr (expr), m_origin (origin),
56 m_old_state (old_state), m_new_state (new_state),
57 m_event_id (event_id), m_event (event)
58 {}
59
60 bool is_global_p () const { return m_expr == NULL_TREE; }
61
62 tree m_expr;
63 tree m_origin;
64 state_machine::state_t m_old_state;
65 state_machine::state_t m_new_state;
66 diagnostic_event_id_t m_event_id;
67 const state_change_event &m_event;
68};
69
70/* For use by pending_diagnostic::describe_call_with_state. */
71
72struct call_with_state : public event_desc
73{
74 call_with_state (bool colorize,
75 tree caller_fndecl, tree callee_fndecl,
76 tree expr, state_machine::state_t state)
77 : event_desc (colorize),
78 m_caller_fndecl (caller_fndecl),
79 m_callee_fndecl (callee_fndecl),
80 m_expr (expr),
81 m_state (state)
82 {
83 }
84
85 tree m_caller_fndecl;
86 tree m_callee_fndecl;
87 tree m_expr;
88 state_machine::state_t m_state;
89};
90
91/* For use by pending_diagnostic::describe_return_of_state. */
92
93struct return_of_state : public event_desc
94{
95 return_of_state (bool colorize,
96 tree caller_fndecl, tree callee_fndecl,
97 state_machine::state_t state)
98 : event_desc (colorize),
99 m_caller_fndecl (caller_fndecl),
100 m_callee_fndecl (callee_fndecl),
101 m_state (state)
102 {
103 }
104
105 tree m_caller_fndecl;
106 tree m_callee_fndecl;
107 state_machine::state_t m_state;
108};
109
110/* For use by pending_diagnostic::describe_final_event. */
111
112struct final_event : public event_desc
113{
114 final_event (bool colorize,
115 tree expr, state_machine::state_t state)
116 : event_desc (colorize),
117 m_expr (expr), m_state (state)
118 {}
119
120 tree m_expr;
121 state_machine::state_t m_state;
122};
123
124} /* end of namespace evdesc */
125
126/* An abstract base class for capturing information about a diagnostic in
127 a form that is ready to emit at a later point (or be rejected).
128 Each kind of diagnostic will have a concrete subclass of
129 pending_diagnostic.
130
131 Normally, gcc diagnostics are emitted using va_list, which can't be
132 portably stored for later use, so we have to use an "emit" virtual
133 function.
134
135 This class also supports comparison, so that multiple pending_diagnostic
136 instances can be de-duplicated.
137
138 As well as emitting a diagnostic, the class has various "precision of
139 wording" virtual functions, for generating descriptions for events
140 within a diagnostic_path. These are optional, but implementing these
141 allows for more precise wordings than the more generic
142 implementation. */
143
144class pending_diagnostic
145{
146 public:
147 virtual ~pending_diagnostic () {}
148
149 /* Vfunc for emitting the diagnostic. The rich_location will have been
150 populated with a diagnostic_path.
151 Return true if a diagnostic is actually emitted. */
152 virtual bool emit (rich_location *) = 0;
153
154 /* Hand-coded RTTI: get an ID for the subclass. */
155 virtual const char *get_kind () const = 0;
156
157 /* Compare for equality with OTHER, which might be of a different
158 subclass. */
159
160 bool equal_p (const pending_diagnostic &other)
161 {
162 /* Check for pointer equality on the IDs from get_kind. */
163 if (get_kind () != other.get_kind ())
164 return false;
165 /* Call vfunc now we know they have the same ID: */
166 return subclass_equal_p (other);
167 }
168
169 /* A vfunc for testing for equality, where we've already
170 checked they have the same ID. See pending_diagnostic_subclass
171 below for a convenience subclass for implementing this. */
172 virtual bool subclass_equal_p (const pending_diagnostic &other) const = 0;
173
14f9d7b9
DM
174 /* Return true if T1 and T2 are "the same" for the purposes of
175 diagnostic deduplication. */
176 static bool same_tree_p (tree t1, tree t2);
177
66dde7bc
DM
178 /* A vfunc for fixing up locations (both the primary location for the
179 diagnostic, and for events in their paths), e.g. to avoid unwinding
180 inside specific macros. */
181 virtual location_t fixup_location (location_t loc) const
182 {
183 return loc;
184 }
185
757bf1df
DM
186 /* For greatest precision-of-wording, the various following "describe_*"
187 virtual functions give the pending diagnostic a way to describe events
188 in a diagnostic_path in terms that make sense for that diagnostic.
189
190 In each case, return a non-NULL label_text to give the event a custom
191 description; NULL otherwise (falling back on a more generic
192 description). */
193
194 /* Precision-of-wording vfunc for describing a critical state change
195 within the diagnostic_path.
196
197 For example, a double-free diagnostic might use the descriptions:
198 - "first 'free' happens here"
199 - "second 'free' happens here"
200 for the pertinent events, whereas a use-after-free might use the
201 descriptions:
202 - "freed here"
203 - "use after free here"
204 Note how in both cases the first event is a "free": the best
205 description to use depends on the diagnostic. */
206
207 virtual label_text describe_state_change (const evdesc::state_change &)
208 {
209 /* Default no-op implementation. */
210 return label_text ();
211 }
212
213 /* Precision-of-wording vfunc for describing an interprocedural call
214 carrying critial state for the diagnostic, from caller to callee.
215
216 For example a double-free diagnostic might use:
217 - "passing freed pointer 'ptr' in call to 'deallocator' from 'test'"
218 to make it clearer how the freed value moves from caller to
219 callee. */
220
221 virtual label_text describe_call_with_state (const evdesc::call_with_state &)
222 {
223 /* Default no-op implementation. */
224 return label_text ();
225 }
226
227 /* Precision-of-wording vfunc for describing an interprocedural return
228 within the diagnostic_path that carries critial state for the
229 diagnostic, from callee back to caller.
230
231 For example, a deref-of-unchecked-malloc diagnostic might use:
232 - "returning possibly-NULL pointer to 'make_obj' from 'allocator'"
233 to make it clearer how the unchecked value moves from callee
234 back to caller. */
235
236 virtual label_text describe_return_of_state (const evdesc::return_of_state &)
237 {
238 /* Default no-op implementation. */
239 return label_text ();
240 }
241
242 /* Precision-of-wording vfunc for describing the final event within a
243 diagnostic_path.
244
245 For example a double-free diagnostic might use:
246 - "second 'free' here; first 'free' was at (3)"
247 and a use-after-free might use
248 - "use after 'free' here; memory was freed at (2)". */
249
250 virtual label_text describe_final_event (const evdesc::final_event &)
251 {
252 /* Default no-op implementation. */
253 return label_text ();
254 }
255
256 /* End of precision-of-wording vfuncs. */
8069928d
DM
257
258 /* Vfunc for extending/overriding creation of the events for an
259 exploded_edge that corresponds to a superedge, allowing for custom
260 events to be created that are pertinent to a particular
261 pending_diagnostic subclass.
262
263 For example, the -Wanalyzer-stale-setjmp-buffer diagnostic adds a
264 custom event showing when the pertinent stack frame is popped
265 (and thus the point at which the jmp_buf becomes invalid). */
266
267 virtual bool maybe_add_custom_events_for_superedge (const exploded_edge &,
268 checker_path *)
269 {
270 return false;
271 }
757bf1df
DM
272};
273
274/* A template to make it easier to make subclasses of pending_diagnostic.
275
276 This uses the curiously-recurring template pattern, to implement
277 pending_diagnostic::subclass_equal_p by casting and calling
278 the operator==
279
280 This assumes that BASE_OTHER has already been checked to have
281 been of the same subclass (which pending_diagnostic::equal_p does). */
282
283template <class Subclass>
284class pending_diagnostic_subclass : public pending_diagnostic
285{
286 public:
287 bool subclass_equal_p (const pending_diagnostic &base_other) const
288 FINAL OVERRIDE
289 {
290 const Subclass &other = (const Subclass &)base_other;
291 return *(const Subclass*)this == other;
292 }
293};
294
75038aa6
DM
295} // namespace ana
296
757bf1df 297#endif /* GCC_ANALYZER_PENDING_DIAGNOSTIC_H */