Index: clang-tidy/hicpp/ExceptionBaseclassCheck.cpp =================================================================== --- clang-tidy/hicpp/ExceptionBaseclassCheck.cpp +++ clang-tidy/hicpp/ExceptionBaseclassCheck.cpp @@ -11,8 +11,6 @@ #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" -#include - using namespace clang::ast_matchers; namespace clang { @@ -28,6 +26,7 @@ allOf( has(expr(unless(hasType(cxxRecordDecl( isSameOrDerivedFrom(hasName("std::exception"))))))), + has(expr(unless(cxxUnresolvedConstructExpr()))), eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything()))) .bind("bad_throw"), this); @@ -35,8 +34,10 @@ void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult &Result) { const auto *BadThrow = Result.Nodes.getNodeAs("bad_throw"); - diag(BadThrow->getLocStart(), - "throwing an exception whose type is not derived from 'std::exception'") + + diag(BadThrow->getSubExpr()->getLocStart(), + "throwing an exception whose type %0 is not derived from 'std::exception'") + << BadThrow->getSubExpr()->getType() << BadThrow->getSourceRange(); const auto *TypeDecl = Result.Nodes.getNodeAs("decl"); Index: test/clang-tidy/hicpp-exception-baseclass.cpp =================================================================== --- test/clang-tidy/hicpp-exception-baseclass.cpp +++ test/clang-tidy/hicpp-exception-baseclass.cpp @@ -5,26 +5,27 @@ } // namespace std class derived_exception : public std::exception {}; +class deep_hierarchy : public derived_exception {}; class non_derived_exception {}; void problematic() { try { throw int(42); // Built in is not allowed -// CHECK-MESSAGES: [[@LINE-1]]:5: warning: throwing an exception whose type is not derived from 'std::exception' + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'int' is not derived from 'std::exception' } catch (int e) { } throw int(42); // Bad -// CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception' + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'int' is not derived from 'std::exception' try { throw non_derived_exception(); // Some class is not allowed -// CHECK-MESSAGES: [[@LINE-1]]:5: warning: throwing an exception whose type is not derived from 'std::exception' -// CHECK-MESSAGES: 8:1: note: type defined here + // CHECK-MESSAGES: [[@LINE-1]]:11: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' + // CHECK-MESSAGES: 9:1: note: type defined here } catch (non_derived_exception &e) { } throw non_derived_exception(); // Bad -// CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception' -// CHECK-MESSAGES: 8:1: note: type defined here + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' + // CHECK-MESSAGES: 9:1: note: type defined here } void allowed_throws() { @@ -39,4 +40,89 @@ } catch (derived_exception &e) { // Ok } throw derived_exception(); // Ok + + try { + throw deep_hierarchy(); // Ok, multiple levels of inheritance + } catch (deep_hierarchy &e) { // Ok + } + throw deep_hierarchy(); // Ok +} + +// Templated function that throws exception based on template type +template +void ThrowException() { throw T(); } +// CHECK-MESSAGES: [[@LINE-1]]:31: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' +// CHECK-MESSAGES: 71:1: note: type defined here +// CHECK-MESSAGES: [[@LINE-3]]:31: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' +// CHECK-MESSAGES: 71:1: note: type defined here +// CHECK-MESSAGES: [[@LINE-5]]:31: warning: throwing an exception whose type 'exotic_exception' is not derived from 'std::exception' +// CHECK-MESSAGES: 74:1: note: type defined here +// CHECK-MESSAGES: [[@LINE-7]]:31: warning: throwing an exception whose type 'int' is not derived from 'std::exception' +// CHECK-MESSAGES: [[@LINE-8]]:31: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' +// CHECK-MESSAGES: 9:1: note: type defined here +#define THROW_EXCEPTION(CLASS) ThrowException() +#define THROW_BAD_EXCEPTION throw int(42); +#define THROW_GOOD_EXCEPTION throw std::exception(); +#define THROW_DERIVED_EXCEPTION throw deep_hierarchy(); + +template +class generic_exception : std::exception {}; + +template +class bad_generic_exception {}; + +template +class exotic_exception : public T {}; + +void generic_exceptions() { + THROW_EXCEPTION(int); // Bad + // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception' + THROW_EXCEPTION(non_derived_exception); // Bad + // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'non_derived_exception' is not derived from 'std::exception' + // CHECK MESSAGES: 9:1: note: type defined here + THROW_EXCEPTION(std::exception); // Ok + THROW_EXCEPTION(derived_exception); // Ok + THROW_EXCEPTION(deep_hierarchy); // Ok + + THROW_BAD_EXCEPTION; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'int' is not derived from 'std::exception' + // CHECK-MESSAGES: [[@LINE-25]]:35: note: expanded from macro 'THROW_BAD_EXCEPTION' + THROW_GOOD_EXCEPTION; + THROW_DERIVED_EXCEPTION; + + throw generic_exception(); // Ok, + THROW_EXCEPTION(generic_exception); // Ok + + throw bad_generic_exception(); // Bad, not derived + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' + throw bad_generic_exception(); // Bad as well, since still not derived + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' + THROW_EXCEPTION(bad_generic_exception); // Bad + // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' + THROW_EXCEPTION(bad_generic_exception); // Bad + // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'bad_generic_exception' is not derived from 'std::exception' + + throw exotic_exception(); // Bad + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'exotic_exception' is not derived from 'std::exception' + THROW_EXCEPTION(exotic_exception); // Bad + // CHECK MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type 'exotic_exception' is not derived from 'std::exception' + + throw exotic_exception(); // Ok + THROW_EXCEPTION(exotic_exception); // Ok +} + +// Test for typedefed exception types +typedef int TypedefedBad; +typedef derived_exception TypedefedGood; +using UsingBad = int; +using UsingGood = deep_hierarchy; + +void typedefed() { + throw TypedefedBad(); // Bad + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'TypedefedBad' (aka 'int') is not derived from 'std::exception' + throw TypedefedGood(); // Ok + + throw UsingBad(); // Bad + // CHECK-MESSAGES: [[@LINE-1]]:9: warning: throwing an exception whose type 'UsingBad' (aka 'int') is not derived from 'std::exception' + throw UsingGood(); // Ok }