1 | // RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions |
2 | |
3 | namespace std { |
4 | class exception {}; |
5 | class invalid_argument : public exception {}; |
6 | } // namespace std |
7 | |
8 | class derived_exception : public std::exception {}; |
9 | class deep_hierarchy : public derived_exception {}; |
10 | class non_derived_exception {}; |
11 | class terrible_idea : public non_derived_exception, public derived_exception {}; |
12 | |
13 | // FIXME: More complicated kinds of inheritance should be checked later, but there is |
14 | // currently no way use ASTMatchers for this kind of task. |
15 | #if 0 |
16 | class bad_inheritance : private std::exception {}; |
17 | class no_good_inheritance : protected std::exception {}; |
18 | class really_creative : public non_derived_exception, private std::exception {}; |
19 | #endif |
20 | |
21 | void problematic() { |
22 | try { |
23 | throw int(42); |
24 | // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
25 | } catch (int e) { |
26 | } |
27 | throw int(42); |
28 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
29 | |
30 | try { |
31 | throw 12; |
32 | // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
33 | } catch (...) { |
34 | throw; // Ok, even if the type is not known, conforming code can never rethrow a non-std::exception object. |
35 | } |
36 | |
37 | try { |
38 | throw non_derived_exception(); |
39 | // CHECK-NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' |
40 | // CHECK-NOTES: 10:1: note: type defined here |
41 | } catch (non_derived_exception &e) { |
42 | } |
43 | throw non_derived_exception(); |
44 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' |
45 | // CHECK-NOTES: 10:1: note: type defined here |
46 | |
47 | // FIXME: More complicated kinds of inheritance should be checked later, but there is |
48 | // currently no way use ASTMatchers for this kind of task. |
49 | #if 0 |
50 | // Handle private inheritance cases correctly. |
51 | try { |
52 | throw bad_inheritance(); |
53 | // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception' |
54 | // CHECK NOTES: 11:1: note: type defined here |
55 | throw no_good_inheritance(); |
56 | // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception' |
57 | // CHECK NOTES: 12:1: note: type defined here |
58 | throw really_creative(); |
59 | // CHECK NOTES: [[@LINE-1]]:11: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception' |
60 | // CHECK NOTES: 13:1: note: type defined here |
61 | } catch (...) { |
62 | } |
63 | throw bad_inheritance(); |
64 | // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_inheritance' is not derived from 'std::exception' |
65 | // CHECK NOTES: 11:1: note: type defined here |
66 | throw no_good_inheritance(); |
67 | // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'no_good_inheritance' is not derived from 'std::exception' |
68 | // CHECK NOTES: 12:1: note: type defined here |
69 | throw really_creative(); |
70 | // CHECK NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'really_creative' is not derived from 'std::exception' |
71 | // CHECK NOTES: 13:1: note: type defined here |
72 | #endif |
73 | } |
74 | |
75 | void allowed_throws() { |
76 | try { |
77 | throw std::exception(); // Ok |
78 | } catch (std::exception &e) { // Ok |
79 | } |
80 | throw std::exception(); |
81 | |
82 | try { |
83 | throw derived_exception(); // Ok |
84 | } catch (derived_exception &e) { // Ok |
85 | } |
86 | throw derived_exception(); // Ok |
87 | |
88 | try { |
89 | throw deep_hierarchy(); // Ok, multiple levels of inheritance |
90 | } catch (deep_hierarchy &e) { // Ok |
91 | } |
92 | throw deep_hierarchy(); // Ok |
93 | |
94 | try { |
95 | throw terrible_idea(); // Ok, but multiple inheritance isn't clean |
96 | } catch (std::exception &e) { // Can be caught as std::exception, even with multiple inheritance |
97 | } |
98 | throw terrible_idea(); // Ok, but multiple inheritance |
99 | } |
100 | |
101 | void test_lambdas() { |
102 | auto BadLambda = []() { throw int(42); }; |
103 | // CHECK-NOTES: [[@LINE-1]]:33: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
104 | auto GoodLambda = []() { throw derived_exception(); }; |
105 | } |
106 | |
107 | // Templated function that throws exception based on template type |
108 | template <typename T> |
109 | void ThrowException() { throw T(); } |
110 | // CHECK-NOTES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception' |
111 | // CHECK-NOTES: [[@LINE-2]]:31: note: type 'bad_generic_exception<int>' is a template instantiation of 'T' |
112 | // CHECK-NOTES: [[@LINE+25]]:1: note: type defined here |
113 | |
114 | // CHECK-NOTES: [[@LINE-5]]:31: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception' |
115 | // CHECK-NOTES: [[@LINE-6]]:31: note: type 'bad_generic_exception<std::exception>' is a template instantiation of 'T' |
116 | // CHECK-NOTES: [[@LINE+21]]:1: note: type defined here |
117 | |
118 | // CHECK-NOTES: [[@LINE-9]]:31: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception' |
119 | // CHECK-NOTES: [[@LINE-10]]:31: note: type 'exotic_exception<non_derived_exception>' is a template instantiation of 'T' |
120 | // CHECK-NOTES: [[@LINE+20]]:1: note: type defined here |
121 | |
122 | // CHECK-NOTES: [[@LINE-13]]:31: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
123 | // CHECK-NOTES: [[@LINE-14]]:31: note: type 'int' is a template instantiation of 'T' |
124 | |
125 | // CHECK-NOTES: [[@LINE-16]]:31: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' |
126 | // CHECK-NOTES: [[@LINE-17]]:31: note: type 'non_derived_exception' is a template instantiation of 'T' |
127 | // CHECK-NOTES: 10:1: note: type defined here |
128 | |
129 | #define THROW_EXCEPTION(CLASS) ThrowException<CLASS>() |
130 | #define THROW_BAD_EXCEPTION throw int(42); |
131 | #define THROW_GOOD_EXCEPTION throw std::exception(); |
132 | #define THROW_DERIVED_EXCEPTION throw deep_hierarchy(); |
133 | |
134 | template <typename T> |
135 | class generic_exception : std::exception {}; |
136 | |
137 | template <typename T> |
138 | class bad_generic_exception {}; |
139 | |
140 | template <typename T> |
141 | class exotic_exception : public T {}; |
142 | |
143 | void generic_exceptions() { |
144 | THROW_EXCEPTION(int); |
145 | THROW_EXCEPTION(non_derived_exception); |
146 | THROW_EXCEPTION(std::exception); // Ok |
147 | THROW_EXCEPTION(derived_exception); // Ok |
148 | THROW_EXCEPTION(deep_hierarchy); // Ok |
149 | |
150 | THROW_BAD_EXCEPTION; |
151 | // CHECK-NOTES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
152 | // CHECK-NOTES: [[@LINE-22]]:35: note: expanded from macro 'THROW_BAD_EXCEPTION' |
153 | THROW_GOOD_EXCEPTION; |
154 | THROW_DERIVED_EXCEPTION; |
155 | |
156 | throw generic_exception<int>(); // Ok, |
157 | THROW_EXCEPTION(generic_exception<float>); // Ok |
158 | |
159 | throw bad_generic_exception<int>(); |
160 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<int>' is not derived from 'std::exception' |
161 | // CHECK-NOTES: [[@LINE-24]]:1: note: type defined here |
162 | throw bad_generic_exception<std::exception>(); |
163 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception<std::exception>' is not derived from 'std::exception' |
164 | // CHECK-NOTES: [[@LINE-27]]:1: note: type defined here |
165 | THROW_EXCEPTION(bad_generic_exception<int>); |
166 | THROW_EXCEPTION(bad_generic_exception<std::exception>); |
167 | |
168 | throw exotic_exception<non_derived_exception>(); |
169 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception<non_derived_exception>' is not derived from 'std::exception' |
170 | // CHECK-NOTES: [[@LINE-30]]:1: note: type defined here |
171 | THROW_EXCEPTION(exotic_exception<non_derived_exception>); |
172 | |
173 | throw exotic_exception<derived_exception>(); // Ok |
174 | THROW_EXCEPTION(exotic_exception<derived_exception>); // Ok |
175 | } |
176 | |
177 | // Test for typedefed exception types |
178 | typedef int TypedefedBad; |
179 | typedef derived_exception TypedefedGood; |
180 | using UsingBad = int; |
181 | using UsingGood = deep_hierarchy; |
182 | |
183 | void typedefed() { |
184 | throw TypedefedBad(); |
185 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'TypedefedBad' (aka 'int') is not derived from 'std::exception' |
186 | // CHECK-NOTES: [[@LINE-8]]:1: note: type defined here |
187 | throw TypedefedGood(); // Ok |
188 | |
189 | throw UsingBad(); |
190 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'UsingBad' (aka 'int') is not derived from 'std::exception' |
191 | // CHECK-NOTES: [[@LINE-11]]:1: note: type defined here |
192 | throw UsingGood(); // Ok |
193 | } |
194 | |
195 | // Fix PR37913 |
196 | struct invalid_argument_maker { |
197 | ::std::invalid_argument operator()() const; |
198 | }; |
199 | struct int_maker { |
200 | int operator()() const; |
201 | }; |
202 | |
203 | template <typename T> |
204 | void templated_thrower() { |
205 | throw T{}(); |
206 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
207 | } |
208 | template <typename T> |
209 | void templated_thrower2() { |
210 | T ExceptionFactory; // This test found a <dependant-type> which did not happend with 'throw T{}()' |
211 | throw ExceptionFactory(); |
212 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
213 | } |
214 | |
215 | void exception_created_with_function() { |
216 | templated_thrower<invalid_argument_maker>(); |
217 | templated_thrower<int_maker>(); |
218 | |
219 | templated_thrower2<invalid_argument_maker>(); |
220 | templated_thrower2<int_maker>(); |
221 | |
222 | throw invalid_argument_maker{}(); |
223 | throw int_maker{}(); |
224 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
225 | } |
226 | |
227 | struct invalid_argument_factory { |
228 | ::std::invalid_argument make_exception() const; |
229 | }; |
230 | |
231 | struct int_factory { |
232 | int make_exception() const; |
233 | }; |
234 | |
235 | template <typename T> |
236 | void templated_factory() { |
237 | T f; |
238 | throw f.make_exception(); |
239 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
240 | } |
241 | template <typename T> |
242 | void templated_factory2() { |
243 | throw T().make_exception(); |
244 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
245 | } |
246 | |
247 | void exception_from_factory() { |
248 | templated_factory<invalid_argument_factory>(); |
249 | templated_factory<int_factory>(); |
250 | |
251 | templated_factory2<invalid_argument_factory>(); |
252 | templated_factory2<int_factory>(); |
253 | |
254 | throw invalid_argument_factory().make_exception(); |
255 | throw int_factory().make_exception(); |
256 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
257 | |
258 | invalid_argument_factory inv_f; |
259 | throw inv_f.make_exception(); |
260 | |
261 | int_factory int_f; |
262 | throw int_f.make_exception(); |
263 | // CHECK-NOTES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
264 | } |
265 | |
266 | template <typename T> |
267 | struct ThrowClassTemplateParam { |
268 | ThrowClassTemplateParam() { throw T(); } |
269 | // CHECK-NOTES: [[@LINE-1]]:37: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
270 | // CHECK-NOTES: [[@LINE-2]]:37: note: type 'int' is a template instantiation of 'T' |
271 | }; |
272 | |
273 | template <int V> |
274 | struct ThrowValueTemplate { |
275 | ThrowValueTemplate() { throw V; } |
276 | // CHECK-NOTES: [[@LINE-1]]:32: warning: throwing an exception whose type 'int' is not derived from 'std::exception' |
277 | }; |
278 | |
279 | void class_templates() { |
280 | ThrowClassTemplateParam<int> IntThrow; |
281 | ThrowClassTemplateParam<std::invalid_argument> ArgThrow; |
282 | |
283 | ThrowValueTemplate<42> ValueThrow; |
284 | } |
285 | |