@@ -5973,6 +5973,37 @@ TEST(StatementMatcher, ForCallable) {
59735973 EXPECT_TRUE (notMatches (CppString2,
59745974 returnStmt (forCallable (functionDecl (hasName (" F" ))))));
59755975
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+
59766007 // These tests are specific to forCallable().
59776008 StringRef ObjCString1 = " @interface I"
59786009 " -(void) foo;"
@@ -6014,6 +6045,105 @@ TEST(StatementMatcher, ForCallable) {
60146045 binaryOperator (forCallable (blockDecl ()))));
60156046}
60166047
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+
60176147TEST (Matcher, ForEachOverriden) {
60186148 const auto ForEachOverriddenInClass = [](const char *ClassName) {
60196149 return cxxMethodDecl (ofClass (hasName (ClassName)), isVirtual (),
0 commit comments