@@ -766,5 +766,85 @@ TEST(HeuristicResolver, UsingValueDecl) {
766766                   cxxMethodDecl (hasName (" waldo"  )).bind (" output"  ));
767767}
768768
769+ //  `arg` is a ParamVarDecl*, `Expected` is a string
770+ MATCHER_P (ParamNameMatcher, Expected, " paramNameMatcher"  ) {
771+   EXPECT_TRUE (arg);
772+   if  (IdentifierInfo *Ident = arg->getDeclName ().getAsIdentifierInfo ()) {
773+     return  Ident->getName () == Expected;
774+   }
775+   return  false ;
776+ }
777+ 
778+ //  Helper function for testing HeuristicResolver::getProtoTypeLoc.
779+ //  Takes a matcher that selects a callee expression bound to the ID "input",
780+ //  calls getProtoTypeLoc() on it, and checks that the call found a
781+ //  FunctionProtoTypeLoc encoding the given parameter names.
782+ template  <typename  InputMatcher, typename ... ParameterNames>
783+ void  expectParameterNames (ASTContext &Ctx, const  InputMatcher &IM,
784+                           ParameterNames... ExpectedParameterNames) {
785+   auto  InputMatches = match (IM, Ctx);
786+   ASSERT_EQ (1u , InputMatches.size ());
787+   const  auto  *Input = InputMatches[0 ].template  getNodeAs <Expr>(" input"  );
788+   ASSERT_TRUE (Input);
789+ 
790+   HeuristicResolver H (Ctx);
791+   auto  Loc = H.getFunctionProtoTypeLoc (Input);
792+   ASSERT_TRUE (Loc);
793+   EXPECT_THAT (Loc.getParams (),
794+               ElementsAre (ParamNameMatcher (ExpectedParameterNames)...));
795+ }
796+ 
797+ TEST (HeuristicResolver, ProtoTypeLoc) {
798+   std::string Code = R"cpp( 
799+     void (*f1)(int param1); 
800+     void (__stdcall *f2)(int param2); 
801+     using f3_t = void(*)(int param3); 
802+     f3_t f3; 
803+     using f4_t = void(__stdcall *)(int param4); 
804+     f4_t f4; 
805+     struct S { 
806+       void (*f5)(int param5); 
807+       using f6_t = void(*)(int param6); 
808+       f6_t f6; 
809+     }; 
810+     void bar() { 
811+       f1(42); 
812+       f2(42); 
813+       f3(42); 
814+       f4(42); 
815+       S s; 
816+       s.f5(42); 
817+       s.f6(42); 
818+     } 
819+   )cpp"  ;
820+   auto  TU = tooling::buildASTFromCodeWithArgs (Code, {" -std=c++20"  });
821+   auto  &Ctx = TU->getASTContext ();
822+   auto  checkFreeFunction = [&](llvm::StringRef FunctionName,
823+                                llvm::StringRef ParamName) {
824+     expectParameterNames (
825+         Ctx,
826+         callExpr (
827+             callee (implicitCastExpr (hasSourceExpression (declRefExpr (
828+                                         to (namedDecl (hasName (FunctionName))))))
829+                        .bind (" input"  ))),
830+         ParamName);
831+   };
832+   checkFreeFunction (" f1"  , " param1"  );
833+   checkFreeFunction (" f2"  , " param2"  );
834+   checkFreeFunction (" f3"  , " param3"  );
835+   checkFreeFunction (" f4"  , " param4"  );
836+   auto  checkMemberFunction = [&](llvm::StringRef MemberName,
837+                                  llvm::StringRef ParamName) {
838+     expectParameterNames (
839+         Ctx,
840+         callExpr (callee (implicitCastExpr (hasSourceExpression (memberExpr (
841+                                              member (hasName (MemberName)))))
842+                             .bind (" input"  ))),
843+         ParamName);
844+   };
845+   checkMemberFunction (" f5"  , " param5"  );
846+   checkMemberFunction (" f6"  , " param6"  );
847+ }
848+ 
769849} //  namespace
770850} //  namespace clang
0 commit comments