11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/AST/OperationKinds.h"
15 using namespace clang::ast_matchers;
20 ThrowByValueCatchByReferenceCheck::ThrowByValueCatchByReferenceCheck(
23 CheckAnonymousTemporaries(Options.get(
"CheckThrowTemporaries", true)) {}
30 Finder->addMatcher(cxxThrowExpr().bind(
"throw"),
this);
31 Finder->addMatcher(cxxCatchStmt().bind(
"catch"),
this);
40 const MatchFinder::MatchResult &
Result) {
41 diagnoseThrowLocations(Result.Nodes.getNodeAs<CXXThrowExpr>(
"throw"));
42 diagnoseCatchLocations(Result.Nodes.getNodeAs<CXXCatchStmt>(
"catch"),
46 bool ThrowByValueCatchByReferenceCheck::isFunctionParameter(
47 const DeclRefExpr *declRefExpr) {
48 return isa<ParmVarDecl>(declRefExpr->getDecl());
51 bool ThrowByValueCatchByReferenceCheck::isCatchVariable(
52 const DeclRefExpr *declRefExpr) {
53 auto *valueDecl = declRefExpr->getDecl();
54 if (
auto *varDecl = dyn_cast<VarDecl>(valueDecl))
55 return varDecl->isExceptionVariable();
59 bool ThrowByValueCatchByReferenceCheck::isFunctionOrCatchVar(
60 const DeclRefExpr *declRefExpr) {
61 return isFunctionParameter(declRefExpr) || isCatchVariable(declRefExpr);
64 void ThrowByValueCatchByReferenceCheck::diagnoseThrowLocations(
65 const CXXThrowExpr *throwExpr) {
68 auto *subExpr = throwExpr->getSubExpr();
71 auto qualType = subExpr->getType();
72 if (qualType->isPointerType()) {
75 auto *inner = subExpr->IgnoreParenImpCasts();
76 if (isa<StringLiteral>(inner))
79 auto *declRef = dyn_cast<DeclRefExpr>(inner);
80 if (declRef && isCatchVariable(declRef)) {
83 diag(subExpr->getLocStart(),
"throw expression throws a pointer; it should "
84 "throw a non-pointer value instead");
99 if (CheckAnonymousTemporaries) {
101 auto *currentSubExpr = subExpr->IgnoreImpCasts();
102 const DeclRefExpr *variableReference =
103 dyn_cast<DeclRefExpr>(currentSubExpr);
104 const CXXConstructExpr *constructorCall =
105 dyn_cast<CXXConstructExpr>(currentSubExpr);
109 if (variableReference)
110 emit = !isFunctionOrCatchVar(variableReference);
111 else if (constructorCall &&
112 constructorCall->getConstructor()->isCopyOrMoveConstructor()) {
119 auto *currentSubExpr = (*argIter)->IgnoreImpCasts();
120 if (currentSubExpr->isLValue()) {
121 if (
auto *tmp = dyn_cast<DeclRefExpr>(currentSubExpr))
122 emit = !isFunctionOrCatchVar(tmp);
123 else if (isa<CallExpr>(currentSubExpr))
128 diag(subExpr->getLocStart(),
129 "throw expression should throw anonymous temporary values instead");
133 void ThrowByValueCatchByReferenceCheck::diagnoseCatchLocations(
134 const CXXCatchStmt *catchStmt, ASTContext &context) {
135 const char *diagMsgCatchReference =
"catch handler catches a pointer value; "
136 "should throw a non-pointer value and "
137 "catch by reference instead";
140 auto caughtType = catchStmt->getCaughtType();
141 if (caughtType.isNull())
143 auto *varDecl = catchStmt->getExceptionDecl();
144 if (
const auto *PT = caughtType.getCanonicalType()->getAs<
PointerType>()) {
147 if (!PT->getPointeeType()->isAnyCharacterType())
148 diag(varDecl->getLocStart(), diagMsgCatchReference);
149 }
else if (!caughtType->isReferenceType()) {
153 if (!caughtType.isTrivialType(context))
154 diag(varDecl->getLocStart(), diagMsgCatchReference);
LangOptions getLangOpts() const
Returns the language options from the context.
std::unique_ptr< ast_matchers::MatchFinder > Finder
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register ASTMatchers with Finder.
Base class for all clang-tidy checks.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
void store(ClangTidyOptions::OptionMap &Options, StringRef LocalName, StringRef Value) const
Stores an option with the check-local name LocalName with string value Value to Options.
std::map< std::string, std::string > OptionMap
static const char PointerType[]
ClangTidyContext & Context
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.