1 //===--- ExceptionBaseclassCheck.cpp - clang-tidy--------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "ExceptionBaseclassCheck.h" 10 #include "clang/AST/ASTContext.h" 11 #include "clang/ASTMatchers/ASTMatchFinder.h" 12 13 using namespace clang::ast_matchers; 14 15 namespace clang { 16 namespace tidy { 17 namespace hicpp { 18 19 void ExceptionBaseclassCheck::registerMatchers(MatchFinder *Finder) { 20 Finder->addMatcher( 21 cxxThrowExpr( 22 unless(has(expr(anyOf(isTypeDependent(), isValueDependent())))), 23 // The thrown value is not derived from 'std::exception'. 24 has(expr(unless( 25 hasType(qualType(hasCanonicalType(hasDeclaration(cxxRecordDecl( 26 isSameOrDerivedFrom(hasName("::std::exception")))))))))), 27 // This condition is always true, but will bind to the 28 // template value if the thrown type is templated. 29 anyOf(has(expr( 30 hasType(substTemplateTypeParmType().bind("templ_type")))), 31 anything()), 32 // Bind to the declaration of the type of the value that 33 // is thrown. 'anything()' is necessary to always succeed 34 // in the 'eachOf' because builtin types are not 35 // 'namedDecl'. 36 eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything())) 37 .bind("bad_throw"), 38 this); 39 } 40 41 void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult &Result) { 42 const auto *BadThrow = Result.Nodes.getNodeAs<CXXThrowExpr>("bad_throw"); 43 assert(BadThrow && "Did not match the throw expression"); 44 45 diag(BadThrow->getSubExpr()->getBeginLoc(), "throwing an exception whose " 46 "type %0 is not derived from " 47 "'std::exception'") 48 << BadThrow->getSubExpr()->getType() << BadThrow->getSourceRange(); 49 50 if (const auto *Template = 51 Result.Nodes.getNodeAs<SubstTemplateTypeParmType>("templ_type")) 52 diag(BadThrow->getSubExpr()->getBeginLoc(), 53 "type %0 is a template instantiation of %1", DiagnosticIDs::Note) 54 << BadThrow->getSubExpr()->getType() 55 << Template->getReplacedParameter(); 56 57 if (const auto *TypeDecl = Result.Nodes.getNodeAs<NamedDecl>("decl")) 58 diag(TypeDecl->getBeginLoc(), "type defined here", DiagnosticIDs::Note); 59 } 60 61 } // namespace hicpp 62 } // namespace tidy 63 } // namespace clang 64