10 #include "clang/AST/ASTContext.h" 11 #include "clang/AST/OperationKinds.h" 12 #include "clang/ASTMatchers/ASTMatchFinder.h" 20 ThrowByValueCatchByReferenceCheck::ThrowByValueCatchByReferenceCheck(
23 CheckAnonymousTemporaries(Options.get(
"CheckThrowTemporaries", true)),
24 WarnOnLargeObject(Options.get(
"WarnOnLargeObject", false)),
26 MaxSize(Options.get(
"MaxSize", std::numeric_limits<uint64_t>::max())) {}
33 Finder->addMatcher(cxxThrowExpr().bind(
"throw"),
this);
34 Finder->addMatcher(cxxCatchStmt().bind(
"catch"),
this);
43 const MatchFinder::MatchResult &Result) {
44 diagnoseThrowLocations(Result.Nodes.getNodeAs<CXXThrowExpr>(
"throw"));
45 diagnoseCatchLocations(Result.Nodes.getNodeAs<CXXCatchStmt>(
"catch"),
49 bool ThrowByValueCatchByReferenceCheck::isFunctionParameter(
50 const DeclRefExpr *declRefExpr) {
51 return isa<ParmVarDecl>(declRefExpr->getDecl());
54 bool ThrowByValueCatchByReferenceCheck::isCatchVariable(
55 const DeclRefExpr *declRefExpr) {
56 auto *valueDecl = declRefExpr->getDecl();
57 if (
auto *varDecl = dyn_cast<VarDecl>(valueDecl))
58 return varDecl->isExceptionVariable();
62 bool ThrowByValueCatchByReferenceCheck::isFunctionOrCatchVar(
63 const DeclRefExpr *declRefExpr) {
64 return isFunctionParameter(declRefExpr) || isCatchVariable(declRefExpr);
67 void ThrowByValueCatchByReferenceCheck::diagnoseThrowLocations(
68 const CXXThrowExpr *throwExpr) {
71 auto *subExpr = throwExpr->getSubExpr();
74 auto qualType = subExpr->getType();
75 if (qualType->isPointerType()) {
78 auto *inner = subExpr->IgnoreParenImpCasts();
79 if (isa<StringLiteral>(inner))
82 auto *declRef = dyn_cast<DeclRefExpr>(inner);
83 if (declRef && isCatchVariable(declRef)) {
86 diag(subExpr->getBeginLoc(),
"throw expression throws a pointer; it should " 87 "throw a non-pointer value instead");
102 if (CheckAnonymousTemporaries) {
104 auto *currentSubExpr = subExpr->IgnoreImpCasts();
105 const auto *variableReference = dyn_cast<DeclRefExpr>(currentSubExpr);
106 const auto *constructorCall = dyn_cast<CXXConstructExpr>(currentSubExpr);
110 if (variableReference)
111 emit = !isFunctionOrCatchVar(variableReference);
112 else if (constructorCall &&
113 constructorCall->getConstructor()->isCopyOrMoveConstructor()) {
120 auto *currentSubExpr = (*argIter)->IgnoreImpCasts();
121 if (currentSubExpr->isLValue()) {
122 if (
auto *tmp = dyn_cast<DeclRefExpr>(currentSubExpr))
123 emit = !isFunctionOrCatchVar(tmp);
124 else if (isa<CallExpr>(currentSubExpr))
129 diag(subExpr->getBeginLoc(),
130 "throw expression should throw anonymous temporary values instead");
134 void ThrowByValueCatchByReferenceCheck::diagnoseCatchLocations(
135 const CXXCatchStmt *catchStmt, ASTContext &context) {
138 auto caughtType = catchStmt->getCaughtType();
139 if (caughtType.isNull())
141 auto *varDecl = catchStmt->getExceptionDecl();
142 if (
const auto *PT = caughtType.getCanonicalType()->getAs<PointerType>()) {
143 const char *diagMsgCatchReference =
"catch handler catches a pointer value; " 144 "should throw a non-pointer value and " 145 "catch by reference instead";
148 if (!PT->getPointeeType()->isAnyCharacterType())
149 diag(varDecl->getBeginLoc(), diagMsgCatchReference);
150 }
else if (!caughtType->isReferenceType()) {
151 const char *diagMsgCatchReference =
"catch handler catches by value; " 152 "should catch by reference instead";
156 if (!caughtType.isTrivialType(context)) {
157 diag(varDecl->getBeginLoc(), diagMsgCatchReference);
158 }
else if (WarnOnLargeObject) {
164 if (MaxSize == std::numeric_limits<uint64_t>::max())
165 MaxSize = context.getTypeSize(context.getSizeType());
166 if (context.getTypeSize(caughtType) > MaxSize)
167 diag(varDecl->getBeginLoc(), diagMsgCatchReference);
Base class for all clang-tidy checks.
const LangOptions & getLangOpts() const
Returns the language options from the context.
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.
static constexpr llvm::StringLiteral Name
std::map< std::string, std::string > OptionMap
===– 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.