@@ -64,16 +64,23 @@ AST_MATCHER(CXXRecordDecl, correctHandleCaptureThisLambda) {
64
64
65
65
constexpr const char *DefaultFunctionWrapperTypes =
66
66
" ::std::function;::std::move_only_function;::boost::function" ;
67
+ constexpr const char *DefaultBindFunctions =
68
+ " ::std::bind;::boost::bind;::std::bind_front;::std::bind_back;"
69
+ " ::boost::compat::bind_front;::boost::compat::bind_back" ;
67
70
68
71
CapturingThisInMemberVariableCheck::CapturingThisInMemberVariableCheck (
69
72
StringRef Name, ClangTidyContext *Context)
70
73
: ClangTidyCheck(Name, Context),
71
74
FunctionWrapperTypes (utils::options::parseStringList(
72
- Options.get(" FunctionWrapperTypes" , DefaultFunctionWrapperTypes))) {}
75
+ Options.get(" FunctionWrapperTypes" , DefaultFunctionWrapperTypes))),
76
+ BindFunctions(utils::options::parseStringList(
77
+ Options.get(" BindFunctions" , DefaultBindFunctions))) {}
73
78
void CapturingThisInMemberVariableCheck::storeOptions (
74
79
ClangTidyOptions::OptionMap &Opts) {
75
80
Options.store (Opts, " FunctionWrapperTypes" ,
76
81
utils::options::serializeStringList (FunctionWrapperTypes));
82
+ Options.store (Opts, " BindFunctions" ,
83
+ utils::options::serializeStringList (BindFunctions));
77
84
}
78
85
79
86
void CapturingThisInMemberVariableCheck::registerMatchers (MatchFinder *Finder) {
@@ -87,33 +94,52 @@ void CapturingThisInMemberVariableCheck::registerMatchers(MatchFinder *Finder) {
87
94
// [self = this]
88
95
capturesVar (varDecl (hasInitializer (cxxThisExpr ())))));
89
96
auto IsLambdaCapturingThis =
90
- lambdaExpr (hasAnyCapture (CaptureThis.bind (" capture" ))).bind (" lambda" );
91
- auto IsInitWithLambda =
92
- anyOf (IsLambdaCapturingThis,
93
- cxxConstructExpr (hasArgument (0 , IsLambdaCapturingThis)));
97
+ lambdaExpr (hasAnyCapture (CaptureThis)).bind (" lambda" );
98
+
99
+ auto IsBindCapturingThis =
100
+ callExpr (
101
+ callee (functionDecl (matchers::matchesAnyListedName (BindFunctions))
102
+ .bind (" callee" )),
103
+ hasAnyArgument (cxxThisExpr ()))
104
+ .bind (" bind" );
105
+
106
+ auto IsInitWithLambdaOrBind =
107
+ anyOf (IsLambdaCapturingThis, IsBindCapturingThis,
108
+ cxxConstructExpr (hasArgument (
109
+ 0 , anyOf (IsLambdaCapturingThis, IsBindCapturingThis))));
110
+
94
111
Finder->addMatcher (
95
112
cxxRecordDecl (
96
113
anyOf (has (cxxConstructorDecl (
97
114
unless (isCopyConstructor ()), unless (isMoveConstructor ()),
98
115
hasAnyConstructorInitializer (cxxCtorInitializer (
99
116
isMemberInitializer (), forField (IsStdFunctionField),
100
- withInitializer (IsInitWithLambda ))))),
117
+ withInitializer (IsInitWithLambdaOrBind ))))),
101
118
has (fieldDecl (IsStdFunctionField,
102
- hasInClassInitializer (IsInitWithLambda )))),
119
+ hasInClassInitializer (IsInitWithLambdaOrBind )))),
103
120
unless (correctHandleCaptureThisLambda ())),
104
121
this );
105
122
}
106
-
107
123
void CapturingThisInMemberVariableCheck::check (
108
124
const MatchFinder::MatchResult &Result) {
109
- const auto *Capture = Result.Nodes .getNodeAs <LambdaCapture>(" capture" );
110
- const auto *Lambda = Result.Nodes .getNodeAs <LambdaExpr>(" lambda" );
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 "
129
+ " use-after-free" );
130
+ } else if (const auto *Bind = Result.Nodes .getNodeAs <CallExpr>(" bind" )) {
131
+ const auto *Callee = Result.Nodes .getNodeAs <FunctionDecl>(" callee" );
132
+ assert (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 "
136
+ " use-after-free" )
137
+ << Callee->getQualifiedNameAsString ();
138
+ }
139
+
111
140
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
+
117
143
diag (Field->getLocation (),
118
144
" class member of type '%0' that stores captured 'this'" ,
119
145
DiagnosticIDs::Note)
0 commit comments