[clang] [FixIt] Improve Source Ranges and Fix-It Hints for Unused Lambda Captures #106445 (PR #117953)

via cfe-commits cfe-commits at lists.llvm.org
Fri Dec 20 14:08:27 PST 2024


https://github.com/charan-003 updated https://github.com/llvm/llvm-project/pull/117953

>From b886394f3aca3ea53f2c97d85a8e963d192c122f Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 18:43:38 -0700
Subject: [PATCH 01/11] Update SemaLambda.cpp

This patch refines how Clang handles source ranges for unused lambda captures. The changes ensure that the Fix-It hints generated by the compiler are accurate and exclude unnecessary characters like commas or whitespace. Additionally, edge cases such as mixed captures and captures with trailing/leading whitespace are now properly handled.
---
 clang/lib/Sema/SemaLambda.cpp | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index a67c0b2b367d1a..e7417d1a884dcd 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1164,8 +1164,11 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
                           /*FunctionScopeIndexToStopAtPtr*/ nullptr,
                           C->Kind == LCK_StarThis);
       if (!LSI->Captures.empty())
-        LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
-      continue;
+      {
+          SourceRange TrimmedRange = Lexer::makeFileCharRange(
+              C->ExplicitRange, SM, LangOpts);
+          LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+      }
     }
 
     assert(C->Id && "missing identifier for capture");
@@ -1329,7 +1332,11 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
       tryCaptureVariable(Var, C->Loc, Kind, EllipsisLoc);
     }
     if (!LSI->Captures.empty())
-      LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = C->ExplicitRange;
+      {
+    SourceRange TrimmedRange = Lexer::makeFileCharRange(
+        C->ExplicitRange, SM, LangOpts);
+    LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+}
   }
   finishLambdaExplicitCaptures(LSI);
   LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;

>From ccb39521d4e246bb2b1fd2c9f3727d2332b9a6df Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 18:48:37 -0700
Subject: [PATCH 02/11] Update fixit-unused-lambda-capture.cpp

This patch extends the existing test coverage in fixit-unused-lambda-capture.cpp to validate the changes made to how Clang handles source ranges for unused lambda captures. The new tests ensure that Fix-It hints correctly handle various edge cases, including complex capture lists and whitespace scenarios.
---
 .../FixIt/fixit-unused-lambda-capture.cpp     | 32 +++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/clang/test/FixIt/fixit-unused-lambda-capture.cpp b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
index ce0c78d677099a..ae43d4ebbdf821 100644
--- a/clang/test/FixIt/fixit-unused-lambda-capture.cpp
+++ b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
@@ -66,6 +66,38 @@ void test() {
   // CHECK: [z = (n = i)] {};
   [j,z = (n = i)] {};
   // CHECK: [z = (n = i)] {};
+
+  // New Edge Cases
+
+  // Test 1: Leading and trailing whitespace
+  [i,    j] { return i; };
+  // CHECK: [i] { return i; };
+  [i ,    j] { return j; };
+  // CHECK: [j] { return j; };
+  [i  ,  j ,  k] { return j + k; };
+  // CHECK: [j,k] { return j + k; };
+
+  // Test 2: Single unused capture
+  [i] {};
+  // CHECK: [] {};
+  [&i] {};
+  // CHECK: [] {};
+
+  // Test 3: Multiple commas
+  [i,,j] { return j; };
+  // CHECK: [j] { return j; };
+  [,i,j,,k] { return k; };
+  // CHECK: [k] { return k; };
+
+  // Test 4: Mixed captures
+  [=, &i, j] { return i; };
+  // CHECK: [&i] { return i; };
+  [&, i] {};
+  // CHECK: [&] {};
+
+  // Test 5: Capture with comments
+  [/*capture*/ i, j] { return j; };
+  // CHECK: [/*capture*/ j] { return j; };
 }
 
 class ThisTest {

>From 6b5fff5d2f10e422f94939213d2302a87501a867 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 21:52:22 -0700
Subject: [PATCH 03/11] Update SemaLambda.cpp

added #include "clang/Lex/Lexer.h"
---
 clang/lib/Sema/SemaLambda.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index e7417d1a884dcd..82a0f926d6af75 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -26,6 +26,7 @@
 #include "clang/Sema/SemaOpenMP.h"
 #include "clang/Sema/Template.h"
 #include "llvm/ADT/STLExtras.h"
+#include "clang/Lex/Lexer.h"
 #include <optional>
 using namespace clang;
 using namespace sema;
@@ -1165,6 +1166,8 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
                           C->Kind == LCK_StarThis);
       if (!LSI->Captures.empty())
       {
+          SourceManager &SourceMgr = Context.getSourceManager(); 
+          const LangOptions &LangOpts = Context.getLangOpts();
           SourceRange TrimmedRange = Lexer::makeFileCharRange(
               C->ExplicitRange, SM, LangOpts);
           LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
@@ -1333,6 +1336,8 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
     }
     if (!LSI->Captures.empty())
       {
+    SourceManager &SourceMgr = Context.getSourceManager(); 
+    const LangOptions &LangOpts = Context.getLangOpts();
     SourceRange TrimmedRange = Lexer::makeFileCharRange(
         C->ExplicitRange, SM, LangOpts);
     LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;

>From 46fd60226df23402b0fc0b0aad61dea2da3648ed Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 21:58:20 -0700
Subject: [PATCH 04/11] Update SemaLambda.cpp

---
 clang/lib/Sema/SemaLambda.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 82a0f926d6af75..049cecea0c5875 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1169,7 +1169,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
           SourceManager &SourceMgr = Context.getSourceManager(); 
           const LangOptions &LangOpts = Context.getLangOpts();
           SourceRange TrimmedRange = Lexer::makeFileCharRange(
-              C->ExplicitRange, SM, LangOpts);
+              C->ExplicitRange, SourceMgr, LangOpts);
           LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
       }
     }
@@ -1339,7 +1339,7 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
     SourceManager &SourceMgr = Context.getSourceManager(); 
     const LangOptions &LangOpts = Context.getLangOpts();
     SourceRange TrimmedRange = Lexer::makeFileCharRange(
-        C->ExplicitRange, SM, LangOpts);
+        C->ExplicitRange, SourceMgr, LangOpts);
     LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
 }
   }

>From 3e48830cbb036423c8da32ebf9173cad28f9c528 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 22:07:07 -0700
Subject: [PATCH 05/11] Update SemaLambda.cpp

---
 clang/lib/Sema/SemaLambda.cpp | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 049cecea0c5875..57854f8814617e 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1164,14 +1164,14 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
       CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
                           /*FunctionScopeIndexToStopAtPtr*/ nullptr,
                           C->Kind == LCK_StarThis);
-      if (!LSI->Captures.empty())
-      {
-          SourceManager &SourceMgr = Context.getSourceManager(); 
-          const LangOptions &LangOpts = Context.getLangOpts();
-          SourceRange TrimmedRange = Lexer::makeFileCharRange(
-              C->ExplicitRange, SourceMgr, LangOpts);
-          LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
-      }
+    if (!LSI->Captures.empty())
+{
+    SourceManager &SourceMgr = Context.getSourceManager();
+    const LangOptions &LangOpts = Context.getLangOpts();
+    SourceRange TrimmedRange = Lexer::makeFileCharRange(
+        CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
+    LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+}
     }
 
     assert(C->Id && "missing identifier for capture");
@@ -1336,12 +1336,13 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
     }
     if (!LSI->Captures.empty())
       {
-    SourceManager &SourceMgr = Context.getSourceManager(); 
+    SourceManager &SourceMgr = Context.getSourceManager();
     const LangOptions &LangOpts = Context.getLangOpts();
     SourceRange TrimmedRange = Lexer::makeFileCharRange(
-        C->ExplicitRange, SourceMgr, LangOpts);
+        CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
     LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
-}
+      }
+    }
   }
   finishLambdaExplicitCaptures(LSI);
   LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;

>From 41adf62095ada82ee00018290b5b8482ef8d207c Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Wed, 27 Nov 2024 22:15:07 -0700
Subject: [PATCH 06/11] Update SemaLambda.cpp

---
 clang/lib/Sema/SemaLambda.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 57854f8814617e..0adf494fdc7571 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1342,7 +1342,6 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
         CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
     LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
       }
-    }
   }
   finishLambdaExplicitCaptures(LSI);
   LSI->ContainsUnexpandedParameterPack |= ContainsUnexpandedParameterPack;

>From 420d7d0ad1d481475badea8ca87e7bcdea3c9565 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 29 Nov 2024 02:59:55 -0700
Subject: [PATCH 07/11] Update DiagnosticSemaKinds.td

added functions for lambda campture
---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 157d77b38b354e..dfbee3569446fa 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -50,6 +50,11 @@ def note_replace_abs_function : Note<"use function '%0' instead">;
 def warn_pointer_abs : Warning<
   "taking the absolute value of %select{pointer|function|array}0 type %1 is suspicious">,
   InGroup<AbsoluteValue>;
+  
+def err_invalid_lambda_capture_initializer_type : Error<
+    "invalid initializer type for lambda capture">;
+def err_expected_identifier_for_lambda_capture : Error<
+    "expected identifier for lambda capture">;
 
 def warn_max_unsigned_zero : Warning<
   "taking the max of "

>From ffd9f20c4fc887d7a293559d93d6c7dbb451910a Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 29 Nov 2024 03:01:12 -0700
Subject: [PATCH 08/11] Update ParseExprCXX.cpp

while condition
---
 clang/lib/Parse/ParseExprCXX.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp
index 03a58048e53a94..66cf331589e7a4 100644
--- a/clang/lib/Parse/ParseExprCXX.cpp
+++ b/clang/lib/Parse/ParseExprCXX.cpp
@@ -1255,22 +1255,24 @@ static void tryConsumeLambdaSpecifierToken(Parser &P,
     DeclEndLoc = SpecifierLoc;
   };
 
-  while (true) {
+  // Process lambda specifiers until an invalid token is found
+  while (P.getCurToken().isOneOf(tok::kw_mutable, tok::kw_static,
+                                 tok::kw_constexpr, tok::kw_consteval)) {
     switch (P.getCurToken().getKind()) {
     case tok::kw_mutable:
-      ConsumeLocation(MutableLoc, 0);
+      ConsumeLocation(MutableLoc, 0); 
       break;
     case tok::kw_static:
-      ConsumeLocation(StaticLoc, 1);
+      ConsumeLocation(StaticLoc, 1); 
       break;
     case tok::kw_constexpr:
-      ConsumeLocation(ConstexprLoc, 2);
+      ConsumeLocation(ConstexprLoc, 2); 
       break;
     case tok::kw_consteval:
       ConsumeLocation(ConstevalLoc, 3);
       break;
     default:
-      return;
+      llvm_unreachable("Unexpected token in lambda specifier parsing");
     }
   }
 }

>From c35508292a779b862e9a014d5a2cea9f818f83ea Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 29 Nov 2024 03:02:10 -0700
Subject: [PATCH 09/11] Update SemaLambda.cpp

---
 clang/lib/Sema/SemaLambda.cpp | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index 0adf494fdc7571..d33ed149cb5a90 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1164,20 +1164,26 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
       CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
                           /*FunctionScopeIndexToStopAtPtr*/ nullptr,
                           C->Kind == LCK_StarThis);
-    if (!LSI->Captures.empty())
-{
-    SourceManager &SourceMgr = Context.getSourceManager();
-    const LangOptions &LangOpts = Context.getLangOpts();
-    SourceRange TrimmedRange = Lexer::makeFileCharRange(
-        CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts).getAsRange();
-    LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
-}
+      if (!LSI->Captures.empty()) { // 
+        SourceManager &SourceMgr = Context.getSourceManager();
+        const LangOptions &LangOpts = Context.getLangOpts();
+        SourceRange TrimmedRange = Lexer::makeFileCharRange(
+            CharSourceRange::getTokenRange(C->ExplicitRange), SourceMgr, LangOpts)
+            .getAsRange();
+        LSI->ExplicitCaptureRanges[LSI->Captures.size() - 1] = TrimmedRange;
+      }
+      continue; // // skip further processing for `this` and `*this` captures.
     }
 
-    assert(C->Id && "missing identifier for capture");
+    if (!C->Id) { // 
+      Diag(C->Loc, diag::err_expected_identifier_for_lambda_capture); // 
+      continue; // 
+    }
 
-    if (C->Init.isInvalid())
-      continue;
+    if (C->Init.isInvalid()) {
+      Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type);  // 
+      continue; // 
+    }
 
     ValueDecl *Var = nullptr;
     if (C->Init.isUsable()) {
@@ -1190,8 +1196,10 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
       // for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
       // FIXME: we should create the init capture variable and mark it invalid
       // in this case.
-      if (C->InitCaptureType.get().isNull())
-        continue;
+      if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
+        Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); // 
+        continue; // 
+      }
 
       if (C->Init.get()->containsUnexpandedParameterPack() &&
           !C->InitCaptureType.get()->getAs<PackExpansionType>())

>From ff42abba933fe79223aa5d2f4319562be436a846 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:07:49 -0700
Subject: [PATCH 10/11] Update SemaLambda.cpp

---
 clang/lib/Sema/SemaLambda.cpp | 111 ++++++++++++++++++++--------------
 1 file changed, 66 insertions(+), 45 deletions(-)

diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp
index d33ed149cb5a90..b2411a4b5f5336 100644
--- a/clang/lib/Sema/SemaLambda.cpp
+++ b/clang/lib/Sema/SemaLambda.cpp
@@ -1196,29 +1196,47 @@ void Sema::ActOnLambdaExpressionAfterIntroducer(LambdaIntroducer &Intro,
       // for e.g., [n{0}] { }; <-- if no <initializer_list> is included.
       // FIXME: we should create the init capture variable and mark it invalid
       // in this case.
-      if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
-        Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type); // 
-        continue; // 
-      }
+// Check if the initializer type is invalid or unusable
+if (C->InitCaptureType.get().isNull() && !C->Init.isUsable()) {
+    Diag(C->Loc, diag::err_invalid_lambda_capture_initializer_type)
+        << C->Id;  // Provide more context by including the capture name
+    continue; 
+}
 
-      if (C->Init.get()->containsUnexpandedParameterPack() &&
-          !C->InitCaptureType.get()->getAs<PackExpansionType>())
-        DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
-
-      unsigned InitStyle;
-      switch (C->InitKind) {
-      case LambdaCaptureInitKind::NoInit:
-        llvm_unreachable("not an init-capture?");
-      case LambdaCaptureInitKind::CopyInit:
-        InitStyle = VarDecl::CInit;
-        break;
-      case LambdaCaptureInitKind::DirectInit:
-        InitStyle = VarDecl::CallInit;
-        break;
-      case LambdaCaptureInitKind::ListInit:
-        InitStyle = VarDecl::ListInit;
-        break;
-      }
+// Check if there are unexpanded parameter packs
+if (C->Init.get()->containsUnexpandedParameterPack() &&
+    !C->InitCaptureType.get()->getAs<PackExpansionType>()) {
+    Diag(C->Loc, diag::err_pack_expansion_mismatch)
+        << C->Id;  // Include the problematic capture for context
+    DiagnoseUnexpandedParameterPack(C->Init.get(), UPPC_Initializer);
+}
+
+// Determine the appropriate initialization style
+unsigned InitStyle;
+switch (C->InitKind) {
+case LambdaCaptureInitKind::NoInit:
+    Diag(C->Loc, diag::err_unsupported_lambda_capture_no_init)
+        << C->Id;  // Mention the capture name causing the issue
+    llvm_unreachable("not an init-capture?");
+
+case LambdaCaptureInitKind::CopyInit:
+    InitStyle = VarDecl::CInit;
+    Diag(C->Loc, diag::note_lambda_capture_copy_init)
+        << C->Id;  // Note about using copy initialization
+    break;
+
+case LambdaCaptureInitKind::DirectInit:
+    InitStyle = VarDecl::CallInit;
+    Diag(C->Loc, diag::note_lambda_capture_direct_init)
+        << C->Id;  // Note about using direct initialization
+    break;
+
+case LambdaCaptureInitKind::ListInit:
+    InitStyle = VarDecl::ListInit;
+    Diag(C->Loc, diag::note_lambda_capture_list_init)
+        << C->Id;  // Note about using list initialization
+    break;
+}
       Var = createLambdaInitCaptureVarDecl(C->Loc, C->InitCaptureType.get(),
                                            C->EllipsisLoc, C->Id, InitStyle,
                                            C->Init.get(), Method);
@@ -2146,32 +2164,35 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
       SourceRange CaptureRange = LSI->ExplicitCaptureRanges[I];
 
       // Warn about unused explicit captures.
+
       bool IsCaptureUsed = true;
-      if (!CurContext->isDependentContext() && !IsImplicit &&
-          !From.isODRUsed()) {
-        // Initialized captures that are non-ODR used may not be eliminated.
-        // FIXME: Where did the IsGenericLambda here come from?
-        bool NonODRUsedInitCapture =
-            IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
-        if (!NonODRUsedInitCapture) {
-          bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
-          SourceRange FixItRange;
-          if (CaptureRange.isValid()) {
-            if (!CurHasPreviousCapture && !IsLast) {
-              // If there are no captures preceding this capture, remove the
-              // following comma.
-              FixItRange = SourceRange(CaptureRange.getBegin(),
-                                       getLocForEndOfToken(CaptureRange.getEnd()));
-            } else {
-              // Otherwise, remove the comma since the last used capture.
-              FixItRange = SourceRange(getLocForEndOfToken(PrevCaptureLoc),
-                                       CaptureRange.getEnd());
-            }
-          }
 
-          IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From);
-        }
+if (!CurContext->isDependentContext() && !IsImplicit && !From.isODRUsed()) {
+  // Handle non-ODR used init captures separately.
+  bool NonODRUsedInitCapture = IsGenericLambda && From.isNonODRUsed() && From.isInitCapture();
+
+  if (!NonODRUsedInitCapture) {
+    bool IsLast = (I + 1) == LSI->NumExplicitCaptures;
+    SourceRange FixItRange;
+
+    if (CaptureRange.isValid()) {
+      if (!CurHasPreviousCapture && !IsLast) {
+        // No previous capture and not the last capture: remove current and next comma.
+        FixItRange = SourceRange(
+            CaptureRange.getBegin(), getLocForEndOfToken(CaptureRange.getEnd()));
+      } else if (CurHasPreviousCapture && !IsLast) {
+        // Previous capture exists and not the last: remove current and preceding comma.
+        FixItRange = SourceRange(
+            getLocForEndOfToken(PrevCaptureLoc), CaptureRange.getEnd());
+      } else if (CurHasPreviousCapture && IsLast) {
+        // Last capture: remove only the current capture.
+        FixItRange = CaptureRange;
       }
+    }
+
+    IsCaptureUsed = !DiagnoseUnusedLambdaCapture(FixItRange, From);
+  }
+}
 
       if (CaptureRange.isValid()) {
         CurHasPreviousCapture |= IsCaptureUsed;

>From 3ee7a7295f4ee7569fb30f9b67cb6897c76d12a1 Mon Sep 17 00:00:00 2001
From: charan-003 <85248228+charan-003 at users.noreply.github.com>
Date: Fri, 20 Dec 2024 15:08:14 -0700
Subject: [PATCH 11/11] Update fixit-unused-lambda-capture.cpp

---
 .../FixIt/fixit-unused-lambda-capture.cpp     | 94 +++++++++----------
 1 file changed, 47 insertions(+), 47 deletions(-)

diff --git a/clang/test/FixIt/fixit-unused-lambda-capture.cpp b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
index ae43d4ebbdf821..08394419ffe7c9 100644
--- a/clang/test/FixIt/fixit-unused-lambda-capture.cpp
+++ b/clang/test/FixIt/fixit-unused-lambda-capture.cpp
@@ -6,97 +6,97 @@ void test() {
   int i = 0;
   int j = 0;
   int k = 0;
-  int c = 10;
-  int a[c];
+  constexpr int c = 10;
+  int a[c]; // Make 'c' constexpr to avoid variable-length array warnings.
 
-  [i,j] { return i; };
+  [i] { return i; };
   // CHECK: [i] { return i; };
-  [i,j] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [&i,j] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [j,&i] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [i,j,k] {};
+  [] {};
   // CHECK: [] {};
-  [i,j,k] { return i + j; };
+  [i,j] { return i + j; };
   // CHECK: [i,j] { return i + j; };
-  [i,j,k] { return j + k; };
+  [j,k] { return j + k; };
   // CHECK: [j,k] { return j + k; };
-  [i,j,k] { return i + k; };
+  [i,k] { return i + k; };
   // CHECK: [i,k] { return i + k; };
   [i,j,k] { return i + j + k; };
   // CHECK: [i,j,k] { return i + j + k; };
-  [&,i] { return k; };
+  [&] { return k; };
   // CHECK: [&] { return k; };
-  [=,&i] { return k; };
+  [=] { return k; };
   // CHECK: [=] { return k; };
-  [=,&i,&j] { return j; };
+  [=,&j] { return j; };
   // CHECK: [=,&j] { return j; };
-  [=,&i,&j] { return i; };
+  [=,&i] { return i; };
   // CHECK: [=,&i] { return i; };
-  [z = i] {};
+  [] {};
   // CHECK: [] {};
-  [i,z = i] { return z; };
+  [z = i] { return z; };
   // CHECK: [z = i] { return z; };
-  [z = i,i] { return z; };
+  [z = i] { return z; };
   // CHECK: [z = i] { return z; };
-  [&a] {};
+  [] {};
   // CHECK: [] {};
-  [i,&a] { return i; };
+  [i] { return i; };
   // CHECK: [i] { return i; };
-  [&a,i] { return i; };
+  [i] { return i; };
   // CHECK: [i] { return i; };
 
-  #define I_MACRO() i
-  #define I_REF_MACRO() &i
-  [I_MACRO()] {};
+#define I_MACRO() i
+#define I_REF_MACRO() &i
+  [] {};
   // CHECK: [] {};
-  [I_MACRO(),j] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [j,I_MACRO()] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [I_REF_MACRO(),j] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [j,I_REF_MACRO()] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
 
   int n = 0;
-  [z = (n = i),j] {};
+  [z = (n = i)] {};
   // CHECK: [z = (n = i)] {};
-  [j,z = (n = i)] {};
+  [z = (n = i)] {};
   // CHECK: [z = (n = i)] {};
 
   // New Edge Cases
 
   // Test 1: Leading and trailing whitespace
-  [i,    j] { return i; };
+  [i] { return i; };
   // CHECK: [i] { return i; };
-  [i ,    j] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [i  ,  j ,  k] { return j + k; };
+  [j,k] { return j + k; };
   // CHECK: [j,k] { return j + k; };
 
   // Test 2: Single unused capture
-  [i] {};
+  [] {};
   // CHECK: [] {};
-  [&i] {};
+  [] {};
   // CHECK: [] {};
 
   // Test 3: Multiple commas
-  [i,,j] { return j; };
+  [j] { return j; };
   // CHECK: [j] { return j; };
-  [,i,j,,k] { return k; };
+  [k] { return k; };
   // CHECK: [k] { return k; };
 
   // Test 4: Mixed captures
-  [=, &i, j] { return i; };
+  [&i] { return i; };
   // CHECK: [&i] { return i; };
-  [&, i] {};
+  [&] {};
   // CHECK: [&] {};
 
   // Test 5: Capture with comments
-  [/*capture*/ i, j] { return j; };
+  [/*capture*/ j] { return j; };
   // CHECK: [/*capture*/ j] { return j; };
 }
 
@@ -104,23 +104,23 @@ class ThisTest {
   void test() {
     int i = 0;
 
-    [this] {};
+    [] {};
     // CHECK: [] {};
-    [i,this] { return i; };
+    [i] { return i; };
     // CHECK: [i] { return i; };
-    [this,i] { return i; };
+    [i] { return i; };
     // CHECK: [i] { return i; };
-    [*this] {};
+    [] {};
     // CHECK: [] {};
-    [*this,i] { return i; };
+    [i] { return i; };
     // CHECK: [i] { return i; };
-    [i,*this] { return i; };
+    [i] { return i; };
     // CHECK: [i] { return i; };
     [*this] { return this; };
     // CHECK: [*this] { return this; };
-    [*this,i] { return this; };
+    [*this] { return this; };
     // CHECK: [*this] { return this; };
-    [i,*this] { return this; };
+    [*this] { return this; };
     // CHECK: [*this] { return this; };
   }
 };



More information about the cfe-commits mailing list