-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang-tidy] Add readability-avoid-default-lambda-capture #160150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
jjmarr-amd
wants to merge
38
commits into
llvm:main
Choose a base branch
from
jjmarr-amd:DefaultLambdaCapture
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+328
−0
Open
Changes from 22 commits
Commits
Show all changes
38 commits
Select commit
Hold shift + click to select a range
35df1c6
Bugprone-default-lambda-capture
jjmarr-amd dbb903f
Merge branch 'main' of github.com:llvm/llvm-project into DefaultLambd…
jjmarr-amd 689f95b
Fix headers
jjmarr-amd 9991b9c
remove superfluous comments.
jjmarr-amd db17a4c
add new matcher
jjmarr-amd 7dcf216
Replace if with assert
jjmarr-amd 176d195
Remove specific warning type
jjmarr-amd 5f23dff
Sync documentation to release notes
jjmarr-amd 4c41332
Update clang-tools-extra/clang-tidy/bugprone/DefaultLambdaCaptureCheck.h
jjmarr-amd 330dbd8
Remove superfluous include
jjmarr-amd 31366e6
Fix doc and release notes
jjmarr-amd 70df9df
Fix const
jjmarr-amd 0418517
Merge branch 'main' into DefaultLambdaCapture
jjmarr-amd 0bcdbc4
Fix header guard
jjmarr-amd ac709f4
Fix header spelling
jjmarr-amd 5d4c2ca
Rename check to readability-default-lambda-capture
jjmarr-amd c0b90d1
Update clang-tools-extra/docs/clang-tidy/checks/readability/default-l…
jjmarr-amd 1172f73
update doc
jjmarr-amd 66e6aaa
rename check to readability-avoid-default-lambda-capture
jjmarr-amd 4bf58b6
use C++ style comments
jjmarr-amd a807dd0
Update clang-tools-extra/docs/clang-tidy/checks/readability/avoid-def…
jjmarr-amd 8fdc097
fix doc again
jjmarr-amd ab8f4b9
remove reference to coding guideline
jjmarr-amd a4348de
Merge branch 'main' of github.com:llvm/llvm-project into DefaultLambd…
jjmarr-amd 13b5049
rephrase
jjmarr-amd 043df7c
commit vibe coded work
jjmarr-amd 33af58b
attempt to fix to use something that isn't weird string manipulation
jjmarr-amd 51aa182
more vibe coding with human intervention
jjmarr-amd dd65b90
go back to the hacky string manipulation
jjmarr-amd a9509f3
remove AI comments
jjmarr-amd e9e0f9a
fix namespacing issues
jjmarr-amd b2c3cc2
remove anonymous namespace
jjmarr-amd 969558e
simplify per code review
jjmarr-amd 359fd6c
Use IIFE so ReplacementText can be const.
jjmarr-amd 4e10e78
simplify code even more
jjmarr-amd 9765c90
Turns out this check doesn't like templated lambdas
jjmarr-amd 33a79a0
ignore VLAs
jjmarr-amd 8f21201
move around doc paragraphs
jjmarr-amd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
40 changes: 40 additions & 0 deletions
40
clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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 "AvoidDefaultLambdaCaptureCheck.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
|
||
using namespace clang::ast_matchers; | ||
|
||
namespace clang::tidy::readability { | ||
|
||
namespace { | ||
AST_MATCHER(LambdaExpr, hasDefaultCapture) { | ||
return Node.getCaptureDefault() != LCD_None; | ||
} | ||
jjmarr-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
} // namespace | ||
|
||
void AvoidDefaultLambdaCaptureCheck::registerMatchers(MatchFinder *Finder) { | ||
Finder->addMatcher(lambdaExpr(hasDefaultCapture()).bind("lambda"), this); | ||
} | ||
|
||
void AvoidDefaultLambdaCaptureCheck::check( | ||
const MatchFinder::MatchResult &Result) { | ||
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda"); | ||
assert(Lambda); | ||
|
||
const SourceLocation DefaultCaptureLoc = Lambda->getCaptureDefaultLoc(); | ||
if (DefaultCaptureLoc.isInvalid()) | ||
return; | ||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
diag(DefaultCaptureLoc, "lambda default captures are discouraged; " | ||
jjmarr-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
"prefer to capture specific variables explicitly"); | ||
} | ||
|
||
} // namespace clang::tidy::readability |
33 changes: 33 additions & 0 deletions
33
clang-tools-extra/clang-tidy/readability/AvoidDefaultLambdaCaptureCheck.h
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// 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_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/avoid-default-lambda-capture.html | ||
class AvoidDefaultLambdaCaptureCheck : public ClangTidyCheck { | ||
public: | ||
AvoidDefaultLambdaCaptureCheck(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::readability | ||
|
||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_AVOIDDEFAULTLAMBDACAPTURECHECK_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
...tools-extra/docs/clang-tidy/checks/readability/avoid-default-lambda-capture.rst
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. ``[&](){ ... }``, ``[=](){ ... }``) | ||
jjmarr-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
||
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/ | ||
jjmarr-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vbvictor marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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 | ||
jjmarr-amd marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
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; | ||
} | ||
); | ||
} | ||
} |
98 changes: 98 additions & 0 deletions
98
clang-tools-extra/test/clang-tidy/checkers/readability/avoid-default-lambda-capture.cpp
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
// RUN: %check_clang_tidy %s readability-avoid-default-lambda-capture %t | ||
|
||
void test_default_captures() { | ||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
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-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-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-avoid-default-lambda-capture] | ||
|
||
auto lambda4 = [&, value](int x) { return value + another + x; }; | ||
jjmarr-amd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// 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() { | ||
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 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-avoid-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 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-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-avoid-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 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-avoid-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 default captures are discouraged; prefer to capture specific variables explicitly [readability-avoid-default-lambda-capture] | ||
} | ||
|
||
void instantiate_templates() { | ||
test_template_lambdas<int>(); | ||
test_template_lambdas<double>(); | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.