[clang-tools-extra] [clang-tidy] fix false positive in cppcoreguidelines-missing-std-forward (PR #77056)
Qizhi Hu via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 5 19:10:24 PST 2024
https://github.com/jcsxky updated https://github.com/llvm/llvm-project/pull/77056
>From 0f1e72b143d360c1f005f4bd63a378c5277d4480 Mon Sep 17 00:00:00 2001
From: huqizhi <huqizhi at feysh.com>
Date: Wed, 3 Jan 2024 09:44:26 +0800
Subject: [PATCH] [clang-tidy] fix false positive in
cppcoreguidelines-missing-std-forward
---
.../MissingStdForwardCheck.cpp | 60 ++++++++++++++++++-
clang-tools-extra/docs/ReleaseNotes.rst | 5 ++
.../cppcoreguidelines/missing-std-forward.cpp | 31 +++++++++-
3 files changed, 91 insertions(+), 5 deletions(-)
diff --git a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
index 0b85ea19735eef..370de12999aceb 100644
--- a/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/cppcoreguidelines/MissingStdForwardCheck.cpp
@@ -53,16 +53,72 @@ AST_MATCHER(ParmVarDecl, isTemplateTypeParameter) {
FuncTemplate->getTemplateParameters()->getDepth();
}
+AST_MATCHER_P(NamedDecl, hasSameNameAsBoundNode, std::string, BindingID) {
+ IdentifierInfo *II = Node.getIdentifier();
+ if (nullptr == II)
+ return false;
+ StringRef Name = II->getName();
+
+ return Builder->removeBindings(
+ [this, Name](const ast_matchers::internal::BoundNodesMap &Nodes) {
+ const DynTypedNode &BN = Nodes.getNode(this->BindingID);
+ if (const auto *ND = BN.get<NamedDecl>()) {
+ if (!isa<FieldDecl, CXXMethodDecl, VarDecl>(ND))
+ return true;
+ return ND->getName() != Name;
+ }
+ return true;
+ });
+}
+
+AST_MATCHER_P(LambdaCapture, hasCaptureKind, LambdaCaptureKind, Kind) {
+ return Node.getCaptureKind() == Kind;
+}
+
+AST_MATCHER_P(LambdaExpr, hasCaptureDefaultKind, LambdaCaptureDefault, Kind) {
+ return Node.getCaptureDefault() == Kind;
+}
+
} // namespace
void MissingStdForwardCheck::registerMatchers(MatchFinder *Finder) {
+ auto RefToParmImplicit = allOf(
+ equalsBoundNode("var"), hasInitializer(ignoringParenImpCasts(
+ declRefExpr(to(equalsBoundNode("param"))))));
+ auto RefToParm = capturesVar(
+ varDecl(anyOf(hasSameNameAsBoundNode("param"), RefToParmImplicit)));
+ auto HasRefToParm = hasAnyCapture(RefToParm);
+
+ auto CaptureInRef =
+ allOf(hasCaptureDefaultKind(LambdaCaptureDefault::LCD_ByRef),
+ unless(hasAnyCapture(
+ capturesVar(varDecl(hasSameNameAsBoundNode("param"))))));
+ auto CaptureInCopy = allOf(
+ hasCaptureDefaultKind(LambdaCaptureDefault::LCD_ByCopy), HasRefToParm);
+ auto CaptureByRefExplicit = hasAnyCapture(
+ allOf(hasCaptureKind(LambdaCaptureKind::LCK_ByRef), RefToParm));
+
+ auto CapturedInBody =
+ lambdaExpr(anyOf(CaptureInRef, CaptureInCopy, CaptureByRefExplicit));
+ auto CapturedInCaptureList = hasAnyCapture(capturesVar(
+ varDecl(hasInitializer(ignoringParenImpCasts(equalsBoundNode("call"))))));
+
+ auto CapturedInLambda = hasDeclContext(cxxRecordDecl(
+ isLambda(),
+ hasParent(lambdaExpr(forCallable(equalsBoundNode("func")),
+ anyOf(CapturedInCaptureList, CapturedInBody)))));
+
auto ToParam = hasAnyParameter(parmVarDecl(equalsBoundNode("param")));
auto ForwardCallMatcher = callExpr(
- forCallable(equalsBoundNode("func")), argumentCountIs(1),
+ callExpr().bind("call"), argumentCountIs(1),
+ hasArgument(
+ 0, declRefExpr(to(
+ varDecl(optionally(equalsBoundNode("param"))).bind("var")))),
+ forCallable(anyOf(equalsBoundNode("func"), CapturedInLambda)),
callee(unresolvedLookupExpr(hasAnyDeclaration(
namedDecl(hasUnderlyingDecl(hasName("::std::forward")))))),
- hasArgument(0, declRefExpr(to(equalsBoundNode("param"))).bind("ref")),
+
unless(anyOf(hasAncestor(typeLoc()),
hasAncestor(expr(hasUnevaluatedContext())))));
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 4d25e2ebe85f5f..b55599cac3dd06 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -295,6 +295,11 @@ Changes in existing checks
coroutine functions and increase issue detection for cases involving type
aliases with references.
+- Improved :doc:`cppcoreguidelines-missing-std-forward
+ <clang-tidy/checks/cppcoreguidelines/missing-std-forward>` check to
+ provide fixes of false positive that forwarded in capture list and body of
+ lambda.
+
- Improved :doc:`cppcoreguidelines-narrowing-conversions
<clang-tidy/checks/cppcoreguidelines/narrowing-conversions>` check by
extending the `IgnoreConversionFromTypes` option to include types without a
diff --git a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp
index b9720db272e406..443f338ba2046a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/cppcoreguidelines/missing-std-forward.cpp
@@ -90,9 +90,9 @@ void lambda_value_capture(T&& t) {
}
template <class T>
-void lambda_value_reference(T&& t) {
- // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: forwarding reference parameter 't' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
- [&]() { T other = std::forward<T>(t); };
+void lambda_value_capture_copy(T&& t) {
+ // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: forwarding reference parameter 't' is never forwarded inside the function body [cppcoreguidelines-missing-std-forward]
+ [&,t]() { T other = std::forward<T>(t); };
}
} // namespace positive_cases
@@ -147,4 +147,29 @@ class AClass {
T data;
};
+template <class T>
+void lambda_value_reference(T&& t) {
+ [&]() { T other = std::forward<T>(t); };
+}
+
+template<typename T>
+void lambda_value_reference_capture_list_ref_1(T&& t) {
+ [=, &t] { T other = std::forward<T>(t); };
+}
+
+template<typename T>
+void lambda_value_reference_capture_list_ref_2(T&& t) {
+ [&t] { T other = std::forward<T>(t); };
+}
+
+template<typename T>
+void lambda_value_reference_capture_list(T&& t) {
+ [t = std::forward<T>(t)] { t(); };
+}
+
+template <class T>
+void lambda_value_reference_auxiliary_var(T&& t) {
+ [&x = t]() { T other = std::forward<T>(x); };
+}
+
} // namespace negative_cases
More information about the cfe-commits
mailing list