@@ -41,7 +41,9 @@ class UncountedLambdaCapturesChecker
4141 const UncountedLambdaCapturesChecker *Checker;
4242 llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
4343 llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
44+ llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
4445 llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
46+
4547 QualType ClsType;
4648
4749 using Base = RecursiveASTVisitor<LocalVisitor>;
@@ -69,7 +71,7 @@ class UncountedLambdaCapturesChecker
6971 bool VisitLambdaExpr (LambdaExpr *L) {
7072 if (LambdasToIgnore.contains (L))
7173 return true ;
72- Checker->visitLambdaExpr (L, shouldCheckThis ());
74+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) );
7375 return true ;
7476 }
7577
@@ -97,7 +99,7 @@ class UncountedLambdaCapturesChecker
9799 if (!L)
98100 return true ;
99101 LambdasToIgnore.insert (L);
100- Checker->visitLambdaExpr (L, shouldCheckThis ());
102+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) );
101103 return true ;
102104 }
103105
@@ -122,7 +124,8 @@ class UncountedLambdaCapturesChecker
122124 if (auto *L = findLambdaInArg (Arg)) {
123125 LambdasToIgnore.insert (L);
124126 if (!Param->hasAttr <NoEscapeAttr>())
125- Checker->visitLambdaExpr (L, shouldCheckThis ());
127+ Checker->visitLambdaExpr (L, shouldCheckThis () &&
128+ !hasProtectedThis (L));
126129 }
127130 ++ArgIndex;
128131 }
@@ -142,7 +145,8 @@ class UncountedLambdaCapturesChecker
142145 if (auto *L = findLambdaInArg (Arg)) {
143146 LambdasToIgnore.insert (L);
144147 if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
145- Checker->visitLambdaExpr (L, shouldCheckThis ());
148+ Checker->visitLambdaExpr (L, shouldCheckThis () &&
149+ !hasProtectedThis (L));
146150 }
147151 ++ArgIndex;
148152 }
@@ -171,6 +175,13 @@ class UncountedLambdaCapturesChecker
171175 ConstructToIgnore.insert (CE);
172176 return Lambda;
173177 }
178+ if (auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
179+ E = TempExpr->getSubExpr ()->IgnoreParenCasts ();
180+ if (auto *Lambda = dyn_cast<LambdaExpr>(E)) {
181+ ConstructToIgnore.insert (CE);
182+ return Lambda;
183+ }
184+ }
174185 auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
175186 if (!DRE)
176187 return nullptr ;
@@ -216,9 +227,68 @@ class UncountedLambdaCapturesChecker
216227 return ;
217228 DeclRefExprsToIgnore.insert (ArgRef);
218229 LambdasToIgnore.insert (L);
219- Checker->visitLambdaExpr (L, shouldCheckThis (),
230+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) ,
220231 /* ignoreParamVarDecl */ true );
221232 }
233+
234+ bool hasProtectedThis (LambdaExpr *L) {
235+ for (const LambdaCapture &OtherCapture : L->captures ()) {
236+ if (!OtherCapture.capturesVariable ())
237+ continue ;
238+ if (auto *ValueDecl = OtherCapture.getCapturedVar ()) {
239+ if (declProtectsThis (ValueDecl)) {
240+ ProtectedThisDecls.insert (ValueDecl);
241+ return true ;
242+ }
243+ }
244+ }
245+ return false ;
246+ }
247+
248+ bool declProtectsThis (const ValueDecl *ValueDecl) const {
249+ auto *VD = dyn_cast<VarDecl>(ValueDecl);
250+ if (!VD)
251+ return false ;
252+ auto *Init = VD->getInit ()->IgnoreParenCasts ();
253+ if (!Init)
254+ return false ;
255+ const Expr *Arg = Init;
256+ do {
257+ if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
258+ Arg = BTE->getSubExpr ()->IgnoreParenCasts ();
259+ if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(Arg)) {
260+ auto *Ctor = CE->getConstructor ();
261+ if (!Ctor)
262+ return false ;
263+ auto clsName = safeGetName (Ctor->getParent ());
264+ if (!isRefType (clsName) || !CE->getNumArgs ())
265+ return false ;
266+ Arg = CE->getArg (0 )->IgnoreParenCasts ();
267+ continue ;
268+ }
269+ if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
270+ auto OpCode = OpCE->getOperator ();
271+ if (OpCode == OO_Star || OpCode == OO_Amp) {
272+ auto *Callee = OpCE->getDirectCallee ();
273+ auto clsName = safeGetName (Callee->getParent ());
274+ if (!isRefType (clsName) || !OpCE->getNumArgs ())
275+ return false ;
276+ Arg = OpCE->getArg (0 )->IgnoreParenCasts ();
277+ continue ;
278+ }
279+ }
280+ if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
281+ auto OpCode = UO->getOpcode ();
282+ if (OpCode == UO_Deref || OpCode == UO_AddrOf)
283+ Arg = UO->getSubExpr ()->IgnoreParenCasts ();
284+ continue ;
285+ }
286+ break ;
287+ } while (Arg);
288+ if (auto *DRE = dyn_cast<DeclRefExpr>(Arg))
289+ return ProtectedThisDecls.contains (DRE->getDecl ());
290+ return isa<CXXThisExpr>(Arg);
291+ }
222292 };
223293
224294 LocalVisitor visitor (this );
@@ -241,53 +311,11 @@ class UncountedLambdaCapturesChecker
241311 } else if (C.capturesThis () && shouldCheckThis) {
242312 if (ignoreParamVarDecl) // this is always a parameter to this function.
243313 continue ;
244- bool hasProtectThis = false ;
245- for (const LambdaCapture &OtherCapture : L->captures ()) {
246- if (!OtherCapture.capturesVariable ())
247- continue ;
248- if (auto *ValueDecl = OtherCapture.getCapturedVar ()) {
249- if (protectThis (ValueDecl)) {
250- hasProtectThis = true ;
251- break ;
252- }
253- }
254- }
255- if (!hasProtectThis)
256- reportBugOnThisPtr (C);
314+ reportBugOnThisPtr (C);
257315 }
258316 }
259317 }
260318
261- bool protectThis (const ValueDecl *ValueDecl) const {
262- auto *VD = dyn_cast<VarDecl>(ValueDecl);
263- if (!VD)
264- return false ;
265- auto *Init = VD->getInit ()->IgnoreParenCasts ();
266- if (!Init)
267- return false ;
268- auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Init);
269- if (!BTE)
270- return false ;
271- auto *CE = dyn_cast_or_null<CXXConstructExpr>(BTE->getSubExpr ());
272- if (!CE)
273- return false ;
274- auto *Ctor = CE->getConstructor ();
275- if (!Ctor)
276- return false ;
277- auto clsName = safeGetName (Ctor->getParent ());
278- if (!isRefType (clsName) || !CE->getNumArgs ())
279- return false ;
280- auto *Arg = CE->getArg (0 )->IgnoreParenCasts ();
281- while (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
282- auto OpCode = UO->getOpcode ();
283- if (OpCode == UO_Deref || OpCode == UO_AddrOf)
284- Arg = UO->getSubExpr ();
285- else
286- break ;
287- }
288- return isa<CXXThisExpr>(Arg);
289- }
290-
291319 void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
292320 const QualType T) const {
293321 assert (CapturedVar);
0 commit comments