11 #include "clang/AST/ASTContext.h" 12 #include "clang/AST/OperationKinds.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 21 ThrowByValueCatchByReferenceCheck::ThrowByValueCatchByReferenceCheck(
24 CheckAnonymousTemporaries(Options.get(
"CheckThrowTemporaries", true)) {}
31 Finder->addMatcher(cxxThrowExpr().bind(
"throw"),
this);
32 Finder->addMatcher(cxxCatchStmt().bind(
"catch"),
this);
41 const MatchFinder::MatchResult &
Result) {
42 diagnoseThrowLocations(Result.Nodes.getNodeAs<CXXThrowExpr>(
"throw"));
43 diagnoseCatchLocations(Result.Nodes.getNodeAs<CXXCatchStmt>(
"catch"),
47 bool ThrowByValueCatchByReferenceCheck::isFunctionParameter(
48 const DeclRefExpr *declRefExpr) {
49 return isa<ParmVarDecl>(declRefExpr->getDecl());
52 bool ThrowByValueCatchByReferenceCheck::isCatchVariable(
53 const DeclRefExpr *declRefExpr) {
54 auto *valueDecl = declRefExpr->getDecl();
55 if (
auto *varDecl = dyn_cast<VarDecl>(valueDecl))
56 return varDecl->isExceptionVariable();
60 bool ThrowByValueCatchByReferenceCheck::isFunctionOrCatchVar(
61 const DeclRefExpr *declRefExpr) {
62 return isFunctionParameter(declRefExpr) || isCatchVariable(declRefExpr);
65 void ThrowByValueCatchByReferenceCheck::diagnoseThrowLocations(
66 const CXXThrowExpr *throwExpr) {
69 auto *subExpr = throwExpr->getSubExpr();
72 auto qualType = subExpr->getType();
73 if (qualType->isPointerType()) {
76 auto *inner = subExpr->IgnoreParenImpCasts();
77 if (isa<StringLiteral>(inner))
80 auto *declRef = dyn_cast<DeclRefExpr>(inner);
81 if (declRef && isCatchVariable(declRef)) {
84 diag(subExpr->getBeginLoc(),
"throw expression throws a pointer; it should " 85 "throw a non-pointer value instead");
100 if (CheckAnonymousTemporaries) {
102 auto *currentSubExpr = subExpr->IgnoreImpCasts();
103 const auto *variableReference = dyn_cast<DeclRefExpr>(currentSubExpr);
104 const auto *constructorCall = dyn_cast<CXXConstructExpr>(currentSubExpr);
108 if (variableReference)
109 emit = !isFunctionOrCatchVar(variableReference);
110 else if (constructorCall &&
111 constructorCall->getConstructor()->isCopyOrMoveConstructor()) {
118 auto *currentSubExpr = (*argIter)->IgnoreImpCasts();
119 if (currentSubExpr->isLValue()) {
120 if (
auto *tmp = dyn_cast<DeclRefExpr>(currentSubExpr))
121 emit = !isFunctionOrCatchVar(tmp);
122 else if (isa<CallExpr>(currentSubExpr))
127 diag(subExpr->getBeginLoc(),
128 "throw expression should throw anonymous temporary values instead");
132 void ThrowByValueCatchByReferenceCheck::diagnoseCatchLocations(
133 const CXXCatchStmt *catchStmt, ASTContext &context) {
136 auto caughtType = catchStmt->getCaughtType();
137 if (caughtType.isNull())
139 auto *varDecl = catchStmt->getExceptionDecl();
140 if (
const auto *PT = caughtType.getCanonicalType()->getAs<PointerType>()) {
141 const char *diagMsgCatchReference =
"catch handler catches a pointer value; " 142 "should throw a non-pointer value and " 143 "catch by reference instead";
146 if (!PT->getPointeeType()->isAnyCharacterType())
147 diag(varDecl->getBeginLoc(), diagMsgCatchReference);
148 }
else if (!caughtType->isReferenceType()) {
149 const char *diagMsgCatchReference =
"catch handler catches by value; " 150 "should catch by reference instead";
154 if (!caughtType.isTrivialType(context))
155 diag(varDecl->getBeginLoc(), diagMsgCatchReference);
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.
LangOptions getLangOpts() const
Returns the language options from the context.
Base class for all clang-tidy checks.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
Should store all options supported by this check with their current values or default values for opti...
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
Override this to register AST matchers with Finder.
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
ClangTidyChecks that register ASTMatchers should do the actual work in here.
DiagnosticBuilder diag(SourceLocation Loc, StringRef Description, DiagnosticIDs::Level Level=DiagnosticIDs::Warning)
Add a diagnostic with the check's name.