1 //===--- ExceptionBaseclassCheck.cpp - clang-tidy--------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "ExceptionBaseclassCheck.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 using namespace clang::ast_matchers
;
15 namespace clang::tidy::hicpp
{
17 void ExceptionBaseclassCheck::registerMatchers(MatchFinder
*Finder
) {
20 unless(has(expr(anyOf(isTypeDependent(), isValueDependent())))),
21 // The thrown value is not derived from 'std::exception'.
23 hasType(qualType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
24 isSameOrDerivedFrom(hasName("::std::exception")))))))))),
25 // This condition is always true, but will bind to the
26 // template value if the thrown type is templated.
28 hasType(substTemplateTypeParmType().bind("templ_type")))),
30 // Bind to the declaration of the type of the value that
31 // is thrown. 'anything()' is necessary to always succeed
32 // in the 'eachOf' because builtin types are not
34 eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything()))
39 void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult
&Result
) {
40 const auto *BadThrow
= Result
.Nodes
.getNodeAs
<CXXThrowExpr
>("bad_throw");
41 assert(BadThrow
&& "Did not match the throw expression");
43 diag(BadThrow
->getSubExpr()->getBeginLoc(), "throwing an exception whose "
44 "type %0 is not derived from "
46 << BadThrow
->getSubExpr()->getType() << BadThrow
->getSourceRange();
48 if (const auto *Template
=
49 Result
.Nodes
.getNodeAs
<SubstTemplateTypeParmType
>("templ_type"))
50 diag(BadThrow
->getSubExpr()->getBeginLoc(),
51 "type %0 is a template instantiation of %1", DiagnosticIDs::Note
)
52 << BadThrow
->getSubExpr()->getType()
53 << Template
->getReplacedParameter();
55 if (const auto *TypeDecl
= Result
.Nodes
.getNodeAs
<NamedDecl
>("decl"))
56 diag(TypeDecl
->getBeginLoc(), "type defined here", DiagnosticIDs::Note
);
59 } // namespace clang::tidy::hicpp