285 lines · cpp
1// RUN: %check_clang_tidy %s hicpp-exception-baseclass %t -- -- -fcxx-exceptions2 3namespace std {4class exception {};5class invalid_argument : public exception {};6} // namespace std7 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 is14// currently no way use ASTMatchers for this kind of task.15#if 016class bad_inheritance : private std::exception {};17class no_good_inheritance : protected std::exception {};18class really_creative : public non_derived_exception, private std::exception {};19#endif20 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 here41 } 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 here46 47// FIXME: More complicated kinds of inheritance should be checked later, but there is48// currently no way use ASTMatchers for this kind of task.49#if 050 // 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 here55 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 here58 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 here61 } 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 here66 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 here69 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 here72#endif73}74 75void allowed_throws() {76 try {77 throw std::exception(); // Ok78 } catch (std::exception &e) { // Ok79 }80 throw std::exception();81 82 try {83 throw derived_exception(); // Ok84 } catch (derived_exception &e) { // Ok85 }86 throw derived_exception(); // Ok87 88 try {89 throw deep_hierarchy(); // Ok, multiple levels of inheritance90 } catch (deep_hierarchy &e) { // Ok91 }92 throw deep_hierarchy(); // Ok93 94 try {95 throw terrible_idea(); // Ok, but multiple inheritance isn't clean96 } catch (std::exception &e) { // Can be caught as std::exception, even with multiple inheritance97 }98 throw terrible_idea(); // Ok, but multiple inheritance99}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 type108template <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 here113 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 here117 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 here121 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 here128 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); // Ok147 THROW_EXCEPTION(derived_exception); // Ok148 THROW_EXCEPTION(deep_hierarchy); // Ok149 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>); // Ok158 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 here162 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 here165 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 here171 THROW_EXCEPTION(exotic_exception<non_derived_exception>);172 173 throw exotic_exception<derived_exception>(); // Ok174 THROW_EXCEPTION(exotic_exception<derived_exception>); // Ok175}176 177// Test for typedefed exception types178typedef 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 here187 throw TypedefedGood(); // Ok188 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 here192 throw UsingGood(); // Ok193}194 195// Fix PR37913196struct 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