@@ -64,16 +64,21 @@ AST_MATCHER(CXXRecordDecl, correctHandleCaptureThisLambda) {
6464
6565constexpr const char *DefaultFunctionWrapperTypes =
6666 " ::std::function;::std::move_only_function;::boost::function" ;
67+ constexpr const char *DefaultBindFunctions = " ::std::bind;::boost::bind" ;
6768
6869CapturingThisInMemberVariableCheck::CapturingThisInMemberVariableCheck (
6970 StringRef Name, ClangTidyContext *Context)
7071 : ClangTidyCheck(Name, Context),
7172 FunctionWrapperTypes (utils::options::parseStringList(
72- Options.get(" FunctionWrapperTypes" , DefaultFunctionWrapperTypes))) {}
73+ Options.get(" FunctionWrapperTypes" , DefaultFunctionWrapperTypes))),
74+ BindFunctions(utils::options::parseStringList(
75+ Options.get(" BindFunctions" , DefaultBindFunctions))) {}
7376void CapturingThisInMemberVariableCheck::storeOptions (
7477 ClangTidyOptions::OptionMap &Opts) {
7578 Options.store (Opts, " FunctionWrapperTypes" ,
7679 utils::options::serializeStringList (FunctionWrapperTypes));
80+ Options.store (Opts, " BindFunctions" ,
81+ utils::options::serializeStringList (BindFunctions));
7782}
7883
7984void CapturingThisInMemberVariableCheck::registerMatchers (MatchFinder *Finder) {
@@ -87,33 +92,54 @@ void CapturingThisInMemberVariableCheck::registerMatchers(MatchFinder *Finder) {
8792 // [self = this]
8893 capturesVar (varDecl (hasInitializer (cxxThisExpr ())))));
8994 auto IsLambdaCapturingThis =
90- lambdaExpr (hasAnyCapture (CaptureThis.bind (" capture" ))).bind (" lambda" );
91- auto IsInitWithLambda =
92- anyOf (IsLambdaCapturingThis,
93- cxxConstructExpr (hasArgument (0 , IsLambdaCapturingThis)));
95+ lambdaExpr (hasAnyCapture (CaptureThis)).bind (" lambda" );
96+
97+ auto IsBindCapturingThis =
98+ callExpr (
99+ callee (functionDecl (matchers::matchesAnyListedName (BindFunctions))
100+ .bind (" callee" )),
101+ hasAnyArgument (cxxThisExpr ()))
102+ .bind (" bind" );
103+
104+ auto IsInitWithLambdaOrBind =
105+ anyOf (IsLambdaCapturingThis, IsBindCapturingThis,
106+ cxxConstructExpr (hasArgument (
107+ 0 , anyOf (IsLambdaCapturingThis, IsBindCapturingThis))));
108+
94109 Finder->addMatcher (
95110 cxxRecordDecl (
96111 anyOf (has (cxxConstructorDecl (
97112 unless (isCopyConstructor ()), unless (isMoveConstructor ()),
98113 hasAnyConstructorInitializer (cxxCtorInitializer (
99114 isMemberInitializer (), forField (IsStdFunctionField),
100- withInitializer (IsInitWithLambda ))))),
115+ withInitializer (IsInitWithLambdaOrBind ))))),
101116 has (fieldDecl (IsStdFunctionField,
102- hasInClassInitializer (IsInitWithLambda )))),
117+ hasInClassInitializer (IsInitWithLambdaOrBind )))),
103118 unless (correctHandleCaptureThisLambda ())),
104119 this );
105120}
106-
107121void CapturingThisInMemberVariableCheck::check (
108122 const MatchFinder::MatchResult &Result) {
109- const auto *Capture = Result.Nodes .getNodeAs <LambdaCapture>(" capture" );
110- const auto *Lambda = Result.Nodes .getNodeAs <LambdaExpr>(" lambda" );
123+ const auto EmitDiag = [this ](const SourceLocation &Location,
124+ const FunctionDecl *Bind) {
125+ const std::string BindName = Bind ? Bind->getQualifiedNameAsString () : " " ;
126+ diag (Location, " 'this' captured by a %select{lambda|'%1' call}0 and "
127+ " stored in a class member variable; disable implicit class "
128+ " copying/moving to prevent potential use-after-free" )
129+ << (Bind ? 1 : 0 ) << BindName;
130+ };
131+
132+ if (const auto *Lambda = Result.Nodes .getNodeAs <LambdaExpr>(" lambda" )) {
133+ EmitDiag (Lambda->getBeginLoc (), nullptr );
134+ } else if (const auto *Bind = Result.Nodes .getNodeAs <CallExpr>(" bind" )) {
135+ const auto *Callee = Result.Nodes .getNodeAs <FunctionDecl>(" callee" );
136+ assert (Callee);
137+ EmitDiag (Bind->getBeginLoc (), Callee);
138+ }
139+
111140 const auto *Field = Result.Nodes .getNodeAs <FieldDecl>(" field" );
112- diag (Lambda->getBeginLoc (),
113- " 'this' captured by a lambda and stored in a class member variable; "
114- " disable implicit class copying/moving to prevent potential "
115- " use-after-free" )
116- << Capture->getLocation ();
141+ assert (Field);
142+
117143 diag (Field->getLocation (),
118144 " class member of type '%0' that stores captured 'this'" ,
119145 DiagnosticIDs::Note)
0 commit comments