@@ -223,6 +223,21 @@ void UseStructuredBindingCheck::registerMatchers(MatchFinder *Finder) {
223
223
return declRefExpr (to (varDecl (UnlessShouldBeIgnored).bind (Name)));
224
224
};
225
225
226
+ auto HasAnyLambdaCaptureThisVar =
227
+ [](ast_matchers::internal::Matcher<VarDecl> VDMatcher)
228
+ -> ast_matchers::internal::BindableMatcher<Stmt> {
229
+ return compoundStmt (hasDescendant (
230
+ lambdaExpr (hasAnyCapture (capturesVar (varDecl (VDMatcher))))));
231
+ };
232
+
233
+ // Captured structured bindings are a C++20 extension
234
+ auto UnlessFirstVarOrSecondVarIsCapturedByLambda =
235
+ getLangOpts ().CPlusPlus20
236
+ ? compoundStmt ()
237
+ : compoundStmt (unless (HasAnyLambdaCaptureThisVar (
238
+ anyOf (equalsBoundNode (std::string (FirstVarDeclName)),
239
+ equalsBoundNode (std::string (SecondVarDeclName))))));
240
+
226
241
// X x;
227
242
// Y y;
228
243
// std::tie(x, y) = ...;
@@ -243,7 +258,8 @@ void UseStructuredBindingCheck::registerMatchers(MatchFinder *Finder) {
243
258
llvm::SmallVector<ast_matchers::internal::Matcher<VarDecl>>{
244
259
varDecl (equalsBoundNode (std::string (FirstVarDeclName))),
245
260
varDecl (equalsBoundNode (std::string (SecondVarDeclName)))}),
246
- hasParent (compoundStmt ().bind (ScopeBlockName))),
261
+ hasParent (compoundStmt (UnlessFirstVarOrSecondVarIsCapturedByLambda)
262
+ .bind (ScopeBlockName))),
247
263
this );
248
264
249
265
// pair<X, Y> p = ...;
@@ -262,7 +278,8 @@ void UseStructuredBindingCheck::registerMatchers(MatchFinder *Finder) {
262
278
hasNextTwoVarDecl (
263
279
llvm::SmallVector<ast_matchers::internal::Matcher<VarDecl>>{
264
280
VarInitWithFirstMember, VarInitWithSecondMember}),
265
- hasParent (compoundStmt ().bind (ScopeBlockName))),
281
+ hasParent (compoundStmt (UnlessFirstVarOrSecondVarIsCapturedByLambda)
282
+ .bind (ScopeBlockName))),
266
283
this );
267
284
268
285
// for (pair<X, Y> p : map) {
@@ -282,7 +299,8 @@ void UseStructuredBindingCheck::registerMatchers(MatchFinder *Finder) {
282
299
compoundStmt (
283
300
hasFirstTwoVarDecl (llvm::SmallVector<
284
301
ast_matchers::internal::Matcher<VarDecl>>{
285
- VarInitWithFirstMember, VarInitWithSecondMember}))
302
+ VarInitWithFirstMember, VarInitWithSecondMember}),
303
+ UnlessFirstVarOrSecondVarIsCapturedByLambda)
286
304
.bind (ScopeBlockName)))
287
305
.bind (ForRangeStmtName),
288
306
this );
@@ -317,17 +335,6 @@ void UseStructuredBindingCheck::check(const MatchFinder::MatchResult &Result) {
317
335
const auto *EndDS = Result.Nodes .getNodeAs <DeclStmt>(EndDeclStmtName);
318
336
const auto *ScopeBlock = Result.Nodes .getNodeAs <CompoundStmt>(ScopeBlockName);
319
337
320
- // Captured structured bindings are a C++20 extension
321
- if (!Result.Context ->getLangOpts ().CPlusPlus20 ) {
322
- if (auto Matchers = match (
323
- compoundStmt (
324
- hasDescendant (lambdaExpr (hasAnyCapture (capturesVar (varDecl (
325
- anyOf (equalsNode (FirstVar), equalsNode (SecondVar)))))))),
326
- *ScopeBlock, *Result.Context );
327
- !Matchers.empty ())
328
- return ;
329
- }
330
-
331
338
const auto *CFRS = Result.Nodes .getNodeAs <CXXForRangeStmt>(ForRangeStmtName);
332
339
auto DiagAndFix = [&BeginDS, &EndDS, &FirstVar, &SecondVar, &CFRS,
333
340
this ](SourceLocation DiagLoc, SourceRange ReplaceRange,
0 commit comments