Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
35df1c6
Bugprone-default-lambda-capture
jjmarr-amd Jul 11, 2025
dbb903f
Merge branch 'main' of github.com:llvm/llvm-project into DefaultLambd…
jjmarr-amd Sep 22, 2025
689f95b
Fix headers
jjmarr-amd Sep 22, 2025
9991b9c
remove superfluous comments.
jjmarr-amd Sep 22, 2025
db17a4c
add new matcher
jjmarr-amd Sep 22, 2025
7dcf216
Replace if with assert
jjmarr-amd Sep 22, 2025
176d195
Remove specific warning type
jjmarr-amd Sep 22, 2025
5f23dff
Sync documentation to release notes
jjmarr-amd Sep 22, 2025
4c41332
Update clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
jjmarr-amd Sep 22, 2025
330dbd8
Remove superfluous include
jjmarr-amd Sep 22, 2025
31366e6
Fix doc and release notes
jjmarr-amd Sep 22, 2025
70df9df
Fix const
jjmarr-amd Sep 22, 2025
0418517
Merge branch 'main' into DefaultLambdaCapture
jjmarr-amd Sep 22, 2025
0bcdbc4
Fix header guard
jjmarr-amd Sep 23, 2025
ac709f4
Fix header spelling
jjmarr-amd Sep 23, 2025
5d4c2ca
Rename check to readability-default-lambda-capture
jjmarr-amd Sep 24, 2025
c0b90d1
Update clang-tools-extra/docs/clang-tidy/checks/readability/default-l…
jjmarr-amd Sep 24, 2025
1172f73
update doc
jjmarr-amd Sep 25, 2025
66e6aaa
rename check to readability-avoid-default-lambda-capture
jjmarr-amd Sep 25, 2025
4bf58b6
use C++ style comments
jjmarr-amd Sep 25, 2025
a807dd0
Update clang-tools-extra/docs/clang-tidy/checks/readability/avoid-def…
jjmarr-amd Sep 25, 2025
8fdc097
fix doc again
jjmarr-amd Sep 25, 2025
ab8f4b9
remove reference to coding guideline
jjmarr-amd Sep 25, 2025
a4348de
Merge branch 'main' of github.com:llvm/llvm-project into DefaultLambd…
jjmarr-amd Sep 29, 2025
13b5049
rephrase
jjmarr-amd Sep 29, 2025
043df7c
commit vibe coded work
jjmarr-amd Sep 29, 2025
33af58b
attempt to fix to use something that isn't weird string manipulation
jjmarr-amd Sep 29, 2025
51aa182
more vibe coding with human intervention
jjmarr-amd Sep 29, 2025
dd65b90
go back to the hacky string manipulation
jjmarr-amd Sep 29, 2025
a9509f3
remove AI comments
jjmarr-amd Sep 29, 2025
e9e0f9a
fix namespacing issues
jjmarr-amd Sep 29, 2025
b2c3cc2
remove anonymous namespace
jjmarr-amd Sep 29, 2025
969558e
simplify per code review
jjmarr-amd Oct 1, 2025
359fd6c
Use IIFE so ReplacementText can be const.
jjmarr-amd Oct 1, 2025
4e10e78
simplify code even more
jjmarr-amd Oct 3, 2025
9765c90
Turns out this check doesn't like templated lambdas
jjmarr-amd Oct 3, 2025
33a79a0
ignore VLAs
jjmarr-amd Oct 8, 2025
8f21201
move around doc paragraphs
jjmarr-amd Oct 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
//
//===----------------------------------------------------------------------===//

#include "DefaultLambdaCaptureCheck.h"
#include "AvoidDefaultLambdaCaptureCheck.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"

using namespace clang::ast_matchers;
Expand All @@ -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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,20 @@
//
//===----------------------------------------------------------------------===//

#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"

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
*/
class DefaultLambdaCaptureCheck : public ClangTidyCheck {
/// 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:
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;
Expand All @@ -31,4 +30,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
2 changes: 1 addition & 1 deletion clang-tools-extra/clang-tidy/readability/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -15,7 +16,6 @@ add_clang_library(clangTidyReadabilityModule STATIC
ContainerDataPointerCheck.cpp
ContainerSizeEmptyCheck.cpp
ConvertMemberFunctionsToStatic.cpp
DefaultLambdaCaptureCheck.cpp
DeleteNullPointerCheck.cpp
DuplicateIncludeCheck.cpp
ElseAfterReturnCheck.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down Expand Up @@ -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>(
Expand Down
4 changes: 2 additions & 2 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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. ``[&](){ ... }``, ``[=](){ ... }``)

Expand Down
2 changes: 1 addition & 1 deletion clang-tools-extra/docs/clang-tidy/checks/list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
.. title:: clang-tidy - readability-avoid-default-lambda-capture

readability-avoid-default-lambda-capture
=========================================

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
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/
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todo: open up the HTML and verify the new link works.

R2021a/bugfinder/ref/autosarc14rulea512.html>`__

Example
-------

.. code-block:: c++

#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;
}
);
}
}

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.

.. code-block:: c++

#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;
}
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -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() {
Expand Down Expand Up @@ -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);
};
Expand All @@ -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 {
Expand All @@ -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; };
Expand All @@ -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() {
Expand Down