@@ -41,7 +41,9 @@ class UncountedLambdaCapturesChecker
41
41
const UncountedLambdaCapturesChecker *Checker;
42
42
llvm::DenseSet<const DeclRefExpr *> DeclRefExprsToIgnore;
43
43
llvm::DenseSet<const LambdaExpr *> LambdasToIgnore;
44
+ llvm::DenseSet<const ValueDecl *> ProtectedThisDecls;
44
45
llvm::DenseSet<const CXXConstructExpr *> ConstructToIgnore;
46
+
45
47
QualType ClsType;
46
48
47
49
using Base = RecursiveASTVisitor<LocalVisitor>;
@@ -69,7 +71,7 @@ class UncountedLambdaCapturesChecker
69
71
bool VisitLambdaExpr (LambdaExpr *L) {
70
72
if (LambdasToIgnore.contains (L))
71
73
return true ;
72
- Checker->visitLambdaExpr (L, shouldCheckThis ());
74
+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) );
73
75
return true ;
74
76
}
75
77
@@ -97,7 +99,7 @@ class UncountedLambdaCapturesChecker
97
99
if (!L)
98
100
return true ;
99
101
LambdasToIgnore.insert (L);
100
- Checker->visitLambdaExpr (L, shouldCheckThis ());
102
+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) );
101
103
return true ;
102
104
}
103
105
@@ -122,7 +124,8 @@ class UncountedLambdaCapturesChecker
122
124
if (auto *L = findLambdaInArg (Arg)) {
123
125
LambdasToIgnore.insert (L);
124
126
if (!Param->hasAttr <NoEscapeAttr>())
125
- Checker->visitLambdaExpr (L, shouldCheckThis ());
127
+ Checker->visitLambdaExpr (L, shouldCheckThis () &&
128
+ !hasProtectedThis (L));
126
129
}
127
130
++ArgIndex;
128
131
}
@@ -142,7 +145,8 @@ class UncountedLambdaCapturesChecker
142
145
if (auto *L = findLambdaInArg (Arg)) {
143
146
LambdasToIgnore.insert (L);
144
147
if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
145
- Checker->visitLambdaExpr (L, shouldCheckThis ());
148
+ Checker->visitLambdaExpr (L, shouldCheckThis () &&
149
+ !hasProtectedThis (L));
146
150
}
147
151
++ArgIndex;
148
152
}
@@ -171,6 +175,13 @@ class UncountedLambdaCapturesChecker
171
175
ConstructToIgnore.insert (CE);
172
176
return Lambda;
173
177
}
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
+ }
174
185
auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
175
186
if (!DRE)
176
187
return nullptr ;
@@ -216,9 +227,68 @@ class UncountedLambdaCapturesChecker
216
227
return ;
217
228
DeclRefExprsToIgnore.insert (ArgRef);
218
229
LambdasToIgnore.insert (L);
219
- Checker->visitLambdaExpr (L, shouldCheckThis (),
230
+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) ,
220
231
/* ignoreParamVarDecl */ true );
221
232
}
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
+ }
222
292
};
223
293
224
294
LocalVisitor visitor (this );
@@ -241,53 +311,11 @@ class UncountedLambdaCapturesChecker
241
311
} else if (C.capturesThis () && shouldCheckThis) {
242
312
if (ignoreParamVarDecl) // this is always a parameter to this function.
243
313
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);
257
315
}
258
316
}
259
317
}
260
318
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
-
291
319
void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
292
320
const QualType T) const {
293
321
assert (CapturedVar);
0 commit comments