diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4886,7 +4886,7 @@ // This test is cheaper compared to the big matcher in the next if. // Therefore, please keep this order. - if (FProto) { + if (FProto && FProto->getNumParams() > ParamIndex) { QualType ParamType = FProto->getParamType(ParamIndex); if (ParamMatcher.matches(ParamType, Finder, &ParamMatches)) { Result.addMatch(ParamMatches); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -1094,6 +1094,31 @@ S, CallExpr, std::make_unique>("arg"))); } +TEST(ForEachArgumentWithParamType, MatchesVariadicFunctionPtrCalls) { + StatementMatcher ArgumentY = + declRefExpr(to(varDecl(hasName("y")))).bind("arg"); + TypeMatcher IntType = qualType(builtinType()).bind("type"); + StatementMatcher CallExpr = + callExpr(forEachArgumentWithParamType(ArgumentY, IntType)); + + StringRef S = R"cpp( + void fcntl(int fd, int cmd, ...) {} + + template + void f(Func F) { + int y = 42; + F(y, 1, 3); + } + + void g() { f(fcntl); } + )cpp"; + + EXPECT_TRUE(matchAndVerifyResultTrue( + S, CallExpr, std::make_unique>("type"))); + EXPECT_TRUE(matchAndVerifyResultTrue( + S, CallExpr, std::make_unique>("arg"))); +} + TEST(QualType, hasCanonicalType) { EXPECT_TRUE(notMatches("typedef int &int_ref;" "int a;"