[clang] [clang-tools-extra] [clang-tidy] Add readability-default-lambda-capture (PR #160150)
JJ Marr via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 29 11:41:05 PDT 2025
https://github.com/jjmarr-amd updated https://github.com/llvm/llvm-project/pull/160150
>From 35df1c6ea3af8dbaea2d7049ae79b14ce39f0774 Mon Sep 17 00:00:00 2001
From: JJ Marr <JJ.Marr at amd.com>
Date: Fri, 11 Jul 2025 14:40:57 -0400
Subject: [PATCH 01/29] Bugprone-default-lambda-capture
on-behalf-of: @AMD <JJ.Marr at amd.com>
---
.../bugprone/BugproneTidyModule.cpp | 3 +
.../clang-tidy/bugprone/CMakeLists.txt | 1 +
.../bugprone/DefaultLambdaCaptureCheck.cpp | 35 +++++++
.../bugprone/DefaultLambdaCaptureCheck.h | 26 +++++
clang-tools-extra/docs/ReleaseNotes.rst | 9 ++
.../bugprone/default-lambda-capture.rst | 42 ++++++++
.../docs/clang-tidy/checks/list.rst | 1 +
.../bugprone/default-lambda-capture.cpp | 98 +++++++++++++++++++
8 files changed, 215 insertions(+)
create mode 100644 clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
create mode 100644 clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 491de6acea2b7..db99d57c511b8 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -23,6 +23,7 @@
#include "CopyConstructorInitCheck.h"
#include "CrtpConstructorAccessibilityCheck.h"
#include "DanglingHandleCheck.h"
+#include "DefaultLambdaCaptureCheck.h"
#include "DynamicStaticInitializersCheck.h"
#include "EasilySwappableParametersCheck.h"
#include "EmptyCatchCheck.h"
@@ -134,6 +135,8 @@ class BugproneModule : public ClangTidyModule {
"bugprone-copy-constructor-init");
CheckFactories.registerCheck<DanglingHandleCheck>(
"bugprone-dangling-handle");
+ CheckFactories.registerCheck<DefaultLambdaCaptureCheck>(
+ "bugprone-default-lambda-capture");
CheckFactories.registerCheck<DynamicStaticInitializersCheck>(
"bugprone-dynamic-static-initializers");
CheckFactories.registerCheck<EasilySwappableParametersCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 46bc8efd44bc5..66125c9d22c1c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -19,6 +19,7 @@ add_clang_library(clangTidyBugproneModule STATIC
CopyConstructorInitCheck.cpp
CrtpConstructorAccessibilityCheck.cpp
DanglingHandleCheck.cpp
+ DefaultLambdaCaptureCheck.cpp
DynamicStaticInitializersCheck.cpp
EasilySwappableParametersCheck.cpp
EmptyCatchCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
new file mode 100644
index 0000000000000..6c95fbc984c5a
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -0,0 +1,35 @@
+#include "DefaultLambdaCaptureCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
+ // Match any lambda expression
+ Finder->addMatcher(lambdaExpr().bind("lambda"), this);
+}
+
+void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
+ if (!Lambda)
+ return;
+
+ // Check if lambda has a default capture
+ if (Lambda->getCaptureDefault() == LCD_None)
+ return;
+
+ SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
+ if (DefaultCaptureLoc.isInvalid())
+ return;
+
+ const char *CaptureKind =
+ (Lambda->getCaptureDefault() == LCD_ByCopy) ? "by-copy" : "by-reference";
+
+ diag(DefaultCaptureLoc, "lambda %0 default capture is discouraged; "
+ "prefer to capture specific variables explicitly")
+ << CaptureKind;
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
new file mode 100644
index 0000000000000..ac47c866cfccd
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
@@ -0,0 +1,26 @@
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/** Flags lambdas that use default capture modes
+ *
+ * For the user-facing documentation see:
+ * http://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html
+ */
+class DefaultLambdaCaptureCheck : public ClangTidyCheck {
+public:
+ DefaultLambdaCaptureCheck(StringRef Name, ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context) {}
+ void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+ void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+ std::optional<TraversalKind> getCheckTraversalKind() const override {
+ return TK_IgnoreUnlessSpelledInSource;
+ }
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 7cdff86beeec6..30d0bffb78f39 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -194,6 +194,15 @@ New checks
Finds virtual function overrides with different visibility than the function
in the base class.
+- New :doc:`bugprone-default-lambda-capture
+ <clang-tidy/checks/bugprone/default-lambda-capture>` check.
+
+ Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``)
+ and suggests using explicit captures instead. Default captures can lead to
+ subtle bugs including dangling references with ``[&]``, unnecessary copies
+ with ``[=]``, and make code less maintainable by hiding which variables are
+ actually being captured.
+
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
new file mode 100644
index 0000000000000..026acf9f1894b
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
@@ -0,0 +1,42 @@
+.. title:: clang-tidy - bugprone-default-lambda-capture
+
+bugprone-default-lambda-capture
+===============================
+
+Warns when lambda expressions use default capture modes (``[=]`` or ``[&]``)
+instead of explicitly capturing specific variables. Default captures can make
+code less readable and more error-prone by making it unclear which variables
+are being captured and how.
+
+Implements Item 31 of Effective Modern C++ by Scott Meyers.
+
+Example
+-------
+
+.. code-block:: c++
+
+ void example() {
+ int x = 1;
+ int y = 2;
+
+ // Bad - default capture by copy
+ auto lambda1 = [=]() { return x + y; };
+
+ // Bad - default capture by reference
+ auto lambda2 = [&]() { return x + y; };
+
+ // Good - explicit captures
+ auto lambda3 = [x, y]() { return x + y; };
+ auto lambda4 = [&x, &y]() { return x + y; };
+ }
+
+The check will warn on:
+
+- Default capture by copy: ``[=]``
+- Default capture by reference: ``[&]``
+- Mixed captures with defaults: ``[=, &x]`` or ``[&, x]``
+
+The check will not warn on:
+
+- Explicit captures: ``[x]``, ``[&x]``, ``[x, y]``, ``[this]``
+- Empty capture lists: ``[]``
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index c490d2ece2e0a..cb6254ee36f42 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -91,6 +91,7 @@ Clang-Tidy Checks
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
+ :doc:`bugprone-default-lambda-capture <bugprone/default-lambda-capture>`,
:doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
:doc:`bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters>`,
:doc:`bugprone-empty-catch <bugprone/empty-catch>`,
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
new file mode 100644
index 0000000000000..f820b4c9b8a0e
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
@@ -0,0 +1,98 @@
+// RUN: %check_clang_tidy %s bugprone-default-lambda-capture %t
+
+void test_default_captures() {
+ int value = 42;
+ int another = 10;
+
+ auto lambda1 = [=](int x) { return value + x; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto lambda2 = [&](int x) { return value + x; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto lambda3 = [=, &another](int x) { return value + another + x; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto lambda4 = [&, value](int x) { return value + another + x; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+}
+
+void test_acceptable_captures() {
+ int value = 42;
+ int another = 10;
+
+ auto lambda1 = [value](int x) { return value + x; };
+ auto lambda2 = [&value](int x) { return value + x; };
+ auto lambda3 = [value, another](int x) { return value + another + x; };
+ auto lambda4 = [&value, &another](int x) { return value + another + x; };
+
+ auto lambda5 = [](int x, int y) { return x + y; };
+
+ struct S {
+ int member = 5;
+ void foo() {
+ auto lambda = [this]() { return member; };
+ }
+ };
+}
+
+void test_nested_lambdas() {
+ int outer_var = 1;
+ int middle_var = 2;
+ int inner_var = 3;
+
+ auto outer = [=]() {
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ return inner(10);
+ };
+}
+
+void test_lambda_returns() {
+ int a = 1, b = 2, c = 3;
+
+ auto create_adder = [=](int x) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture
+ };
+
+ auto func1 = [&]() { return a; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto func2 = [=]() { return b; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+}
+
+class TestClass {
+ int member = 42;
+
+public:
+ void test_member_function_lambdas() {
+ int local = 10;
+
+ auto lambda1 = [=]() { return member + local; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto lambda2 = [&]() { return member + local; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+
+ auto lambda3 = [this, local]() { return member + local; };
+ auto lambda4 = [this, &local]() { return member + local; };
+ }
+};
+
+template<typename T>
+void test_template_lambdas() {
+ T value{};
+
+ auto lambda = [=](T x) { return value + x; };
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+}
+
+void instantiate_templates() {
+ test_template_lambdas<int>();
+ test_template_lambdas<double>();
+}
>From 689f95b2ba46d6ca319e0735b5f5474bfc14f999 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 09:58:59 -0400
Subject: [PATCH 02/29] Fix headers
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 8 ++++++++
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.h | 8 ++++++++
2 files changed, 16 insertions(+)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 6c95fbc984c5a..0ee65df4b9860 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#include "DefaultLambdaCaptureCheck.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
index ac47c866cfccd..9af861aaf2e93 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
@@ -1,3 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
>From 9991b9ceda13c036e78c0e95978fe16f0bde5959 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 10:21:44 -0400
Subject: [PATCH 03/29] remove superfluous comments.
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 0ee65df4b9860..6db5cc8fc10bb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -15,7 +15,6 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
- // Match any lambda expression
Finder->addMatcher(lambdaExpr().bind("lambda"), this);
}
@@ -24,7 +23,6 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
if (!Lambda)
return;
- // Check if lambda has a default capture
if (Lambda->getCaptureDefault() == LCD_None)
return;
>From db17a4c5a29faa47c69ddb48edb2b0316287c5bc Mon Sep 17 00:00:00 2001
From: "Marr, J J" <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 10:37:30 -0400
Subject: [PATCH 04/29] add new matcher
on-behalf-of: @AMD <JJ.Marr at amd.com>
---
.../bugprone/DefaultLambdaCaptureCheck.cpp | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 6db5cc8fc10bb..7fc3e571db220 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -14,8 +14,15 @@ using namespace clang::ast_matchers;
namespace clang::tidy::bugprone {
+namespace {
+AST_MATCHER(LambdaExpr, hasDefaultCapture) {
+ return Node.getCaptureDefault() != LCD_None;
+}
+
+} // namespace
+
void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(lambdaExpr().bind("lambda"), this);
+ Finder->addMatcher(lambdaExpr(hasDefaultCapture()).bind("lambda"), this);
}
void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
@@ -23,8 +30,8 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
if (!Lambda)
return;
- if (Lambda->getCaptureDefault() == LCD_None)
- return;
+ // No need to check getCaptureDefault() != LCD_None since our custom matcher
+ // hasDefaultCapture() already ensures this condition
SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
if (DefaultCaptureLoc.isInvalid())
>From 7dcf2162c2a6df4057585e2898bc8feb4536a67c Mon Sep 17 00:00:00 2001
From: "Marr, J J" <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 11:51:27 -0400
Subject: [PATCH 05/29] Replace if with assert
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 7fc3e571db220..4db95101025cc 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -27,11 +27,7 @@ void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
- if (!Lambda)
- return;
-
- // No need to check getCaptureDefault() != LCD_None since our custom matcher
- // hasDefaultCapture() already ensures this condition
+ assert(Lambda);
SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
if (DefaultCaptureLoc.isInvalid())
>From 176d195cc753b3c95b9a82305e1fe1267e181cfa Mon Sep 17 00:00:00 2001
From: "Marr, J J" <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 11:52:40 -0400
Subject: [PATCH 06/29] Remove specific warning type
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../bugprone/DefaultLambdaCaptureCheck.cpp | 8 ++-----
.../bugprone/default-lambda-capture.cpp | 24 +++++++++----------
2 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 4db95101025cc..288feb7853e0b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -33,12 +33,8 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
if (DefaultCaptureLoc.isInvalid())
return;
- const char *CaptureKind =
- (Lambda->getCaptureDefault() == LCD_ByCopy) ? "by-copy" : "by-reference";
-
- diag(DefaultCaptureLoc, "lambda %0 default capture is discouraged; "
- "prefer to capture specific variables explicitly")
- << CaptureKind;
+ diag(DefaultCaptureLoc, "lambda default captures are discouraged; "
+ "prefer to capture specific variables explicitly");
}
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
index f820b4c9b8a0e..010edf11f0a2b 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
@@ -5,16 +5,16 @@ void test_default_captures() {
int another = 10;
auto lambda1 = [=](int x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto lambda2 = [&](int x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto lambda3 = [=, &another](int x) { return value + another + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto lambda4 = [&, value](int x) { return value + another + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
}
void test_acceptable_captures() {
@@ -42,10 +42,10 @@ void test_nested_lambdas() {
int inner_var = 3;
auto outer = [=]() {
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
return inner(10);
};
@@ -55,15 +55,15 @@ void test_lambda_returns() {
int a = 1, b = 2, c = 3;
auto create_adder = [=](int x) {
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture
};
auto func1 = [&]() { return a; };
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto func2 = [=]() { return b; };
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
}
class TestClass {
@@ -74,10 +74,10 @@ class TestClass {
int local = 10;
auto lambda1 = [=]() { return member + local; };
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto lambda2 = [&]() { return member + local; };
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda by-reference default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
auto lambda3 = [this, local]() { return member + local; };
auto lambda4 = [this, &local]() { return member + local; };
@@ -89,7 +89,7 @@ void test_template_lambdas() {
T value{};
auto lambda = [=](T x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda by-copy default capture is discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
}
void instantiate_templates() {
>From 5f23dfff1a8368ebca7c2da691201ea1277ad128 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 12:25:50 -0400
Subject: [PATCH 07/29] Sync documentation to release notes
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../checks/bugprone/default-lambda-capture.rst | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
index 026acf9f1894b..f1fcf3ec52948 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
@@ -3,10 +3,11 @@
bugprone-default-lambda-capture
===============================
-Warns when lambda expressions use default capture modes (``[=]`` or ``[&]``)
-instead of explicitly capturing specific variables. Default captures can make
-code less readable and more error-prone by making it unclear which variables
-are being captured and how.
+ Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``)
+ and suggests using explicit captures instead. Default captures can lead to
+ subtle bugs including dangling references with ``[&]``, unnecessary copies
+ with ``[=]``, and make code less maintainable by hiding which variables are
+ actually being captured.
Implements Item 31 of Effective Modern C++ by Scott Meyers.
>From 4c413327a64669d5254f0d6e343ca5c394701611 Mon Sep 17 00:00:00 2001
From: JJ Marr <jjmarr12 at amd.com>
Date: Mon, 22 Sep 2025 13:00:22 -0400
Subject: [PATCH 08/29] Update
clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
index 9af861aaf2e93..ad48316708b1b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
@@ -16,7 +16,7 @@ namespace clang::tidy::bugprone {
/** Flags lambdas that use default capture modes
*
* For the user-facing documentation see:
- * http://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html
+ * https://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html
*/
class DefaultLambdaCaptureCheck : public ClangTidyCheck {
public:
>From 330dbd8ca5eeed45d63d1a44c15eeb5357a8a4ef Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 13:01:23 -0400
Subject: [PATCH 09/29] Remove superfluous include
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 288feb7853e0b..8f52aeb59ead6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -7,7 +7,6 @@
//===----------------------------------------------------------------------===//
#include "DefaultLambdaCaptureCheck.h"
-#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
>From 31366e6b34dce3ab7e5f24d07f81ad10ecd9b875 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 13:09:55 -0400
Subject: [PATCH 10/29] Fix doc and release notes
on-behalf-of: @amd <JJ.Marr at amd.com>
---
clang-tools-extra/docs/ReleaseNotes.rst | 14 +++++---------
.../checks/bugprone/default-lambda-capture.rst | 10 +++++-----
2 files changed, 10 insertions(+), 14 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 780cf41373128..9d2e8dcad7045 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -167,6 +167,11 @@ New checks
Detects default initialization (to 0) of variables with ``enum`` type where
the enum has no enumerator with value of 0.
+- New :doc:`bugprone-default-lambda-capture
+ <clang-tidy/checks/bugprone/default-lambda-capture>` check.
+
+ Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
+
- New :doc:`bugprone-derived-method-shadowing-base-method
<clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check.
@@ -203,15 +208,6 @@ New checks
Finds virtual function overrides with different visibility than the function
in the base class.
-- New :doc:`bugprone-default-lambda-capture
- <clang-tidy/checks/bugprone/default-lambda-capture>` check.
-
- Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``)
- and suggests using explicit captures instead. Default captures can lead to
- subtle bugs including dangling references with ``[&]``, unnecessary copies
- with ``[=]``, and make code less maintainable by hiding which variables are
- actually being captured.
-
New check aliases
^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
index f1fcf3ec52948..9cedc6276e1b3 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
@@ -3,11 +3,11 @@
bugprone-default-lambda-capture
===============================
- Finds lambda expressions that use default capture modes (``[=]`` or ``[&]``)
- and suggests using explicit captures instead. Default captures can lead to
- subtle bugs including dangling references with ``[&]``, unnecessary copies
- with ``[=]``, and make code less maintainable by hiding which variables are
- actually being captured.
+Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
+
+Default captures can lead to subtle bugs including dangling references with
+``[&]``, unnecessary copies with ``[=]``, and make code less maintainable by
+hiding which variables are actually being captured.
Implements Item 31 of Effective Modern C++ by Scott Meyers.
>From 70df9dff73c3b3de4dcdfbed8b44186ff2000997 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 22 Sep 2025 14:43:19 -0400
Subject: [PATCH 11/29] Fix const
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
index 8f52aeb59ead6..a7a18ccb30864 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
@@ -28,7 +28,7 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
assert(Lambda);
- SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
+ const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
if (DefaultCaptureLoc.isInvalid())
return;
>From 0bcdbc4373a6d320f49f30a64c647b1da3956756 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Tue, 23 Sep 2025 13:15:11 -0400
Subject: [PATCH 12/29] Fix header guard
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
index ad48316708b1b..fa69245b91c94 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURE_H
#include "../ClangTidyCheck.h"
@@ -31,4 +31,4 @@ class DefaultLambdaCaptureCheck : public ClangTidyCheck {
} // namespace clang::tidy::bugprone
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULT_LAMBDA_CAPTURE_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURE_H
>From ac709f4fcf092da2b240b9e0a62d1f8c314fdebb Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Tue, 23 Sep 2025 16:07:45 -0400
Subject: [PATCH 13/29] Fix header spelling
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/bugprone/DefaultLambdaCaptureCheck.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
index fa69245b91c94..c41d7257592d5 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURE_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURE_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURECHECK_H
#include "../ClangTidyCheck.h"
@@ -31,4 +31,4 @@ class DefaultLambdaCaptureCheck : public ClangTidyCheck {
} // namespace clang::tidy::bugprone
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURE_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURECHECK_H
>From 5d4c2ca704cce01a491ac38ecd25bf722b94ad78 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Wed, 24 Sep 2025 13:24:17 -0400
Subject: [PATCH 14/29] Rename check to readability-default-lambda-capture
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../bugprone/BugproneTidyModule.cpp | 3 ---
.../clang-tidy/bugprone/CMakeLists.txt | 1 -
.../clang-tidy/readability/CMakeLists.txt | 1 +
.../DefaultLambdaCaptureCheck.cpp | 4 +--
.../DefaultLambdaCaptureCheck.h | 12 ++++-----
.../readability/ReadabilityTidyModule.cpp | 3 +++
clang-tools-extra/docs/ReleaseNotes.rst | 10 +++----
.../docs/clang-tidy/checks/list.rst | 2 +-
.../default-lambda-capture.rst | 4 +--
.../default-lambda-capture.cpp | 26 +++++++++----------
10 files changed, 33 insertions(+), 33 deletions(-)
rename clang-tools-extra/clang-tidy/{bugprone => readability}/DefaultLambdaCaptureCheck.cpp (94%)
rename clang-tools-extra/clang-tidy/{bugprone => readability}/DefaultLambdaCaptureCheck.h (69%)
rename clang-tools-extra/docs/clang-tidy/checks/{bugprone => readability}/default-lambda-capture.rst (91%)
rename clang-tools-extra/test/clang-tidy/checkers/{bugprone => readability}/default-lambda-capture.cpp (84%)
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 67222cbafb5f9..8baa8f6b35d4c 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -23,7 +23,6 @@
#include "CopyConstructorInitCheck.h"
#include "CrtpConstructorAccessibilityCheck.h"
#include "DanglingHandleCheck.h"
-#include "DefaultLambdaCaptureCheck.h"
#include "DerivedMethodShadowingBaseMethodCheck.h"
#include "DynamicStaticInitializersCheck.h"
#include "EasilySwappableParametersCheck.h"
@@ -137,8 +136,6 @@ class BugproneModule : public ClangTidyModule {
"bugprone-copy-constructor-init");
CheckFactories.registerCheck<DanglingHandleCheck>(
"bugprone-dangling-handle");
- CheckFactories.registerCheck<DefaultLambdaCaptureCheck>(
- "bugprone-default-lambda-capture");
CheckFactories.registerCheck<DerivedMethodShadowingBaseMethodCheck>(
"bugprone-derived-method-shadowing-base-method");
CheckFactories.registerCheck<DynamicStaticInitializersCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index c8c31f9f96bb0..b0dbe84a16cd4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -19,7 +19,6 @@ add_clang_library(clangTidyBugproneModule STATIC
CopyConstructorInitCheck.cpp
CrtpConstructorAccessibilityCheck.cpp
DanglingHandleCheck.cpp
- DefaultLambdaCaptureCheck.cpp
DerivedMethodShadowingBaseMethodCheck.cpp
DynamicStaticInitializersCheck.cpp
EasilySwappableParametersCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 4b4c49d3b17d1..829caa15377e6 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -15,6 +15,7 @@ add_clang_library(clangTidyReadabilityModule STATIC
ContainerDataPointerCheck.cpp
ContainerSizeEmptyCheck.cpp
ConvertMemberFunctionsToStatic.cpp
+ DefaultLambdaCaptureCheck.cpp
DeleteNullPointerCheck.cpp
DuplicateIncludeCheck.cpp
ElseAfterReturnCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.cpp
similarity index 94%
rename from clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
rename to clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.cpp
index a7a18ccb30864..60914fc7e7069 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.cpp
@@ -11,7 +11,7 @@
using namespace clang::ast_matchers;
-namespace clang::tidy::bugprone {
+namespace clang::tidy::readability {
namespace {
AST_MATCHER(LambdaExpr, hasDefaultCapture) {
@@ -36,4 +36,4 @@ void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
"prefer to capture specific variables explicitly");
}
-} // namespace clang::tidy::bugprone
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.h
similarity index 69%
rename from clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
rename to clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.h
index c41d7257592d5..fd29d71b7c542 100644
--- a/clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.h
@@ -6,17 +6,17 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURECHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURECHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DEFAULTLAMBDACAPTURECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DEFAULTLAMBDACAPTURECHECK_H
#include "../ClangTidyCheck.h"
-namespace clang::tidy::bugprone {
+namespace clang::tidy::readability {
/** Flags lambdas that use default capture modes
*
* For the user-facing documentation see:
- * https://clang.llvm.org/extra/clang-tidy/checks/bugprone/default-lambda-capture.html
+ * https://clang.llvm.org/extra/clang-tidy/checks/readability/default-lambda-capture.html
*/
class DefaultLambdaCaptureCheck : public ClangTidyCheck {
public:
@@ -29,6 +29,6 @@ class DefaultLambdaCaptureCheck : public ClangTidyCheck {
}
};
-} // namespace clang::tidy::bugprone
+} // namespace clang::tidy::readability
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_DEFAULTLAMBDACAPTURECHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DEFAULTLAMBDACAPTURECHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index d01882dfc9daa..4b9bf3d417a7b 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -20,6 +20,7 @@
#include "ContainerDataPointerCheck.h"
#include "ContainerSizeEmptyCheck.h"
#include "ConvertMemberFunctionsToStatic.h"
+#include "DefaultLambdaCaptureCheck.h"
#include "DeleteNullPointerCheck.h"
#include "DuplicateIncludeCheck.h"
#include "ElseAfterReturnCheck.h"
@@ -92,6 +93,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-container-size-empty");
CheckFactories.registerCheck<ConvertMemberFunctionsToStatic>(
"readability-convert-member-functions-to-static");
+ CheckFactories.registerCheck<DefaultLambdaCaptureCheck>(
+ "readability-default-lambda-capture");
CheckFactories.registerCheck<DeleteNullPointerCheck>(
"readability-delete-null-pointer");
CheckFactories.registerCheck<DuplicateIncludeCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 9d2e8dcad7045..6f29f0e99d6f7 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -167,11 +167,6 @@ New checks
Detects default initialization (to 0) of variables with ``enum`` type where
the enum has no enumerator with value of 0.
-- New :doc:`bugprone-default-lambda-capture
- <clang-tidy/checks/bugprone/default-lambda-capture>` check.
-
- Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
-
- New :doc:`bugprone-derived-method-shadowing-base-method
<clang-tidy/checks/bugprone/derived-method-shadowing-base-method>` check.
@@ -356,6 +351,11 @@ Changes in existing checks
<clang-tidy/checks/readability/uppercase-literal-suffix>` check to recognize
literal suffixes added in C++23 and C23.
+- New :doc:`readability-default-lambda-capture
+ <clang-tidy/checks/readability/default-lambda-capture>` check.
+
+ Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
+
Removed checks
^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 5232f650f6579..e72cbf75fa03f 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -91,7 +91,6 @@ Clang-Tidy Checks
:doc:`bugprone-copy-constructor-init <bugprone/copy-constructor-init>`, "Yes"
:doc:`bugprone-crtp-constructor-accessibility <bugprone/crtp-constructor-accessibility>`, "Yes"
:doc:`bugprone-dangling-handle <bugprone/dangling-handle>`,
- :doc:`bugprone-default-lambda-capture <bugprone/default-lambda-capture>`,
:doc:`bugprone-derived-method-shadowing-base-method <bugprone/derived-method-shadowing-base-method>`,
:doc:`bugprone-dynamic-static-initializers <bugprone/dynamic-static-initializers>`,
:doc:`bugprone-easily-swappable-parameters <bugprone/easily-swappable-parameters>`,
@@ -378,6 +377,7 @@ Clang-Tidy Checks
:doc:`readability-container-data-pointer <readability/container-data-pointer>`, "Yes"
:doc:`readability-container-size-empty <readability/container-size-empty>`, "Yes"
:doc:`readability-convert-member-functions-to-static <readability/convert-member-functions-to-static>`, "Yes"
+ :doc:`readability-default-lambda-capture <readability/default-lambda-capture>`,
:doc:`readability-delete-null-pointer <readability/delete-null-pointer>`, "Yes"
:doc:`readability-duplicate-include <readability/duplicate-include>`, "Yes"
:doc:`readability-else-after-return <readability/else-after-return>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
similarity index 91%
rename from clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
rename to clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
index 9cedc6276e1b3..00734b427d131 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
@@ -1,6 +1,6 @@
-.. title:: clang-tidy - bugprone-default-lambda-capture
+.. title:: clang-tidy - readability-default-lambda-capture
-bugprone-default-lambda-capture
+readability-default-lambda-capture
===============================
Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/default-lambda-capture.cpp
similarity index 84%
rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/readability/default-lambda-capture.cpp
index 010edf11f0a2b..ecc45130a6cdf 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/default-lambda-capture.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/default-lambda-capture.cpp
@@ -1,20 +1,20 @@
-// RUN: %check_clang_tidy %s bugprone-default-lambda-capture %t
+// RUN: %check_clang_tidy %s readability-default-lambda-capture %t
void test_default_captures() {
int value = 42;
int another = 10;
auto lambda1 = [=](int x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto lambda2 = [&](int x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto lambda3 = [=, &another](int x) { return value + another + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto lambda4 = [&, value](int x) { return value + another + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
}
void test_acceptable_captures() {
@@ -42,10 +42,10 @@ void test_nested_lambdas() {
int inner_var = 3;
auto outer = [=]() {
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
return inner(10);
};
@@ -55,15 +55,15 @@ void test_lambda_returns() {
int a = 1, b = 2, c = 3;
auto create_adder = [=](int x) {
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture
};
auto func1 = [&]() { return a; };
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto func2 = [=]() { return b; };
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
}
class TestClass {
@@ -74,10 +74,10 @@ class TestClass {
int local = 10;
auto lambda1 = [=]() { return member + local; };
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto lambda2 = [&]() { return member + local; };
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
auto lambda3 = [this, local]() { return member + local; };
auto lambda4 = [this, &local]() { return member + local; };
@@ -89,7 +89,7 @@ void test_template_lambdas() {
T value{};
auto lambda = [=](T x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [bugprone-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
}
void instantiate_templates() {
>From c0b90d1d0a20ac71d4f6944e0818a1d56eba4acd Mon Sep 17 00:00:00 2001
From: JJ Marr <jjmarr12 at amd.com>
Date: Wed, 24 Sep 2025 13:32:04 -0400
Subject: [PATCH 15/29] Update
clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../clang-tidy/checks/readability/default-lambda-capture.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
index 00734b427d131..785f112a70b11 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
@@ -1,7 +1,7 @@
.. title:: clang-tidy - readability-default-lambda-capture
readability-default-lambda-capture
-===============================
+==================================
Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
>From 1172f730ba67151e560dc4ec46a203a8bf83a52b Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Thu, 25 Sep 2025 10:29:37 -0400
Subject: [PATCH 16/29] update doc
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../readability/default-lambda-capture.rst | 62 +++++++++++--------
1 file changed, 37 insertions(+), 25 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
index 785f112a70b11..daabdd1a92995 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
@@ -5,39 +5,51 @@ readability-default-lambda-capture
Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
-Default captures can lead to subtle bugs including dangling references with
-``[&]``, unnecessary copies with ``[=]``, and make code less maintainable by
-hiding which variables are actually being captured.
+Captures can lead to subtle bugs including dangling references and unnecessary
+copies. Writing out the name of the variables being captured reminds programmers
+and reviewers to know what is being captured. And knowing is half the battle.
-Implements Item 31 of Effective Modern C++ by Scott Meyers.
+Coding guidelines that recommend against defaulted lambda captures include:
+
+* Item 31 of Effective Modern C++ by Scott Meyers
+* `AUTOSAR C++ Rule A5-1-2 <https://www.mathworks.com/help//releases/
+ R2021a/bugfinder/ref/autosarc14rulea512.html>`__
Example
-------
.. code-block:: c++
- void example() {
- int x = 1;
- int y = 2;
-
- // Bad - default capture by copy
- auto lambda1 = [=]() { return x + y; };
-
- // Bad - default capture by reference
- auto lambda2 = [&]() { return x + y; };
-
- // Good - explicit captures
- auto lambda3 = [x, y]() { return x + y; };
- auto lambda4 = [&x, &y]() { return x + y; };
+ #include <iostream>
+
+ class Widget {
+ std::vector<std::function<void(int)>> callbacks;
+ int widgetId;
+ void addCallback(int factoryId) {
+ callbacks.emplace_back(
+ [&](){
+ std::cout << "Widget " << widgetId << " made in factory " << factoryId;
+ }
+ );
+ }
}
-The check will warn on:
-
-- Default capture by copy: ``[=]``
-- Default capture by reference: ``[&]``
-- Mixed captures with defaults: ``[=, &x]`` or ``[&, x]``
+When ``callbacks`` is executed, ``factoryId`` will dangle. Writing the name of
+``factoryId`` in the capture list makes it easy to review the captures and
+detect obvious bugs.
-The check will not warn on:
+.. code-block:: c++
-- Explicit captures: ``[x]``, ``[&x]``, ``[x, y]``, ``[this]``
-- Empty capture lists: ``[]``
+ #include <iostream>
+
+ class Widget {
+ std::vector<std::function<void(int)>> callbacks;
+ int widgetId;
+ void addCallback(int factoryId) {
+ callbacks.emplace_back(
+ [&factoryId, &widgetId](){ // Why isn't factoryId captured by value??
+ std::cout << "Widget " << widgetId << " made in factory " << factoryId;
+ }
+ );
+ }
+ }
>From 66e6aaa168928f18e8a427b0cf4abe21fb52fb9b Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Thu, 25 Sep 2025 11:04:26 -0400
Subject: [PATCH 17/29] rename check to
readability-avoid-default-lambda-capture
on-behalf-of: @amd <JJ.Marr at amd.com>
---
...cpp => AvoidDefaultLambdaCaptureCheck.cpp} | 7 ++--
...eck.h => AvoidDefaultLambdaCaptureCheck.h} | 12 +++----
.../clang-tidy/readability/CMakeLists.txt | 2 +-
.../readability/ReadabilityTidyModule.cpp | 6 ++--
clang-tools-extra/docs/ReleaseNotes.rst | 4 +--
.../docs/clang-tidy/checks/list.rst | 2 +-
...e.rst => avoid-default-lambda-capture.rst} | 6 ++--
...e.cpp => avoid-default-lambda-capture.cpp} | 32 +++++++++----------
8 files changed, 36 insertions(+), 35 deletions(-)
rename clang-tools-extra/clang-tidy/readability/{DefaultLambdaCaptureCheck.cpp => AvoidDefaultLambdaCaptureCheck.cpp} (83%)
rename clang-tools-extra/clang-tidy/readability/{DefaultLambdaCaptureCheck.h => AvoidDefaultLambdaCaptureCheck.h} (64%)
rename clang-tools-extra/docs/clang-tidy/checks/readability/{default-lambda-capture.rst => avoid-default-lambda-capture.rst} (91%)
rename clang-tools-extra/test/clang-tidy/checkers/readability/{default-lambda-capture.cpp => avoid-default-lambda-capture.cpp} (83%)
diff --git a/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
similarity index 83%
rename from clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.cpp
rename to clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index 60914fc7e7069..1036d764497b4 100644
--- a/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//
-#include "DefaultLambdaCaptureCheck.h"
+#include "AvoidDefaultLambdaCaptureCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
using namespace clang::ast_matchers;
@@ -20,11 +20,12 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
} // namespace
-void DefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
+void AvoidDefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(lambdaExpr(hasDefaultCapture()).bind("lambda"), this);
}
-void DefaultLambdaCaptureCheck::check(const MatchFinder::MatchResult &Result) {
+void AvoidDefaultLambdaCaptureCheck::check(
+ const MatchFinder::MatchResult &Result) {
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
assert(Lambda);
diff --git a/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
similarity index 64%
rename from clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.h
rename to clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
index fd29d71b7c542..604cf85b2a71f 100644
--- a/clang-tools-extra/clang-tidy/readability/DefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
@@ -6,8 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DEFAULTLAMBDACAPTURECHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DEFAULTLAMBDACAPTURECHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H
#include "../ClangTidyCheck.h"
@@ -16,11 +16,11 @@ namespace clang::tidy::readability {
/** Flags lambdas that use default capture modes
*
* For the user-facing documentation see:
- * https://clang.llvm.org/extra/clang-tidy/checks/readability/default-lambda-capture.html
+ * https://clang.llvm.org/extra/clang-tidy/checks/readability/avoid-default-lambda-capture.html
*/
-class DefaultLambdaCaptureCheck : public ClangTidyCheck {
+class AvoidDefaultLambdaCaptureCheck : public ClangTidyCheck {
public:
- DefaultLambdaCaptureCheck(StringRef Name, ClangTidyContext *Context)
+ AvoidDefaultLambdaCaptureCheck(StringRef Name, ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
@@ -31,4 +31,4 @@ class DefaultLambdaCaptureCheck : public ClangTidyCheck {
} // namespace clang::tidy::readability
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_DEFAULTLAMBDACAPTURECHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H
diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 829caa15377e6..b4e0c7b8a4a43 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -6,6 +6,7 @@ set(LLVM_LINK_COMPONENTS
add_clang_library(clangTidyReadabilityModule STATIC
AmbiguousSmartptrResetCallCheck.cpp
AvoidConstParamsInDecls.cpp
+ AvoidDefaultLambdaCaptureCheck.cpp
AvoidNestedConditionalOperatorCheck.cpp
AvoidReturnWithVoidValueCheck.cpp
AvoidUnconditionalPreprocessorIfCheck.cpp
@@ -15,7 +16,6 @@ add_clang_library(clangTidyReadabilityModule STATIC
ContainerDataPointerCheck.cpp
ContainerSizeEmptyCheck.cpp
ConvertMemberFunctionsToStatic.cpp
- DefaultLambdaCaptureCheck.cpp
DeleteNullPointerCheck.cpp
DuplicateIncludeCheck.cpp
ElseAfterReturnCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index 4b9bf3d417a7b..34c9e71926d18 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -11,6 +11,7 @@
#include "../ClangTidyModuleRegistry.h"
#include "AmbiguousSmartptrResetCallCheck.h"
#include "AvoidConstParamsInDecls.h"
+#include "AvoidDefaultLambdaCaptureCheck.h"
#include "AvoidNestedConditionalOperatorCheck.h"
#include "AvoidReturnWithVoidValueCheck.h"
#include "AvoidUnconditionalPreprocessorIfCheck.h"
@@ -20,7 +21,6 @@
#include "ContainerDataPointerCheck.h"
#include "ContainerSizeEmptyCheck.h"
#include "ConvertMemberFunctionsToStatic.h"
-#include "DefaultLambdaCaptureCheck.h"
#include "DeleteNullPointerCheck.h"
#include "DuplicateIncludeCheck.h"
#include "ElseAfterReturnCheck.h"
@@ -93,8 +93,8 @@ class ReadabilityModule : public ClangTidyModule {
"readability-container-size-empty");
CheckFactories.registerCheck<ConvertMemberFunctionsToStatic>(
"readability-convert-member-functions-to-static");
- CheckFactories.registerCheck<DefaultLambdaCaptureCheck>(
- "readability-default-lambda-capture");
+ CheckFactories.registerCheck<AvoidDefaultLambdaCaptureCheck>(
+ "readability-avoid-default-lambda-capture");
CheckFactories.registerCheck<DeleteNullPointerCheck>(
"readability-delete-null-pointer");
CheckFactories.registerCheck<DuplicateIncludeCheck>(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6f29f0e99d6f7..d3edc1a9865ab 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -351,8 +351,8 @@ Changes in existing checks
<clang-tidy/checks/readability/uppercase-literal-suffix>` check to recognize
literal suffixes added in C++23 and C23.
-- New :doc:`readability-default-lambda-capture
- <clang-tidy/checks/readability/default-lambda-capture>` check.
+- New :doc:`readability-avoid-default-lambda-capture
+ <clang-tidy/checks/readability/avoid-default-lambda-capture>` check.
Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index e72cbf75fa03f..0b8dcd440e1f6 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -377,7 +377,7 @@ Clang-Tidy Checks
:doc:`readability-container-data-pointer <readability/container-data-pointer>`, "Yes"
:doc:`readability-container-size-empty <readability/container-size-empty>`, "Yes"
:doc:`readability-convert-member-functions-to-static <readability/convert-member-functions-to-static>`, "Yes"
- :doc:`readability-default-lambda-capture <readability/default-lambda-capture>`,
+ :doc:`readability-avoid-default-lambda-capture <readability/avoid-default-lambda-capture>`,
:doc:`readability-delete-null-pointer <readability/delete-null-pointer>`, "Yes"
:doc:`readability-duplicate-include <readability/duplicate-include>`, "Yes"
:doc:`readability-else-after-return <readability/else-after-return>`, "Yes"
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
similarity index 91%
rename from clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
rename to clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
index daabdd1a92995..9851896026be5 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - readability-default-lambda-capture
+.. title:: clang-tidy - readability-avoid-default-lambda-capture
-readability-default-lambda-capture
-==================================
+readability-avoid-default-lambda-capture
+=========================================
Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
similarity index 83%
rename from clang-tools-extra/test/clang-tidy/checkers/readability/default-lambda-capture.cpp
rename to clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
index ecc45130a6cdf..f452ea6f6ccb1 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/default-lambda-capture.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
@@ -1,20 +1,20 @@
-// RUN: %check_clang_tidy %s readability-default-lambda-capture %t
+// RUN: %check_clang_tidy %s readability-avoid-default-lambda-capture %t
void test_default_captures() {
int value = 42;
int another = 10;
auto lambda1 = [=](int x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
auto lambda2 = [&](int x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
auto lambda3 = [=, &another](int x) { return value + another + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
auto lambda4 = [&, value](int x) { return value + another + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
}
void test_acceptable_captures() {
@@ -42,10 +42,10 @@ void test_nested_lambdas() {
int inner_var = 3;
auto outer = [=]() {
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
-
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+
auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
return inner(10);
};
@@ -55,15 +55,15 @@ void test_lambda_returns() {
int a = 1, b = 2, c = 3;
auto create_adder = [=](int x) {
- // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture
};
auto func1 = [&]() { return a; };
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
-
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+
auto func2 = [=]() { return b; };
- // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
}
class TestClass {
@@ -74,10 +74,10 @@ class TestClass {
int local = 10;
auto lambda1 = [=]() { return member + local; };
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
-
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+
auto lambda2 = [&]() { return member + local; };
- // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
auto lambda3 = [this, local]() { return member + local; };
auto lambda4 = [this, &local]() { return member + local; };
@@ -89,7 +89,7 @@ void test_template_lambdas() {
T value{};
auto lambda = [=](T x) { return value + x; };
- // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-default-lambda-capture]
+ // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
}
void instantiate_templates() {
>From 4bf58b6eddee9b1027654653fa409d6bd668e79c Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Thu, 25 Sep 2025 11:05:23 -0400
Subject: [PATCH 18/29] use C++ style comments
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../readability/AvoidDefaultLambdaCaptureCheck.h | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
index 604cf85b2a71f..82262a210e4c4 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
@@ -13,11 +13,10 @@
namespace clang::tidy::readability {
-/** Flags lambdas that use default capture modes
- *
- * For the user-facing documentation see:
- * https://clang.llvm.org/extra/clang-tidy/checks/readability/avoid-default-lambda-capture.html
- */
+/// Flags lambdas that use default capture modes
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/readability/avoid-default-lambda-capture.html
class AvoidDefaultLambdaCaptureCheck : public ClangTidyCheck {
public:
AvoidDefaultLambdaCaptureCheck(StringRef Name, ClangTidyContext *Context)
>From a807dd0e29f5af7af8cc6747082bac606b3ea2ec Mon Sep 17 00:00:00 2001
From: JJ Marr <jjmarr12 at amd.com>
Date: Thu, 25 Sep 2025 11:19:41 -0400
Subject: [PATCH 19/29] Update
clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
Co-authored-by: EugeneZelenko <eugene.zelenko at gmail.com>
---
.../checks/readability/avoid-default-lambda-capture.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
index 9851896026be5..4513e5d1ef305 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
@@ -1,7 +1,7 @@
.. title:: clang-tidy - readability-avoid-default-lambda-capture
readability-avoid-default-lambda-capture
-=========================================
+========================================
Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
>From 8fdc0974ed84e8177ab61c6dbeeccf6b43ed1593 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Thu, 25 Sep 2025 11:20:22 -0400
Subject: [PATCH 20/29] fix doc again
on-behalf-of: @amd <JJ.Marr at amd.com>
---
clang-tools-extra/docs/ReleaseNotes.rst | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index d3edc1a9865ab..583d4de022218 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -203,6 +203,11 @@ New checks
Finds virtual function overrides with different visibility than the function
in the base class.
+- New :doc:`readability-avoid-default-lambda-capture
+ <clang-tidy/checks/readability/avoid-default-lambda-capture>` check.
+
+ Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
+
New check aliases
^^^^^^^^^^^^^^^^^
@@ -351,11 +356,6 @@ Changes in existing checks
<clang-tidy/checks/readability/uppercase-literal-suffix>` check to recognize
literal suffixes added in C++23 and C23.
-- New :doc:`readability-avoid-default-lambda-capture
- <clang-tidy/checks/readability/avoid-default-lambda-capture>` check.
-
- Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
-
Removed checks
^^^^^^^^^^^^^^
>From ab8f4b9db4011587bc51407abf4f2a4ad9d7920c Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Thu, 25 Sep 2025 12:58:26 -0400
Subject: [PATCH 21/29] remove reference to coding guideline
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../checks/readability/avoid-default-lambda-capture.rst | 2 --
1 file changed, 2 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
index 4513e5d1ef305..6b63e103e588e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
@@ -12,8 +12,6 @@ and reviewers to know what is being captured. And knowing is half the battle.
Coding guidelines that recommend against defaulted lambda captures include:
* Item 31 of Effective Modern C++ by Scott Meyers
-* `AUTOSAR C++ Rule A5-1-2 <https://www.mathworks.com/help//releases/
- R2021a/bugfinder/ref/autosarc14rulea512.html>`__
Example
-------
>From 13b50491bbb329fa24b714d1af0203ab6ce85ce3 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 09:50:39 -0400
Subject: [PATCH 22/29] rephrase
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../checks/readability/avoid-default-lambda-capture.rst | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
index 6b63e103e588e..d4ecd4c7eb27d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
@@ -3,7 +3,7 @@
readability-avoid-default-lambda-capture
========================================
-Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``)
+Warns on default lambda captures (e.g. ``[&](){ ... }``, ``[=](){ ... }``).
Captures can lead to subtle bugs including dangling references and unnecessary
copies. Writing out the name of the variables being captured reminds programmers
@@ -33,8 +33,8 @@ Example
}
When ``callbacks`` is executed, ``factoryId`` will dangle. Writing the name of
-``factoryId`` in the capture list makes it easy to review the captures and
-detect obvious bugs.
+``factoryId`` in the capture list reminds the reader that it is being captured,
+which will hopefully lead to the bug being fixed during code review.
.. code-block:: c++
>From 043df7c76564f55e5ff76e5139ca29fa827e402c Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 10:27:18 -0400
Subject: [PATCH 23/29] commit vibe coded work
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../AvoidDefaultLambdaCaptureCheck.cpp | 57 ++++++++++++++++++-
.../avoid-default-lambda-capture.cpp | 12 ++++
2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index 1036d764497b4..361af6794a9b5 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -8,6 +8,8 @@
#include "AvoidDefaultLambdaCaptureCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Basic/Lambda.h"
+#include "clang/Lex/Lexer.h"
using namespace clang::ast_matchers;
@@ -18,6 +20,45 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
return Node.getCaptureDefault() != LCD_None;
}
+std::string getCaptureString(const LambdaCapture &Capture) {
+ if (Capture.capturesThis()) {
+ return Capture.getCaptureKind() == LCK_StarThis ? "*this" : "this";
+ }
+
+ if (Capture.capturesVariable()) {
+ std::string Result;
+ if (Capture.getCaptureKind() == LCK_ByRef) {
+ Result += "&";
+ }
+ Result += Capture.getCapturedVar()->getName().str();
+ return Result;
+ }
+
+ // Handle VLA captures - these are rare but possible
+ return "/* VLA capture */";
+}
+
+std::string buildExplicitCaptureList(const LambdaExpr *Lambda) {
+ std::vector<std::string> CaptureStrings;
+
+ // Add explicit captures first (preserve their order and syntax)
+ for (const auto &Capture : Lambda->explicit_captures()) {
+ CaptureStrings.push_back(getCaptureString(Capture));
+ }
+
+ // Add implicit captures (convert to explicit syntax)
+ for (const auto &Capture : Lambda->implicit_captures()) {
+ CaptureStrings.push_back(getCaptureString(Capture));
+ }
+
+ return "[" + llvm::join(CaptureStrings, ", ") + "]";
+}
+
+SourceRange getCaptureListRange(const LambdaExpr *Lambda) {
+ SourceRange IntroducerRange = Lambda->getIntroducerRange();
+ return IntroducerRange;
+}
+
} // namespace
void AvoidDefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
@@ -33,8 +74,20 @@ void AvoidDefaultLambdaCaptureCheck::check(
if (DefaultCaptureLoc.isInvalid())
return;
- diag(DefaultCaptureLoc, "lambda default captures are discouraged; "
- "prefer to capture specific variables explicitly");
+ // Build the replacement capture list
+ std::string NewCaptureList = buildExplicitCaptureList(Lambda);
+
+ // Get the range of the entire capture list [...]
+ SourceRange CaptureListRange = getCaptureListRange(Lambda);
+
+ auto Diag = diag(DefaultCaptureLoc,
+ "lambda default captures are discouraged; "
+ "prefer to capture specific variables explicitly");
+
+ // Only provide fixit if we can determine a valid replacement
+ if (CaptureListRange.isValid() && !NewCaptureList.empty()) {
+ Diag << FixItHint::CreateReplacement(CaptureListRange, NewCaptureList);
+ }
}
} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
index f452ea6f6ccb1..6e81a9eb2b3d4 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
@@ -6,15 +6,19 @@ void test_default_captures() {
auto lambda1 = [=](int x) { return value + x; };
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda1 = [value](int x) { return value + x; };
auto lambda2 = [&](int x) { return value + x; };
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda2 = [&value](int x) { return value + x; };
auto lambda3 = [=, &another](int x) { return value + another + x; };
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda3 = [&another, value](int x) { return value + another + x; };
auto lambda4 = [&, value](int x) { return value + another + x; };
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda4 = [value, &another](int x) { return value + another + x; };
}
void test_acceptable_captures() {
@@ -43,9 +47,11 @@ void test_nested_lambdas() {
auto outer = [=]() {
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto outer = [outer_var, middle_var, inner_var]() {
auto inner = [&](int x) { return outer_var + middle_var + inner_var + x; };
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto inner = [&outer_var, &middle_var, &inner_var](int x) { return outer_var + middle_var + inner_var + x; };
return inner(10);
};
@@ -56,14 +62,17 @@ void test_lambda_returns() {
auto create_adder = [=](int x) {
// CHECK-MESSAGES: :[[@LINE-1]]:24: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto create_adder = [](int x) {
return [x](int y) { return x + y; }; // Inner lambda is fine - explicit capture
};
auto func1 = [&]() { return a; };
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto func1 = [&a]() { return a; };
auto func2 = [=]() { return b; };
// CHECK-MESSAGES: :[[@LINE-1]]:17: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto func2 = [b]() { return b; };
}
class TestClass {
@@ -75,9 +84,11 @@ class TestClass {
auto lambda1 = [=]() { return member + local; };
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda1 = [this, local]() { return member + local; };
auto lambda2 = [&]() { return member + local; };
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda2 = [this, &local]() { return member + local; };
auto lambda3 = [this, local]() { return member + local; };
auto lambda4 = [this, &local]() { return member + local; };
@@ -90,6 +101,7 @@ void test_template_lambdas() {
auto lambda = [=](T x) { return value + x; };
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: lambda default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture]
+ // CHECK-FIXES: auto lambda = [](T x) { return value + x; };
}
void instantiate_templates() {
>From 33af58bf9f683c21f0263f2d1e9b8810c76d30f3 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 10:37:55 -0400
Subject: [PATCH 24/29] attempt to fix to use something that isn't weird string
manipulation
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../AvoidDefaultLambdaCaptureCheck.cpp | 39 +++++++++++++++++--
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index 361af6794a9b5..b64717534acd6 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -20,6 +20,29 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
return Node.getCaptureDefault() != LCD_None;
}
+std::string getExplicitCaptureText(const LambdaCapture &Capture,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ if (!Capture.isExplicit() || !Capture.getLocation().isValid()) {
+ return "";
+ }
+
+ // For explicit captures, extract the actual source text to preserve
+ // original formatting, spacing, and comments
+ SourceLocation CaptureBegin = Capture.getLocation();
+
+ // Find the end of this capture by looking for the next comma or closing
+ // bracket This is a simplified approach - a more robust implementation would
+ // parse tokens
+ SourceLocation CaptureEnd =
+ Lexer::getLocForEndOfToken(CaptureBegin, 0, SM, LangOpts);
+
+ // For now, we'll still reconstruct to ensure correctness
+ // but this framework allows for future enhancement to preserve exact source
+ // text
+ return "";
+}
+
std::string getCaptureString(const LambdaCapture &Capture) {
if (Capture.capturesThis()) {
return Capture.getCaptureKind() == LCK_StarThis ? "*this" : "this";
@@ -38,12 +61,21 @@ std::string getCaptureString(const LambdaCapture &Capture) {
return "/* VLA capture */";
}
-std::string buildExplicitCaptureList(const LambdaExpr *Lambda) {
+std::string buildExplicitCaptureList(const LambdaExpr *Lambda,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
std::vector<std::string> CaptureStrings;
// Add explicit captures first (preserve their order and syntax)
for (const auto &Capture : Lambda->explicit_captures()) {
- CaptureStrings.push_back(getCaptureString(Capture));
+ // Try to get the original source text first
+ std::string ExplicitText = getExplicitCaptureText(Capture, SM, LangOpts);
+ if (!ExplicitText.empty()) {
+ CaptureStrings.push_back(ExplicitText);
+ } else {
+ // Fall back to reconstructed text
+ CaptureStrings.push_back(getCaptureString(Capture));
+ }
}
// Add implicit captures (convert to explicit syntax)
@@ -75,7 +107,8 @@ void AvoidDefaultLambdaCaptureCheck::check(
return;
// Build the replacement capture list
- std::string NewCaptureList = buildExplicitCaptureList(Lambda);
+ std::string NewCaptureList = buildExplicitCaptureList(
+ Lambda, *Result.SourceManager, Result.Context->getLangOpts());
// Get the range of the entire capture list [...]
SourceRange CaptureListRange = getCaptureListRange(Lambda);
>From 51aa1820f59dbd749807900ea53eb3710477d9ab Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 12:58:51 -0400
Subject: [PATCH 25/29] more vibe coding with human intervention
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../AvoidDefaultLambdaCaptureCheck.cpp | 156 +++++++++++-------
1 file changed, 99 insertions(+), 57 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index b64717534acd6..72294cc164360 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -20,30 +20,47 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
return Node.getCaptureDefault() != LCD_None;
}
-std::string getExplicitCaptureText(const LambdaCapture &Capture,
+// Find the source range of the default capture token (= or &)
+SourceRange getDefaultCaptureRange(const LambdaExpr *Lambda,
const SourceManager &SM,
const LangOptions &LangOpts) {
- if (!Capture.isExplicit() || !Capture.getLocation().isValid()) {
- return "";
- }
+ SourceLocation DefaultLoc = Lambda->getCaptureDefaultLoc();
+ if (DefaultLoc.isInvalid())
+ return SourceRange();
+
+ // The default capture is a single token
+ SourceLocation EndLoc =
+ Lexer::getLocForEndOfToken(DefaultLoc, 0, SM, LangOpts);
+ return SourceRange(DefaultLoc, EndLoc);
+}
- // For explicit captures, extract the actual source text to preserve
- // original formatting, spacing, and comments
- SourceLocation CaptureBegin = Capture.getLocation();
+// Find where to insert implicit captures
+SourceLocation getImplicitCaptureInsertionLoc(const LambdaExpr *Lambda,
+ const SourceManager &SM,
+ const LangOptions &LangOpts) {
+ // If there are explicit captures, insert after the last one
+ if (Lambda->explicit_capture_begin() != Lambda->explicit_capture_end()) {
+ // Find the location after the last explicit capture
+ const auto *LastExplicit = Lambda->explicit_capture_end() - 1;
+ SourceLocation LastLoc = LastExplicit->getLocation();
+ if (LastLoc.isValid()) {
+ return Lexer::getLocForEndOfToken(LastLoc, 0, SM, LangOpts);
+ }
+ }
- // Find the end of this capture by looking for the next comma or closing
- // bracket This is a simplified approach - a more robust implementation would
- // parse tokens
- SourceLocation CaptureEnd =
- Lexer::getLocForEndOfToken(CaptureBegin, 0, SM, LangOpts);
+ // If no explicit captures, insert after the default capture
+ SourceLocation DefaultLoc = Lambda->getCaptureDefaultLoc();
+ if (DefaultLoc.isValid()) {
+ return Lexer::getLocForEndOfToken(DefaultLoc, 0, SM, LangOpts);
+ }
- // For now, we'll still reconstruct to ensure correctness
- // but this framework allows for future enhancement to preserve exact source
- // text
- return "";
+ // Fallback: insert at the beginning of the capture list
+ return Lambda->getIntroducerRange().getBegin().getLocWithOffset(1);
}
-std::string getCaptureString(const LambdaCapture &Capture) {
+// Generate the text for an implicit capture
+std::optional<std::string>
+generateImplicitCaptureText(const LambdaCapture &Capture) {
if (Capture.capturesThis()) {
return Capture.getCaptureKind() == LCK_StarThis ? "*this" : "this";
}
@@ -57,38 +74,15 @@ std::string getCaptureString(const LambdaCapture &Capture) {
return Result;
}
- // Handle VLA captures - these are rare but possible
- return "/* VLA capture */";
-}
-
-std::string buildExplicitCaptureList(const LambdaExpr *Lambda,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
- std::vector<std::string> CaptureStrings;
-
- // Add explicit captures first (preserve their order and syntax)
- for (const auto &Capture : Lambda->explicit_captures()) {
- // Try to get the original source text first
- std::string ExplicitText = getExplicitCaptureText(Capture, SM, LangOpts);
- if (!ExplicitText.empty()) {
- CaptureStrings.push_back(ExplicitText);
- } else {
- // Fall back to reconstructed text
- CaptureStrings.push_back(getCaptureString(Capture));
- }
- }
-
- // Add implicit captures (convert to explicit syntax)
- for (const auto &Capture : Lambda->implicit_captures()) {
- CaptureStrings.push_back(getCaptureString(Capture));
- }
-
- return "[" + llvm::join(CaptureStrings, ", ") + "]";
+ // TODO: handle VLAs and other weird captures
+ return std::nullopt;
}
-SourceRange getCaptureListRange(const LambdaExpr *Lambda) {
- SourceRange IntroducerRange = Lambda->getIntroducerRange();
- return IntroducerRange;
+// Check if we need a comma before inserting captures
+bool needsCommaBefore(const LambdaExpr *Lambda, SourceLocation InsertLoc,
+ const SourceManager &SM, const LangOptions &LangOpts) {
+ // If there are explicit captures, we need a comma
+ return Lambda->explicit_capture_begin() != Lambda->explicit_capture_end();
}
} // namespace
@@ -102,24 +96,72 @@ void AvoidDefaultLambdaCaptureCheck::check(
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
assert(Lambda);
+ const SourceManager &SM = *Result.SourceManager;
+ const LangOptions &LangOpts = Result.Context->getLangOpts();
+
const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
if (DefaultCaptureLoc.isInvalid())
return;
- // Build the replacement capture list
- std::string NewCaptureList = buildExplicitCaptureList(
- Lambda, *Result.SourceManager, Result.Context->getLangOpts());
-
- // Get the range of the entire capture list [...]
- SourceRange CaptureListRange = getCaptureListRange(Lambda);
-
auto Diag = diag(DefaultCaptureLoc,
"lambda default captures are discouraged; "
"prefer to capture specific variables explicitly");
- // Only provide fixit if we can determine a valid replacement
- if (CaptureListRange.isValid() && !NewCaptureList.empty()) {
- Diag << FixItHint::CreateReplacement(CaptureListRange, NewCaptureList);
+ // Get the range of the default capture token to remove
+ SourceRange DefaultRange = getDefaultCaptureRange(Lambda, SM, LangOpts);
+ if (!DefaultRange.isValid())
+ return;
+
+ // Collect all implicit captures that need to be made explicit
+ std::vector<std::string> ImplicitCaptureTexts;
+ for (const auto &Capture : Lambda->implicit_captures()) {
+ if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
+ ImplicitCaptureTexts.push_back(CaptureText.value());
+ }
+ }
+
+ // If there are no implicit captures, just remove the default capture
+ if (ImplicitCaptureTexts.empty()) {
+ // Also remove any trailing comma if it exists
+ SourceLocation AfterDefault = DefaultRange.getEnd();
+ SourceLocation CommaLoc = Lexer::findLocationAfterToken(
+ AfterDefault, tok::comma, SM, LangOpts, false);
+
+ if (CommaLoc.isValid()) {
+ // Remove default capture and the comma
+ SourceRange RemovalRange(DefaultRange.getBegin(), CommaLoc);
+ Diag << FixItHint::CreateRemoval(RemovalRange);
+ } else {
+ // Just remove the default capture
+ Diag << FixItHint::CreateRemoval(DefaultRange);
+ }
+ return;
+ }
+
+ // Find where to insert the implicit captures
+ SourceLocation InsertLoc =
+ getImplicitCaptureInsertionLoc(Lambda, SM, LangOpts);
+ if (!InsertLoc.isValid())
+ return;
+
+ // Apply the transformations:
+ // 1. Remove the default capture
+ Diag << FixItHint::CreateRemoval(DefaultRange);
+
+ // 2. Insert the explicit captures if any
+ if (!ImplicitCaptureTexts.empty()) {
+ // Build the insertion text for implicit captures
+ std::string InsertionText;
+ bool NeedsComma = needsCommaBefore(Lambda, InsertLoc, SM, LangOpts);
+
+ for (size_t I = 0; I < ImplicitCaptureTexts.size(); ++I) {
+ if (NeedsComma || I > 0) {
+ InsertionText += ", ";
+ }
+ InsertionText += ImplicitCaptureTexts[I];
+ }
+
+ Diag << FixItHint::CreateInsertion(InsertLoc, InsertionText);
}
}
>From dd65b903b04d4bc2cd5587723eb55fc8ea5400e9 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 13:16:40 -0400
Subject: [PATCH 26/29] go back to the hacky string manipulation
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../AvoidDefaultLambdaCaptureCheck.cpp | 122 ++++--------------
1 file changed, 26 insertions(+), 96 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index 72294cc164360..e0b9a8b44a29f 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -20,45 +20,6 @@ AST_MATCHER(LambdaExpr, hasDefaultCapture) {
return Node.getCaptureDefault() != LCD_None;
}
-// Find the source range of the default capture token (= or &)
-SourceRange getDefaultCaptureRange(const LambdaExpr *Lambda,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
- SourceLocation DefaultLoc = Lambda->getCaptureDefaultLoc();
- if (DefaultLoc.isInvalid())
- return SourceRange();
-
- // The default capture is a single token
- SourceLocation EndLoc =
- Lexer::getLocForEndOfToken(DefaultLoc, 0, SM, LangOpts);
- return SourceRange(DefaultLoc, EndLoc);
-}
-
-// Find where to insert implicit captures
-SourceLocation getImplicitCaptureInsertionLoc(const LambdaExpr *Lambda,
- const SourceManager &SM,
- const LangOptions &LangOpts) {
- // If there are explicit captures, insert after the last one
- if (Lambda->explicit_capture_begin() != Lambda->explicit_capture_end()) {
- // Find the location after the last explicit capture
- const auto *LastExplicit = Lambda->explicit_capture_end() - 1;
- SourceLocation LastLoc = LastExplicit->getLocation();
- if (LastLoc.isValid()) {
- return Lexer::getLocForEndOfToken(LastLoc, 0, SM, LangOpts);
- }
- }
-
- // If no explicit captures, insert after the default capture
- SourceLocation DefaultLoc = Lambda->getCaptureDefaultLoc();
- if (DefaultLoc.isValid()) {
- return Lexer::getLocForEndOfToken(DefaultLoc, 0, SM, LangOpts);
- }
-
- // Fallback: insert at the beginning of the capture list
- return Lambda->getIntroducerRange().getBegin().getLocWithOffset(1);
-}
-
-// Generate the text for an implicit capture
std::optional<std::string>
generateImplicitCaptureText(const LambdaCapture &Capture) {
if (Capture.capturesThis()) {
@@ -74,15 +35,13 @@ generateImplicitCaptureText(const LambdaCapture &Capture) {
return Result;
}
- // TODO: handle VLAs and other weird captures
- return std::nullopt;
-}
+ if (Capture.capturesVLAType()) {
+ // VLA captures are rare and complex - for now we skip them
+ // A full implementation would need to handle the VLA type properly
+ return std::nullopt;
+ }
-// Check if we need a comma before inserting captures
-bool needsCommaBefore(const LambdaExpr *Lambda, SourceLocation InsertLoc,
- const SourceManager &SM, const LangOptions &LangOpts) {
- // If there are explicit captures, we need a comma
- return Lambda->explicit_capture_begin() != Lambda->explicit_capture_end();
+ return std::nullopt;
}
} // namespace
@@ -96,9 +55,6 @@ void AvoidDefaultLambdaCaptureCheck::check(
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
assert(Lambda);
- const SourceManager &SM = *Result.SourceManager;
- const LangOptions &LangOpts = Result.Context->getLangOpts();
-
const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
if (DefaultCaptureLoc.isInvalid())
return;
@@ -107,61 +63,35 @@ void AvoidDefaultLambdaCaptureCheck::check(
"lambda default captures are discouraged; "
"prefer to capture specific variables explicitly");
- // Get the range of the default capture token to remove
- SourceRange DefaultRange = getDefaultCaptureRange(Lambda, SM, LangOpts);
- if (!DefaultRange.isValid())
- return;
+ // Build the complete replacement capture list
+ std::vector<std::string> AllCaptures;
- // Collect all implicit captures that need to be made explicit
- std::vector<std::string> ImplicitCaptureTexts;
- for (const auto &Capture : Lambda->implicit_captures()) {
+ // Add explicit captures first (preserve their order)
+ for (const auto &Capture : Lambda->explicit_captures()) {
if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
- ImplicitCaptureTexts.push_back(CaptureText.value());
+ AllCaptures.push_back(CaptureText.value());
}
}
- // If there are no implicit captures, just remove the default capture
- if (ImplicitCaptureTexts.empty()) {
- // Also remove any trailing comma if it exists
- SourceLocation AfterDefault = DefaultRange.getEnd();
- SourceLocation CommaLoc = Lexer::findLocationAfterToken(
- AfterDefault, tok::comma, SM, LangOpts, false);
-
- if (CommaLoc.isValid()) {
- // Remove default capture and the comma
- SourceRange RemovalRange(DefaultRange.getBegin(), CommaLoc);
- Diag << FixItHint::CreateRemoval(RemovalRange);
- } else {
- // Just remove the default capture
- Diag << FixItHint::CreateRemoval(DefaultRange);
+ // Add implicit captures (convert to explicit)
+ for (const auto &Capture : Lambda->implicit_captures()) {
+ if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
+ AllCaptures.push_back(CaptureText.value());
}
- return;
}
- // Find where to insert the implicit captures
- SourceLocation InsertLoc =
- getImplicitCaptureInsertionLoc(Lambda, SM, LangOpts);
- if (!InsertLoc.isValid())
- return;
-
- // Apply the transformations:
- // 1. Remove the default capture
- Diag << FixItHint::CreateRemoval(DefaultRange);
-
- // 2. Insert the explicit captures if any
- if (!ImplicitCaptureTexts.empty()) {
- // Build the insertion text for implicit captures
- std::string InsertionText;
- bool NeedsComma = needsCommaBefore(Lambda, InsertLoc, SM, LangOpts);
-
- for (size_t I = 0; I < ImplicitCaptureTexts.size(); ++I) {
- if (NeedsComma || I > 0) {
- InsertionText += ", ";
- }
- InsertionText += ImplicitCaptureTexts[I];
- }
+ // Build the final capture list
+ std::string ReplacementText;
+ if (AllCaptures.empty()) {
+ ReplacementText = "[]";
+ } else {
+ ReplacementText = "[" + llvm::join(AllCaptures, ", ") + "]";
+ }
- Diag << FixItHint::CreateInsertion(InsertLoc, InsertionText);
+ // Replace the entire capture list with the explicit version
+ SourceRange IntroducerRange = Lambda->getIntroducerRange();
+ if (IntroducerRange.isValid()) {
+ Diag << FixItHint::CreateReplacement(IntroducerRange, ReplacementText);
}
}
>From a9509f3a37fa9350e1de1ee0223f10dc17ff9a1d Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 13:17:28 -0400
Subject: [PATCH 27/29] remove AI comments
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../readability/AvoidDefaultLambdaCaptureCheck.cpp | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index e0b9a8b44a29f..66d4c9653860a 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -63,24 +63,21 @@ void AvoidDefaultLambdaCaptureCheck::check(
"lambda default captures are discouraged; "
"prefer to capture specific variables explicitly");
- // Build the complete replacement capture list
std::vector<std::string> AllCaptures;
- // Add explicit captures first (preserve their order)
for (const auto &Capture : Lambda->explicit_captures()) {
if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
AllCaptures.push_back(CaptureText.value());
}
}
- // Add implicit captures (convert to explicit)
for (const auto &Capture : Lambda->implicit_captures()) {
if (const auto CaptureText = generateImplicitCaptureText(Capture)) {
AllCaptures.push_back(CaptureText.value());
}
}
- // Build the final capture list
+ // Replace with new capture list
std::string ReplacementText;
if (AllCaptures.empty()) {
ReplacementText = "[]";
@@ -88,7 +85,6 @@ void AvoidDefaultLambdaCaptureCheck::check(
ReplacementText = "[" + llvm::join(AllCaptures, ", ") + "]";
}
- // Replace the entire capture list with the explicit version
SourceRange IntroducerRange = Lambda->getIntroducerRange();
if (IntroducerRange.isValid()) {
Diag << FixItHint::CreateReplacement(IntroducerRange, ReplacementText);
>From e9e0f9ac4d6d272f22a961ab17028849e6a03142 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 14:03:59 -0400
Subject: [PATCH 28/29] fix namespacing issues
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../AvoidDefaultLambdaCaptureCheck.cpp | 38 +++++++++----------
clang/include/clang/ASTMatchers/ASTMatchers.h | 14 +++++++
2 files changed, 32 insertions(+), 20 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index 66d4c9653860a..7dfe07a8cf7b1 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -11,24 +11,18 @@
#include "clang/Basic/Lambda.h"
#include "clang/Lex/Lexer.h"
-using namespace clang::ast_matchers;
-
-namespace clang::tidy::readability {
+using namespace clang::tidy::readability;
namespace {
-AST_MATCHER(LambdaExpr, hasDefaultCapture) {
- return Node.getCaptureDefault() != LCD_None;
-}
-
-std::optional<std::string>
-generateImplicitCaptureText(const LambdaCapture &Capture) {
+static std::optional<std::string>
+generateImplicitCaptureText(const clang::LambdaCapture &Capture) {
if (Capture.capturesThis()) {
- return Capture.getCaptureKind() == LCK_StarThis ? "*this" : "this";
+ return Capture.getCaptureKind() == clang::LCK_StarThis ? "*this" : "this";
}
if (Capture.capturesVariable()) {
std::string Result;
- if (Capture.getCaptureKind() == LCK_ByRef) {
+ if (Capture.getCaptureKind() == clang::LCK_ByRef) {
Result += "&";
}
Result += Capture.getCapturedVar()->getName().str();
@@ -46,16 +40,21 @@ generateImplicitCaptureText(const LambdaCapture &Capture) {
} // namespace
-void AvoidDefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) {
- Finder->addMatcher(lambdaExpr(hasDefaultCapture()).bind("lambda"), this);
+void AvoidDefaultLambdaCaptureCheck::registerMatchers(
+ clang::ast_matchers::MatchFinder *Finder) {
+ Finder->addMatcher(
+ clang::ast_matchers::lambdaExpr(clang::ast_matchers::hasDefaultCapture())
+ .bind("lambda"),
+ this);
}
void AvoidDefaultLambdaCaptureCheck::check(
- const MatchFinder::MatchResult &Result) {
- const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
+ const clang::ast_matchers::MatchFinder::MatchResult &Result) {
+ const auto *Lambda = Result.Nodes.getNodeAs<clang::LambdaExpr>("lambda");
assert(Lambda);
- const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc();
+ const clang::SourceLocation DefaultCaptureLoc =
+ Lambda->getCaptureDefaultLoc();
if (DefaultCaptureLoc.isInvalid())
return;
@@ -85,10 +84,9 @@ void AvoidDefaultLambdaCaptureCheck::check(
ReplacementText = "[" + llvm::join(AllCaptures, ", ") + "]";
}
- SourceRange IntroducerRange = Lambda->getIntroducerRange();
+ clang::SourceRange IntroducerRange = Lambda->getIntroducerRange();
if (IntroducerRange.isValid()) {
- Diag << FixItHint::CreateReplacement(IntroducerRange, ReplacementText);
+ Diag << clang::FixItHint::CreateReplacement(IntroducerRange,
+ ReplacementText);
}
}
-
-} // namespace clang::tidy::readability
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 492863ddfc4a1..0a0d42ca259b8 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -5096,6 +5096,20 @@ AST_MATCHER_P(LambdaCapture, capturesVar, internal::Matcher<ValueDecl>,
/// matches `[this]() { return cc; }`.
AST_MATCHER(LambdaCapture, capturesThis) { return Node.capturesThis(); }
+/// Matches lambda expressions that have default capture modes.
+///
+/// Given
+/// \code
+/// auto l1 = [=]() {}; // matches
+/// auto l2 = [&]() {}; // matches
+/// auto l3 = []() {}; // does not match
+/// \endcode
+/// lambdaExpr(hasDefaultCapture())
+/// matches l1 and l2, but not l3.
+AST_MATCHER(LambdaExpr, hasDefaultCapture) {
+ return Node.getCaptureDefault() != LCD_None;
+}
+
/// Matches a constructor call expression which uses list initialization.
AST_MATCHER(CXXConstructExpr, isListInitialization) {
return Node.isListInitialization();
>From b2c3cc2e8e927a9d10598b2c625324e4df180b69 Mon Sep 17 00:00:00 2001
From: jjmarr-amd <JJ.Marr at amd.com>
Date: Mon, 29 Sep 2025 14:31:34 -0400
Subject: [PATCH 29/29] remove anonymous namespace
on-behalf-of: @amd <JJ.Marr at amd.com>
---
.../clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp | 3 ---
1 file changed, 3 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
index 7dfe07a8cf7b1..e75acb9551701 100644
--- a/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
@@ -13,7 +13,6 @@
using namespace clang::tidy::readability;
-namespace {
static std::optional<std::string>
generateImplicitCaptureText(const clang::LambdaCapture &Capture) {
if (Capture.capturesThis()) {
@@ -38,8 +37,6 @@ generateImplicitCaptureText(const clang::LambdaCapture &Capture) {
return std::nullopt;
}
-} // namespace
-
void AvoidDefaultLambdaCaptureCheck::registerMatchers(
clang::ast_matchers::MatchFinder *Finder) {
Finder->addMatcher(
More information about the cfe-commits
mailing list