[clang-tools-extra] [clang-tidy] Add new check bugprone-capture-this-by-field (PR #130297)
Congcong Cai via cfe-commits
cfe-commits at lists.llvm.org
Tue Mar 11 18:30:28 PDT 2025
================
@@ -0,0 +1,114 @@
+//===--- CapturingThisByFieldCheck.cpp - clang-tidy -----------------------===//
+//
+// 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 "CapturingThisByFieldCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/ASTMatchers/ASTMatchersMacros.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+namespace {
+
+AST_MATCHER(CXXRecordDecl, correctHandleCaptureThisLambda) {
+ // unresolved
+ if (Node.needsOverloadResolutionForCopyConstructor() &&
+ Node.needsImplicitCopyConstructor())
+ return false;
+ if (Node.needsOverloadResolutionForMoveConstructor() &&
+ Node.needsImplicitMoveConstructor())
+ return false;
+ if (Node.needsOverloadResolutionForCopyAssignment() &&
+ Node.needsImplicitCopyAssignment())
+ return false;
+ if (Node.needsOverloadResolutionForMoveAssignment() &&
+ Node.needsImplicitMoveAssignment())
+ return false;
+ // default but not deleted
+ if (Node.hasSimpleCopyConstructor())
+ return false;
+ if (Node.hasSimpleMoveConstructor())
+ return false;
+ if (Node.hasSimpleCopyAssignment())
+ return false;
+ if (Node.hasSimpleMoveAssignment())
+ return false;
+
+ for (CXXConstructorDecl const *C : Node.ctors()) {
+ if (C->isCopyOrMoveConstructor() && C->isDefaulted() && !C->isDeleted())
+ return false;
+ }
+ for (CXXMethodDecl const *M : Node.methods()) {
+ if (M->isCopyAssignmentOperator() && M->isDefaulted() && !M->isDeleted())
+ return false;
+ if (M->isMoveAssignmentOperator() && M->isDefaulted() && !M->isDeleted())
+ return false;
+ }
+ // FIXME: find ways to identifier correct handle capture this lambda
+ return true;
+}
+
+} // namespace
+
+CapturingThisByFieldCheck::CapturingThisByFieldCheck(StringRef Name,
+ ClangTidyContext *Context)
+ : ClangTidyCheck(Name, Context),
+ FunctionWrapperTypes(utils::options::parseStringList(Options.get(
+ "FunctionWrapperTypes", "::std::function;::boost::function"))) {}
+void CapturingThisByFieldCheck::storeOptions(
+ ClangTidyOptions::OptionMap &Opts) {
+ Options.store(Opts, "FunctionWrapperTypes",
+ utils::options::serializeStringList(FunctionWrapperTypes));
+}
+
+void CapturingThisByFieldCheck::registerMatchers(MatchFinder *Finder) {
+ auto IsStdFunctionField =
+ fieldDecl(hasType(cxxRecordDecl(
+ matchers::matchesAnyListedName(FunctionWrapperTypes))))
+ .bind("field");
+ auto CaptureThis = lambdaCapture(anyOf(
+ // [this]
+ capturesThis(),
+ // [self = this]
+ capturesVar(varDecl(hasInitializer(cxxThisExpr())))));
+ auto IsInitWithLambda = cxxConstructExpr(hasArgument(
+ 0,
+ lambdaExpr(hasAnyCapture(CaptureThis.bind("capture"))).bind("lambda")));
+ Finder->addMatcher(
+ cxxRecordDecl(
+ has(cxxConstructorDecl(
+ unless(isCopyConstructor()), unless(isMoveConstructor()),
+ hasAnyConstructorInitializer(cxxCtorInitializer(
+ isMemberInitializer(), forField(IsStdFunctionField),
+ withInitializer(IsInitWithLambda))))),
+ unless(correctHandleCaptureThisLambda())),
+ this);
+}
+
+void CapturingThisByFieldCheck::check(const MatchFinder::MatchResult &Result) {
+ const auto *Capture = Result.Nodes.getNodeAs<LambdaCapture>("capture");
+ const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>("lambda");
+ const auto *Field = Result.Nodes.getNodeAs<FieldDecl>("field");
+ diag(Lambda->getBeginLoc(),
+ "using lambda expressions to capture 'this' and storing it in class "
+ "member will cause potential variable lifetime issue when the class "
----------------
HerrCai0907 wrote:
Let us align with field. IMO member also includes member functions. clang's type also use field e.g. `FieldDecl`
https://github.com/llvm/llvm-project/pull/130297
More information about the cfe-commits
mailing list