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