blob: b299151cceaac5e1ac7414baa1a1321b940f4ed7 [file] [log] [blame]
Aaron Ballmana3274e52017-08-11 16:31:51 +00001//===--- ExceptionBaseclassCheck.cpp - clang-tidy--------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "ExceptionBaseclassCheck.h"
11#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13
Aaron Ballmana3274e52017-08-11 16:31:51 +000014using namespace clang::ast_matchers;
15
16namespace clang {
17namespace tidy {
18namespace hicpp {
19
20void ExceptionBaseclassCheck::registerMatchers(MatchFinder *Finder) {
21 if (!getLangOpts().CPlusPlus)
22 return;
23
24 Finder->addMatcher(
Jonas Tothb1efe512018-09-17 13:55:10 +000025 cxxThrowExpr(
26 allOf(
27 unless(has(expr(anyOf(isTypeDependent(), isValueDependent())))),
28 // The thrown value is not derived from 'std::exception'.
29 has(expr(unless(hasType(
30 qualType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
31 isSameOrDerivedFrom(hasName("::std::exception")))))))))),
32 // This condition is always true, but will bind to the
33 // template value if the thrown type is templated.
34 anyOf(has(expr(hasType(
35 substTemplateTypeParmType().bind("templ_type")))),
36 anything()),
37 // Bind to the declaration of the type of the value that
38 // is thrown. 'anything()' is necessary to always suceed
39 // in the 'eachOf' because builtin types are not
40 // 'namedDecl'.
41 eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything())))
Aaron Ballmana3274e52017-08-11 16:31:51 +000042 .bind("bad_throw"),
43 this);
44}
45
46void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult &Result) {
47 const auto *BadThrow = Result.Nodes.getNodeAs<CXXThrowExpr>("bad_throw");
Jonas Tothb1efe512018-09-17 13:55:10 +000048 assert(BadThrow && "Did not match the throw expression");
Jonas Toth673dbd12017-08-30 15:59:01 +000049
Stephen Kelly43465bf2018-08-09 22:42:26 +000050 diag(BadThrow->getSubExpr()->getBeginLoc(), "throwing an exception whose "
Jonas Toth673dbd12017-08-30 15:59:01 +000051 "type %0 is not derived from "
52 "'std::exception'")
53 << BadThrow->getSubExpr()->getType() << BadThrow->getSourceRange();
Aaron Ballmana3274e52017-08-11 16:31:51 +000054
Jonas Tothb1efe512018-09-17 13:55:10 +000055 if (const auto *Template =
56 Result.Nodes.getNodeAs<SubstTemplateTypeParmType>("templ_type"))
57 diag(BadThrow->getSubExpr()->getBeginLoc(),
58 "type %0 is a template instantiation of %1", DiagnosticIDs::Note)
59 << BadThrow->getSubExpr()->getType()
60 << Template->getReplacedParameter()->getDecl();
61
62 if (const auto *TypeDecl = Result.Nodes.getNodeAs<NamedDecl>("decl"))
Stephen Kelly43465bf2018-08-09 22:42:26 +000063 diag(TypeDecl->getBeginLoc(), "type defined here", DiagnosticIDs::Note);
Aaron Ballmana3274e52017-08-11 16:31:51 +000064}
65
66} // namespace hicpp
67} // namespace tidy
68} // namespace clang