24class UncountedLambdaCapturesChecker
25 :
public Checker<check::ASTDecl<TranslationUnitDecl>> {
27 BugType Bug{
this,
"Lambda capture of uncounted variable",
28 "WebKit coding guidelines"};
41 const UncountedLambdaCapturesChecker *
Checker;
42 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
43 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
46 explicit LocalVisitor(
const UncountedLambdaCapturesChecker *
Checker)
49 ShouldVisitTemplateInstantiations =
true;
50 ShouldVisitImplicitCode =
false;
57 return DynamicRecursiveASTVisitor::TraverseCXXMethodDecl(CXXMD);
60 bool shouldCheckThis() {
62 return result && *result;
66 if (LambdasToIgnore.contains(L))
68 Checker->visitLambdaExpr(L, shouldCheckThis());
72 bool VisitVarDecl(
VarDecl *VD)
override {
76 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
79 LambdasToIgnore.insert(L);
84 if (DeclRefExprsToIgnore.contains(DRE))
86 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
92 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
95 LambdasToIgnore.insert(L);
96 Checker->visitLambdaExpr(L, shouldCheckThis());
103 auto *NsDecl =
Decl->getParent();
104 if (!NsDecl || !isa<NamespaceDecl>(NsDecl))
109 bool VisitCallExpr(
CallExpr *CE)
override {
110 checkCalleeLambda(CE);
112 bool TreatAllArgsAsNoEscape = shouldTreatAllArgAsNoEscape(Callee);
113 unsigned ArgIndex = 0;
114 for (
auto *Param :
Callee->parameters()) {
118 if (
auto *L = findLambdaInArg(Arg)) {
119 LambdasToIgnore.insert(L);
120 if (!Param->hasAttr<NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
121 Checker->visitLambdaExpr(L, shouldCheckThis());
130 if (
auto *Lambda = dyn_cast_or_null<LambdaExpr>(
E))
132 auto *TempExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(
E);
138 if (
auto *Lambda = dyn_cast<LambdaExpr>(
E))
140 auto *CE = dyn_cast_or_null<CXXConstructExpr>(
E);
146 if (
auto *Lambda = dyn_cast<LambdaExpr>(CtorArg))
148 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
151 auto *VD = dyn_cast_or_null<VarDecl>(DRE->
getDecl());
157 TempExpr = dyn_cast<CXXBindTemporaryExpr>(
Init->IgnoreParenCasts());
160 return dyn_cast_or_null<LambdaExpr>(TempExpr->getSubExpr());
163 void checkCalleeLambda(
CallExpr *CE) {
167 auto *DRE = dyn_cast<DeclRefExpr>(
Callee->IgnoreParenCasts());
170 auto *MD = dyn_cast_or_null<CXXMethodDecl>(DRE->
getDecl());
174 if (
auto *L = dyn_cast_or_null<LambdaExpr>(Arg)) {
175 LambdasToIgnore.insert(L);
178 auto *ArgRef = dyn_cast<DeclRefExpr>(Arg);
181 auto *VD = dyn_cast_or_null<VarDecl>(ArgRef->getDecl());
187 auto *L = dyn_cast_or_null<LambdaExpr>(
Init->IgnoreParenCasts());
190 DeclRefExprsToIgnore.insert(ArgRef);
191 LambdasToIgnore.insert(L);
192 Checker->visitLambdaExpr(L, shouldCheckThis(),
197 LocalVisitor visitor(
this);
201 void visitLambdaExpr(
LambdaExpr *L,
bool shouldCheckThis,
202 bool ignoreParamVarDecl =
false)
const {
206 if (
C.capturesVariable()) {
208 if (ignoreParamVarDecl && isa<ParmVarDecl>(CapturedVar))
212 if (IsUncountedPtr && *IsUncountedPtr)
213 reportBug(
C, CapturedVar, CapturedVarQualType);
214 }
else if (
C.capturesThis() && shouldCheckThis) {
215 if (ignoreParamVarDecl)
217 bool hasProtectThis =
false;
219 if (!OtherCapture.capturesVariable())
221 if (
auto *
ValueDecl = OtherCapture.getCapturedVar()) {
223 hasProtectThis =
true;
229 reportBugOnThisPtr(
C);
241 auto *BTE = dyn_cast<CXXBindTemporaryExpr>(
Init);
244 auto *CE = dyn_cast_or_null<CXXConstructExpr>(BTE->getSubExpr());
247 auto *Ctor = CE->getConstructor();
254 while (
auto *UO = dyn_cast<UnaryOperator>(Arg)) {
255 auto OpCode = UO->getOpcode();
256 if (OpCode == UO_Deref || OpCode == UO_AddrOf)
257 Arg = UO->getSubExpr();
261 return isa<CXXThisExpr>(Arg);
269 llvm::raw_svector_ostream Os(Buf);
274 Os <<
"Implicitly captured ";
277 Os <<
"raw-pointer ";
284 Os <<
" to ref-counted type or CheckedPtr-capable type is unsafe.";
287 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
293 llvm::raw_svector_ostream Os(Buf);
298 Os <<
"Implicitly captured ";
301 Os <<
"raw-pointer 'this' to ref-counted type or CheckedPtr-capable type "
305 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);
311void ento::registerUncountedLambdaCapturesChecker(
CheckerManager &Mgr) {
315bool ento::shouldRegisterUncountedLambdaCapturesChecker(
Represents a static or instance method of a struct/union/class.
QualType getThisType() const
Return the type of the this pointer.
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
A reference to a declared variable, function, enum, etc.
Decl - This represents one declaration (or definition), e.g.
Recursive AST visitor that supports extension via dynamic dispatch.
This represents one expression.
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Represents a function declaration or definition.
Describes the capture of a variable or of this, or of a C++1y init-capture.
A C++ lambda expression, which produces a function object (of unspecified type) that can be invoked l...
Stmt * getBody() const
Retrieve the body of the lambda.
capture_range captures() const
Retrieve this lambda's captures.
A (possibly-)qualified type.
bool isNull() const
Return true if this QualType doesn't point to a type yet.
The top declaration context.
An inter-procedural analysis facility that detects functions with "trivial" behavior with respect to ...
bool isTrivial(const Decl *D) const
bool isPointerType() const
bool isReferenceType() const
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Represents a variable declaration or definition.
const Expr * getInit() const
BugReporter is a utility class for generating PathDiagnostics for analysis.
const SourceManager & getSourceManager()
virtual void emitReport(std::unique_ptr< BugReport > R)
Add the given report to the set of reports tracked by BugReporter.
CHECKER * registerChecker(AT &&... Args)
Used to register checkers.
SourceLocation getLocation() const
Retrieve the location at which this variable was captured.
The JSON file list parser is used to communicate input to InstallAPI.
void printQuotedQualifiedName(llvm::raw_ostream &Os, const NamedDeclDerivedT &D)
bool isRefType(const std::string &Name)
const FunctionProtoType * T
std::string safeGetName(const T *ASTNode)
std::optional< bool > isUnsafePtr(const QualType T)