1// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions
2
3namespace std {
4class exception {};
5class invalid_argument : public exception {};
6} // namespace std
7
8class derived_exception : public std::exception {};
9class deep_hierarchy : public derived_exception {};
10class non_derived_exception {};
11class 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
16class bad_inheritance : private std::exception {};
17class no_good_inheritance : protected std::exception {};
18class really_creative : public non_derived_exception, private std::exception {};
19#endif
20
21void 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
75void 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
101void 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
108template <typename T>
109void 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
134template <typename T>
135class generic_exception : std::exception {};
136
137template <typename T>
138class bad_generic_exception {};
139
140template <typename T>
141class exotic_exception : public T {};
142
143void 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
178typedef int TypedefedBad;
179typedef derived_exception TypedefedGood;
180using UsingBad = int;
181using UsingGood = deep_hierarchy;
182
183void 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
196struct invalid_argument_maker {
197 ::std::invalid_argument operator()() const;
198};
199struct int_maker {
200 int operator()() const;
201};
202
203template <typename T>
204void 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}
208template <typename T>
209void 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
215void 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
227struct invalid_argument_factory {
228 ::std::invalid_argument make_exception() const;
229};
230
231struct int_factory {
232 int make_exception() const;
233};
234
235template <typename T>
236void 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}
241template <typename T>
242void 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
247void 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
266template <typename T>
267struct 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
273template <int V>
274struct 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
279void class_templates() {
280 ThrowClassTemplateParam<int> IntThrow;
281 ThrowClassTemplateParam<std::invalid_argument> ArgThrow;
282
283 ThrowValueTemplate<42> ValueThrow;
284}
285

source code of clang-tools-extra/test/clang-tidy/checkers/hicpp/exception-baseclass.cpp