12#include "clang/AST/DeclCXX.h"
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/ASTMatchers/ASTMatchers.h"
15#include "clang/ASTMatchers/ASTMatchersMacros.h"
23AST_MATCHER(CXXRecordDecl, correctHandleCaptureThisLambda) {
25 if (Node.needsOverloadResolutionForCopyConstructor() &&
26 Node.needsImplicitCopyConstructor())
28 if (Node.needsOverloadResolutionForMoveConstructor() &&
29 Node.needsImplicitMoveConstructor())
31 if (Node.needsOverloadResolutionForCopyAssignment() &&
32 Node.needsImplicitCopyAssignment())
34 if (Node.needsOverloadResolutionForMoveAssignment() &&
35 Node.needsImplicitMoveAssignment())
38 if (Node.hasSimpleCopyConstructor())
40 if (Node.hasSimpleMoveConstructor())
42 if (Node.hasSimpleCopyAssignment())
44 if (Node.hasSimpleMoveAssignment())
47 for (
const CXXConstructorDecl *C : Node.ctors()) {
48 if (
C->isCopyOrMoveConstructor() &&
C->isDefaulted() && !
C->isDeleted())
51 for (
const CXXMethodDecl *M : Node.methods()) {
52 if (M->isCopyAssignmentOperator())
53 llvm::errs() << M->isDeleted() <<
"\n";
54 if (M->isCopyAssignmentOperator() && M->isDefaulted() && !M->isDeleted())
56 if (M->isMoveAssignmentOperator() && M->isDefaulted() && !M->isDeleted())
66 "::std::function;::std::move_only_function;::boost::function";
68 "::std::bind;::boost::bind;::std::bind_front;::std::bind_back;"
69 "::boost::compat::bind_front;::boost::compat::bind_back";
74 FunctionWrapperTypes(
utils::options::parseStringList(
76 BindFunctions(
utils::options::parseStringList(
80 Options.store(Opts,
"FunctionWrapperTypes",
82 Options.store(Opts,
"BindFunctions",
87 auto IsStdFunctionField =
88 fieldDecl(hasType(cxxRecordDecl(
91 auto CaptureThis = lambdaCapture(anyOf(
95 capturesVar(varDecl(hasInitializer(cxxThisExpr())))));
96 auto IsLambdaCapturingThis =
97 lambdaExpr(hasAnyCapture(CaptureThis)).bind(
"lambda");
99 auto IsBindCapturingThis =
103 hasAnyArgument(cxxThisExpr()))
106 auto IsInitWithLambdaOrBind =
107 anyOf(IsLambdaCapturingThis, IsBindCapturingThis,
108 cxxConstructExpr(hasArgument(
109 0, anyOf(IsLambdaCapturingThis, IsBindCapturingThis))));
113 anyOf(has(cxxConstructorDecl(
114 unless(isCopyConstructor()), unless(isMoveConstructor()),
115 hasAnyConstructorInitializer(cxxCtorInitializer(
116 isMemberInitializer(), forField(IsStdFunctionField),
117 withInitializer(IsInitWithLambdaOrBind))))),
118 has(fieldDecl(IsStdFunctionField,
119 hasInClassInitializer(IsInitWithLambdaOrBind)))),
120 unless(correctHandleCaptureThisLambda())),
124 const MatchFinder::MatchResult &Result) {
125 if (
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>(
"lambda")) {
126 diag(Lambda->getBeginLoc(),
127 "'this' captured by a lambda and stored in a class member variable; "
128 "disable implicit class copying/moving to prevent potential "
130 }
else if (
const auto *Bind = Result.Nodes.getNodeAs<CallExpr>(
"bind")) {
131 const auto *Callee = Result.Nodes.getNodeAs<FunctionDecl>(
"callee");
133 diag(Bind->getBeginLoc(),
134 "'this' captured by a '%0' call and stored in a class member "
135 "variable; disable implicit class copying/moving to prevent potential "
137 << Callee->getQualifiedNameAsString();
140 const auto *Field = Result.Nodes.getNodeAs<FieldDecl>(
"field");
143 diag(Field->getLocation(),
144 "class member of type '%0' that stores captured 'this'",
146 << Field->getType().getAsString();
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.
void registerMatchers(ast_matchers::MatchFinder *Finder) override
CapturingThisInMemberVariableCheck(StringRef Name, ClangTidyContext *Context)
void storeOptions(ClangTidyOptions::OptionMap &Opts) override
void check(const ast_matchers::MatchFinder::MatchResult &Result) override
constexpr const char * DefaultFunctionWrapperTypes
constexpr const char * DefaultBindFunctions
AST_MATCHER(BinaryOperator, isRelationalOperator)
inline ::clang::ast_matchers::internal::Matcher< NamedDecl > matchesAnyListedName(llvm::ArrayRef< StringRef > NameList)
std::string serializeStringList(ArrayRef< StringRef > Strings)
Serialize a sequence of names that can be parsed by parseStringList.
llvm::StringMap< ClangTidyValue > OptionMap