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 { @@ -35,6 +33,7 @@ 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'") << BadThrow->getSourceRange(); Index: docs/ReleaseNotes.rst =================================================================== --- docs/ReleaseNotes.rst +++ docs/ReleaseNotes.rst @@ -57,6 +57,12 @@ Improvements to clang-tidy -------------------------- +- New `hicpp-exception-baseclass + `_ check + + This check ensures that all exception will be instances of ``std::exception`` and classes + that are derived from it. + - Renamed checks to use correct term "implicit conversion" instead of "implicit cast" and modified messages and option names accordingly: Index: docs/clang-tidy/checks/list.rst =================================================================== --- docs/clang-tidy/checks/list.rst +++ docs/clang-tidy/checks/list.rst @@ -38,7 +38,7 @@ cert-msc30-c (redirects to cert-msc50-cpp) cert-msc50-cpp cert-oop11-cpp (redirects to misc-move-constructor-init) - cppcoreguidelines-c-copy-assignment-signature + cppcoreguidelines-c-copy-assignment-signature (redirects to misc-unconventional-assign-operator) cppcoreguidelines-interfaces-global-init cppcoreguidelines-no-malloc cppcoreguidelines-pro-bounds-array-to-pointer-decay 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]]:5: warning: throwing an exception whose type 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]]:3: warning: throwing an exception whose type 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]]:5: warning: throwing an exception whose type 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]]:3: warning: throwing an exception whose type is not derived from 'std::exception' + // CHECK-MESSAGES: 9:1: note: type defined here } void allowed_throws() { @@ -39,4 +40,41 @@ } 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]]:25: warning: throwing an exception whose type is not derived from 'std::exception' + // CHECK-MESSAGES: [[@LINE-3]]:11: 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 {}; + +void generic_exceptions() { + THROW_EXCEPTION(int); + THROW_EXCEPTION(std::exception); + THROW_EXCEPTION(derived_exception); + THROW_EXCEPTION(deep_hierarchy); + THROW_EXCEPTION(non_derived_exception); + + THROW_BAD_EXCEPTION; + // CHECK-MESSAGES: [[@LINE-1]]:3: warning: throwing an exception whose type is not derived from 'std::exception' + // CHECK-MESSAGES: [[@LINE-16]]:29: note: expanded from macro 'THROW_BAD_EXCEPTION' + THROW_GOOD_EXCEPTION; + THROW_DERIVED_EXCEPTION; + + throw generic_exception(); + + THROW_EXCEPTION(generic_exception); }