blob: 890a56f7b56286bb96a516a0466186f671447ab2 [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(
Alexander Kornienko976e0c02018-11-25 02:41:01 +000026 unless(has(expr(anyOf(isTypeDependent(), isValueDependent())))),
27 // The thrown value is not derived from 'std::exception'.
28 has(expr(unless(
29 hasType(qualType(hasCanonicalType(hasDeclaration(cxxRecordDecl(
30 isSameOrDerivedFrom(hasName("::std::exception")))))))))),
31 // This condition is always true, but will bind to the
32 // template value if the thrown type is templated.
33 anyOf(has(expr(
34 hasType(substTemplateTypeParmType().bind("templ_type")))),
35 anything()),
36 // Bind to the declaration of the type of the value that
37 // is thrown. 'anything()' is necessary to always suceed
38 // in the 'eachOf' because builtin types are not
39 // 'namedDecl'.
40 eachOf(has(expr(hasType(namedDecl().bind("decl")))), anything()))
Aaron Ballmana3274e52017-08-11 16:31:51 +000041 .bind("bad_throw"),
42 this);
43}
44
45void ExceptionBaseclassCheck::check(const MatchFinder::MatchResult &Result) {
46 const auto *BadThrow = Result.Nodes.getNodeAs<CXXThrowExpr>("bad_throw");
Jonas Tothb1efe512018-09-17 13:55:10 +000047 assert(BadThrow && "Did not match the throw expression");
Jonas Toth673dbd12017-08-30 15:59:01 +000048
Stephen Kelly43465bf2018-08-09 22:42:26 +000049 diag(BadThrow->getSubExpr()->getBeginLoc(), "throwing an exception whose "
Jonas Toth673dbd12017-08-30 15:59:01 +000050 "type %0 is not derived from "
51 "'std::exception'")
52 << BadThrow->getSubExpr()->getType() << BadThrow->getSourceRange();
Aaron Ballmana3274e52017-08-11 16:31:51 +000053
Jonas Tothb1efe512018-09-17 13:55:10 +000054 if (const auto *Template =
55 Result.Nodes.getNodeAs<SubstTemplateTypeParmType>("templ_type"))
56 diag(BadThrow->getSubExpr()->getBeginLoc(),
57 "type %0 is a template instantiation of %1", DiagnosticIDs::Note)
58 << BadThrow->getSubExpr()->getType()
59 << Template->getReplacedParameter()->getDecl();
60
61 if (const auto *TypeDecl = Result.Nodes.getNodeAs<NamedDecl>("decl"))
Stephen Kelly43465bf2018-08-09 22:42:26 +000062 diag(TypeDecl->getBeginLoc(), "type defined here", DiagnosticIDs::Note);
Aaron Ballmana3274e52017-08-11 16:31:51 +000063}
64
65} // namespace hicpp
66} // namespace tidy
67} // namespace clang