@@ -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
explicit LocalVisitor (const UncountedLambdaCapturesChecker *Checker)
@@ -66,7 +68,7 @@ class UncountedLambdaCapturesChecker
66
68
bool VisitLambdaExpr (LambdaExpr *L) override {
67
69
if (LambdasToIgnore.contains (L))
68
70
return true ;
69
- Checker->visitLambdaExpr (L, shouldCheckThis ());
71
+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) );
70
72
return true ;
71
73
}
72
74
@@ -94,7 +96,7 @@ class UncountedLambdaCapturesChecker
94
96
if (!L)
95
97
return true ;
96
98
LambdasToIgnore.insert (L);
97
- Checker->visitLambdaExpr (L, shouldCheckThis ());
99
+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) );
98
100
return true ;
99
101
}
100
102
@@ -119,7 +121,8 @@ class UncountedLambdaCapturesChecker
119
121
if (auto *L = findLambdaInArg (Arg)) {
120
122
LambdasToIgnore.insert (L);
121
123
if (!Param->hasAttr <NoEscapeAttr>())
122
- Checker->visitLambdaExpr (L, shouldCheckThis ());
124
+ Checker->visitLambdaExpr (L, shouldCheckThis () &&
125
+ !hasProtectedThis (L));
123
126
}
124
127
++ArgIndex;
125
128
}
@@ -139,7 +142,8 @@ class UncountedLambdaCapturesChecker
139
142
if (auto *L = findLambdaInArg (Arg)) {
140
143
LambdasToIgnore.insert (L);
141
144
if (!Param->hasAttr <NoEscapeAttr>() && !TreatAllArgsAsNoEscape)
142
- Checker->visitLambdaExpr (L, shouldCheckThis ());
145
+ Checker->visitLambdaExpr (L, shouldCheckThis () &&
146
+ !hasProtectedThis (L));
143
147
}
144
148
++ArgIndex;
145
149
}
@@ -168,6 +172,13 @@ class UncountedLambdaCapturesChecker
168
172
ConstructToIgnore.insert (CE);
169
173
return Lambda;
170
174
}
175
+ if (auto *TempExpr = dyn_cast<CXXBindTemporaryExpr>(CtorArg)) {
176
+ E = TempExpr->getSubExpr ()->IgnoreParenCasts ();
177
+ if (auto *Lambda = dyn_cast<LambdaExpr>(E)) {
178
+ ConstructToIgnore.insert (CE);
179
+ return Lambda;
180
+ }
181
+ }
171
182
auto *DRE = dyn_cast<DeclRefExpr>(CtorArg);
172
183
if (!DRE)
173
184
return nullptr ;
@@ -213,9 +224,68 @@ class UncountedLambdaCapturesChecker
213
224
return ;
214
225
DeclRefExprsToIgnore.insert (ArgRef);
215
226
LambdasToIgnore.insert (L);
216
- Checker->visitLambdaExpr (L, shouldCheckThis (),
227
+ Checker->visitLambdaExpr (L, shouldCheckThis () && ! hasProtectedThis (L) ,
217
228
/* ignoreParamVarDecl */ true );
218
229
}
230
+
231
+ bool hasProtectedThis (LambdaExpr *L) {
232
+ for (const LambdaCapture &OtherCapture : L->captures ()) {
233
+ if (!OtherCapture.capturesVariable ())
234
+ continue ;
235
+ if (auto *ValueDecl = OtherCapture.getCapturedVar ()) {
236
+ if (declProtectsThis (ValueDecl)) {
237
+ ProtectedThisDecls.insert (ValueDecl);
238
+ return true ;
239
+ }
240
+ }
241
+ }
242
+ return false ;
243
+ }
244
+
245
+ bool declProtectsThis (const ValueDecl *ValueDecl) const {
246
+ auto *VD = dyn_cast<VarDecl>(ValueDecl);
247
+ if (!VD)
248
+ return false ;
249
+ auto *Init = VD->getInit ()->IgnoreParenCasts ();
250
+ if (!Init)
251
+ return false ;
252
+ const Expr *Arg = Init;
253
+ do {
254
+ if (auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Arg))
255
+ Arg = BTE->getSubExpr ()->IgnoreParenCasts ();
256
+ if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(Arg)) {
257
+ auto *Ctor = CE->getConstructor ();
258
+ if (!Ctor)
259
+ return false ;
260
+ auto clsName = safeGetName (Ctor->getParent ());
261
+ if (!isRefType (clsName) || !CE->getNumArgs ())
262
+ return false ;
263
+ Arg = CE->getArg (0 )->IgnoreParenCasts ();
264
+ continue ;
265
+ }
266
+ if (auto *OpCE = dyn_cast<CXXOperatorCallExpr>(Arg)) {
267
+ auto OpCode = OpCE->getOperator ();
268
+ if (OpCode == OO_Star || OpCode == OO_Amp) {
269
+ auto *Callee = OpCE->getDirectCallee ();
270
+ auto clsName = safeGetName (Callee->getParent ());
271
+ if (!isRefType (clsName) || !OpCE->getNumArgs ())
272
+ return false ;
273
+ Arg = OpCE->getArg (0 )->IgnoreParenCasts ();
274
+ continue ;
275
+ }
276
+ }
277
+ if (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
278
+ auto OpCode = UO->getOpcode ();
279
+ if (OpCode == UO_Deref || OpCode == UO_AddrOf)
280
+ Arg = UO->getSubExpr ()->IgnoreParenCasts ();
281
+ continue ;
282
+ }
283
+ break ;
284
+ } while (Arg);
285
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Arg))
286
+ return ProtectedThisDecls.contains (DRE->getDecl ());
287
+ return isa<CXXThisExpr>(Arg);
288
+ }
219
289
};
220
290
221
291
LocalVisitor visitor (this );
@@ -238,53 +308,11 @@ class UncountedLambdaCapturesChecker
238
308
} else if (C.capturesThis () && shouldCheckThis) {
239
309
if (ignoreParamVarDecl) // this is always a parameter to this function.
240
310
continue ;
241
- bool hasProtectThis = false ;
242
- for (const LambdaCapture &OtherCapture : L->captures ()) {
243
- if (!OtherCapture.capturesVariable ())
244
- continue ;
245
- if (auto *ValueDecl = OtherCapture.getCapturedVar ()) {
246
- if (protectThis (ValueDecl)) {
247
- hasProtectThis = true ;
248
- break ;
249
- }
250
- }
251
- }
252
- if (!hasProtectThis)
253
- reportBugOnThisPtr (C);
311
+ reportBugOnThisPtr (C);
254
312
}
255
313
}
256
314
}
257
315
258
- bool protectThis (const ValueDecl *ValueDecl) const {
259
- auto *VD = dyn_cast<VarDecl>(ValueDecl);
260
- if (!VD)
261
- return false ;
262
- auto *Init = VD->getInit ()->IgnoreParenCasts ();
263
- if (!Init)
264
- return false ;
265
- auto *BTE = dyn_cast<CXXBindTemporaryExpr>(Init);
266
- if (!BTE)
267
- return false ;
268
- auto *CE = dyn_cast_or_null<CXXConstructExpr>(BTE->getSubExpr ());
269
- if (!CE)
270
- return false ;
271
- auto *Ctor = CE->getConstructor ();
272
- if (!Ctor)
273
- return false ;
274
- auto clsName = safeGetName (Ctor->getParent ());
275
- if (!isRefType (clsName) || !CE->getNumArgs ())
276
- return false ;
277
- auto *Arg = CE->getArg (0 )->IgnoreParenCasts ();
278
- while (auto *UO = dyn_cast<UnaryOperator>(Arg)) {
279
- auto OpCode = UO->getOpcode ();
280
- if (OpCode == UO_Deref || OpCode == UO_AddrOf)
281
- Arg = UO->getSubExpr ();
282
- else
283
- break ;
284
- }
285
- return isa<CXXThisExpr>(Arg);
286
- }
287
-
288
316
void reportBug (const LambdaCapture &Capture, ValueDecl *CapturedVar,
289
317
const QualType T) const {
290
318
assert (CapturedVar);
0 commit comments