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 if (llvm::any_of(Node.ctors(), [](
const CXXConstructorDecl *C) {
48 return C->isCopyOrMoveConstructor() && C->isDefaulted() &&
52 if (llvm::any_of(Node.methods(), [](
const CXXMethodDecl *M) {
53 return (M->isCopyAssignmentOperator() ||
54 M->isMoveAssignmentOperator()) &&
55 M->isDefaulted() && !M->isDeleted();
65 "::std::function;::std::move_only_function;::boost::function";
67 "::std::bind;::boost::bind;::std::bind_front;::std::bind_back;"
68 "::boost::compat::bind_front;::boost::compat::bind_back";
73 FunctionWrapperTypes(
utils::options::parseStringList(
75 BindFunctions(
utils::options::parseStringList(
79 Options.store(Opts,
"FunctionWrapperTypes",
81 Options.store(Opts,
"BindFunctions",
86 auto IsStdFunctionField =
87 fieldDecl(hasType(cxxRecordDecl(
90 auto CaptureThis = lambdaCapture(anyOf(
94 capturesVar(varDecl(hasInitializer(cxxThisExpr())))));
95 auto IsLambdaCapturingThis =
96 lambdaExpr(hasAnyCapture(CaptureThis)).bind(
"lambda");
98 auto IsBindCapturingThis =
102 hasAnyArgument(cxxThisExpr()))
105 auto IsInitWithLambdaOrBind =
106 anyOf(IsLambdaCapturingThis, IsBindCapturingThis,
107 cxxConstructExpr(hasArgument(
108 0, anyOf(IsLambdaCapturingThis, IsBindCapturingThis))));
112 anyOf(has(cxxConstructorDecl(
113 unless(isCopyConstructor()), unless(isMoveConstructor()),
114 hasAnyConstructorInitializer(cxxCtorInitializer(
115 isMemberInitializer(), forField(IsStdFunctionField),
116 withInitializer(IsInitWithLambdaOrBind))))),
117 has(fieldDecl(IsStdFunctionField,
118 hasInClassInitializer(IsInitWithLambdaOrBind)))),
119 unless(correctHandleCaptureThisLambda())),
123 const MatchFinder::MatchResult &Result) {
124 if (
const auto *Lambda = Result.Nodes.getNodeAs<LambdaExpr>(
"lambda")) {
125 diag(Lambda->getBeginLoc(),
126 "'this' captured by a lambda and stored in a class member variable; "
127 "disable implicit class copying/moving to prevent potential "
129 }
else if (
const auto *Bind = Result.Nodes.getNodeAs<CallExpr>(
"bind")) {
130 const auto *Callee = Result.Nodes.getNodeAs<FunctionDecl>(
"callee");
132 diag(Bind->getBeginLoc(),
133 "'this' captured by a '%0' call and stored in a class member "
134 "variable; disable implicit class copying/moving to prevent potential "
136 << Callee->getQualifiedNameAsString();
139 const auto *Field = Result.Nodes.getNodeAs<FieldDecl>(
"field");
142 diag(Field->getLocation(),
143 "class member of type '%0' that stores captured 'this'",
145 << 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