Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -2807,6 +2807,50 @@ *Node.getParamDecl(N), Finder, Builder)); } +/// \brief Matches all arguments and their respective ParmVarDecl. +/// +/// Given +/// \code +/// void f(int i); +/// int y; +/// f(y); +/// \endcode +/// callExpr(declRefExpr(to(varDecl(hasName("y")))), +/// parmVarDecl(hasType(isInteger()))) +/// matches f(y); +/// with declRefExpr(...) +/// matching int y +/// and parmVarDecl(...) +/// matching int i +AST_POLYMORPHIC_MATCHER_P2(forEachArgumentWithParam, + AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr, + CXXConstructExpr), + internal::Matcher, ArgMatcher, + internal::Matcher, ParamMatcher) { + int ParamIndex = 0; + bool Matched = false; + for (const Expr *Arg : Node.arguments()) { + BoundNodesTreeBuilder ArgMatches; + if (ArgMatcher.matches(*Arg->IgnoreParenCasts(), Finder, &ArgMatches)) { + BoundNodesTreeBuilder ParamMatches; + if ((dyn_cast(&Node) && + cxxConstructExpr(hasDeclaration(cxxConstructorDecl( + hasParameter(ParamIndex, ParamMatcher)))) + .matches(Node, Finder, &ParamMatches)) || + (dyn_cast(&Node) && + callExpr( + callee(functionDecl(hasParameter(ParamIndex, ParamMatcher)))) + .matches(Node, Finder, &ParamMatches))) { + Builder->addMatch(ArgMatches); + Builder->addMatch(ParamMatches); + Matched = true; + } + } + ++ParamIndex; + } + return Matched; +} + /// \brief Matches any parameter of a function declaration. /// /// Does not match the 'this' parameter of a method. Index: unittests/ASTMatchers/ASTMatchersTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTest.cpp +++ unittests/ASTMatchers/ASTMatchersTest.cpp @@ -1570,6 +1570,34 @@ EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY)); } +TEST(Matcher, ForEachArgumentWithParam) { + StatementMatcher ArgumentY = + declRefExpr(to(varDecl(hasName("y")))).bind("arg"); + DeclarationMatcher IntParam = + parmVarDecl(hasType(isInteger())).bind("param"); + StatementMatcher CallExpr = + callExpr(forEachArgumentWithParam(ArgumentY, IntParam)); + + // IntParam does not match. + EXPECT_FALSE(matches("void f(int* i) { int* y; f(y); }", CallExpr)); + // ArgumentY does not match. + EXPECT_FALSE(matches("void f(int i) { int x; f(x); }", CallExpr)); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "void f(int i) { int y; f(y); }", CallExpr, + new VerifyIdIsBoundTo("param"))); + EXPECT_TRUE( + matchAndVerifyResultTrue("void f(int i) { int y; f(y); }", CallExpr, + new VerifyIdIsBoundTo("arg"))); + + EXPECT_TRUE(matchAndVerifyResultTrue( + "void f(int i, int j) { int y; f(y, y); }", CallExpr, + new VerifyIdIsBoundTo("param", 2))); + EXPECT_TRUE(matchAndVerifyResultTrue( + "void f(int i, int j) { int y; f(y, y); }", CallExpr, + new VerifyIdIsBoundTo("arg", 2))); +} + TEST(Matcher, ArgumentCount) { StatementMatcher Call1Arg = callExpr(argumentCountIs(1));