@@ -5973,6 +5973,37 @@ TEST(StatementMatcher, ForCallable) {
5973
5973
EXPECT_TRUE (notMatches (CppString2,
5974
5974
returnStmt (forCallable (functionDecl (hasName (" F" ))))));
5975
5975
5976
+ StringRef CodeWithDeepCallExpr = R"cpp(
5977
+ void Other();
5978
+ void Function() {
5979
+ {
5980
+ (
5981
+ Other()
5982
+ );
5983
+ }
5984
+ }
5985
+ )cpp" ;
5986
+ auto ForCallableFirst =
5987
+ callExpr (forCallable (functionDecl (hasName (" Function" ))),
5988
+ callee (functionDecl (hasName (" Other" )).bind (" callee" )))
5989
+ .bind (" call" );
5990
+ auto ForCallableSecond =
5991
+ callExpr (callee (functionDecl (hasName (" Other" )).bind (" callee" )),
5992
+ forCallable (functionDecl (hasName (" Function" ))))
5993
+ .bind (" call" );
5994
+ EXPECT_TRUE (matchAndVerifyResultTrue (
5995
+ CodeWithDeepCallExpr, ForCallableFirst,
5996
+ std::make_unique<VerifyIdIsBoundTo<CallExpr>>(" call" )));
5997
+ EXPECT_TRUE (matchAndVerifyResultTrue (
5998
+ CodeWithDeepCallExpr, ForCallableFirst,
5999
+ std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>(" callee" )));
6000
+ EXPECT_TRUE (matchAndVerifyResultTrue (
6001
+ CodeWithDeepCallExpr, ForCallableSecond,
6002
+ std::make_unique<VerifyIdIsBoundTo<CallExpr>>(" call" )));
6003
+ EXPECT_TRUE (matchAndVerifyResultTrue (
6004
+ CodeWithDeepCallExpr, ForCallableSecond,
6005
+ std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>(" callee" )));
6006
+
5976
6007
// These tests are specific to forCallable().
5977
6008
StringRef ObjCString1 = " @interface I"
5978
6009
" -(void) foo;"
@@ -6014,6 +6045,105 @@ TEST(StatementMatcher, ForCallable) {
6014
6045
binaryOperator (forCallable (blockDecl ()))));
6015
6046
}
6016
6047
6048
+ namespace {
6049
+ class ForCallablePreservesBindingWithMultipleParentsTestCallback
6050
+ : public BoundNodesCallback {
6051
+ public:
6052
+ bool run (const BoundNodes *BoundNodes) override {
6053
+ FunctionDecl const *FunDecl =
6054
+ BoundNodes->getNodeAs <FunctionDecl>(" funDecl" );
6055
+ // Validate test assumptions. This would be expressed as ASSERT_* in
6056
+ // a TEST().
6057
+ if (!FunDecl) {
6058
+ EXPECT_TRUE (false && " Incorrect test setup" );
6059
+ return false ;
6060
+ }
6061
+ auto const *FunDef = FunDecl->getDefinition ();
6062
+ if (!FunDef || !FunDef->getBody () ||
6063
+ FunDef->getNameAsString () != " Function" ) {
6064
+ EXPECT_TRUE (false && " Incorrect test setup" );
6065
+ return false ;
6066
+ }
6067
+
6068
+ ExpectCorrectResult (
6069
+ " Baseline" ,
6070
+ callExpr (callee (cxxMethodDecl ().bind (" callee" ))).bind (" call" ), //
6071
+ FunDecl);
6072
+
6073
+ ExpectCorrectResult (" ForCallable first" ,
6074
+ callExpr (forCallable (equalsNode (FunDecl)),
6075
+ callee (cxxMethodDecl ().bind (" callee" )))
6076
+ .bind (" call" ),
6077
+ FunDecl);
6078
+
6079
+ ExpectCorrectResult (" ForCallable second" ,
6080
+ callExpr (callee (cxxMethodDecl ().bind (" callee" )),
6081
+ forCallable (equalsNode (FunDecl)))
6082
+ .bind (" call" ),
6083
+ FunDecl);
6084
+
6085
+ // This value does not really matter: the EXPECT_* will set the exit code.
6086
+ return true ;
6087
+ }
6088
+
6089
+ bool run (const BoundNodes *BoundNodes, ASTContext *Context) override {
6090
+ return run (BoundNodes);
6091
+ }
6092
+
6093
+ private:
6094
+ void ExpectCorrectResult (StringRef LogInfo,
6095
+ ArrayRef<BoundNodes> Results) const {
6096
+ EXPECT_EQ (Results.size (), 1u ) << LogInfo;
6097
+ if (Results.empty ())
6098
+ return ;
6099
+ auto const &R = Results.front ();
6100
+ EXPECT_TRUE (R.getNodeAs <CallExpr>(" call" )) << LogInfo;
6101
+ EXPECT_TRUE (R.getNodeAs <CXXMethodDecl>(" callee" )) << LogInfo;
6102
+ }
6103
+
6104
+ template <typename MatcherT>
6105
+ void ExpectCorrectResult (StringRef LogInfo, MatcherT Matcher,
6106
+ FunctionDecl const *FunDef) const {
6107
+ auto &Context = FunDef->getASTContext ();
6108
+ auto const &Results = match (findAll (Matcher), *FunDef->getBody (), Context);
6109
+ ExpectCorrectResult (LogInfo, Results);
6110
+ }
6111
+ };
6112
+ } // namespace
6113
+
6114
+ TEST (StatementMatcher, ForCallablePreservesBindingWithMultipleParents) {
6115
+ // Tests in this file are fairly simple and therefore can rely on matches,
6116
+ // matchAndVerifyResultTrue, etc. This test, however, needs a FunctionDecl* in
6117
+ // order to call equalsNode in order to reproduce the observed issue (bindings
6118
+ // being removed despite forCallable matching the node).
6119
+ //
6120
+ // Because of this and because the machinery to compile the code into an
6121
+ // ASTUnit is not exposed outside matchAndVerifyResultConditionally, it is
6122
+ // cheaper to have a custom BoundNodesCallback for the purpose of this test.
6123
+ StringRef codeWithTemplateFunction = R"cpp(
6124
+ struct Klass {
6125
+ void Method();
6126
+ template <typename T>
6127
+ void Function(T t); // Declaration
6128
+ };
6129
+
6130
+ void Instantiate(Klass k) {
6131
+ k.Function(0);
6132
+ }
6133
+
6134
+ template <typename T>
6135
+ void Klass::Function(T t) { // Definition
6136
+ // Compound statement has two parents: the declaration and the definition.
6137
+ Method();
6138
+ }
6139
+ )cpp" ;
6140
+ EXPECT_TRUE (matchAndVerifyResultTrue (
6141
+ codeWithTemplateFunction,
6142
+ callExpr (callee (functionDecl (hasName (" Function" )).bind (" funDecl" ))),
6143
+ std::make_unique<
6144
+ ForCallablePreservesBindingWithMultipleParentsTestCallback>()));
6145
+ }
6146
+
6017
6147
TEST (Matcher, ForEachOverriden) {
6018
6148
const auto ForEachOverriddenInClass = [](const char *ClassName) {
6019
6149
return cxxMethodDecl (ofClass (hasName (ClassName)), isVirtual (),
0 commit comments