r258042 - Add forEachArgumentWithParam AST matcher.
Manuel Klimek via cfe-commits
cfe-commits at lists.llvm.org
Mon Jan 18 03:20:09 PST 2016
Author: klimek
Date: Mon Jan 18 05:20:09 2016
New Revision: 258042
URL: http://llvm.org/viewvc/llvm-project?rev=258042&view=rev
Log:
Add forEachArgumentWithParam AST matcher.
The new matcher allows users to provide a matcher for both the argument
of a CallExpr/CxxConstructExpr a well as the ParmVarDecl of the
argument.
Patch by Felix Berger.
Differential Revision: http://reviews.llvm.org/D13845
Modified:
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=258042&r1=258041&r2=258042&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Mon Jan 18 05:20:09 2016
@@ -2871,6 +2871,57 @@ AST_MATCHER_P2(FunctionDecl, hasParamete
*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<Expr>, ArgMatcher,
+ internal::Matcher<ParmVarDecl>, ParamMatcher) {
+ BoundNodesTreeBuilder Result;
+ // The first argument of an overloaded member operator is the implicit object
+ // argument of the method which should not be matched against a parameter, so
+ // we skip over it here.
+ BoundNodesTreeBuilder Matches;
+ unsigned ArgIndex = cxxOperatorCallExpr(callee(cxxMethodDecl()))
+ .matches(Node, Finder, &Matches)
+ ? 1
+ : 0;
+ int ParamIndex = 0;
+ bool Matched = false;
+ for (; ArgIndex < Node.getNumArgs(); ++ArgIndex) {
+ BoundNodesTreeBuilder ArgMatches(*Builder);
+ if (ArgMatcher.matches(*(Node.getArg(ArgIndex)->IgnoreParenCasts()),
+ Finder, &ArgMatches)) {
+ BoundNodesTreeBuilder ParamMatches(ArgMatches);
+ if (expr(anyOf(cxxConstructExpr(hasDeclaration(cxxConstructorDecl(
+ hasParameter(ParamIndex, ParamMatcher)))),
+ callExpr(callee(functionDecl(
+ hasParameter(ParamIndex, ParamMatcher))))))
+ .matches(Node, Finder, &ParamMatches)) {
+ Result.addMatch(ParamMatches);
+ Matched = true;
+ }
+ }
+ ++ParamIndex;
+ }
+ *Builder = std::move(Result);
+ return Matched;
+}
+
/// \brief Matches any parameter of a function declaration.
///
/// Does not match the 'this' parameter of a method.
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=258042&r1=258041&r2=258042&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Mon Jan 18 05:20:09 2016
@@ -174,6 +174,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(fieldDecl);
REGISTER_MATCHER(floatLiteral);
REGISTER_MATCHER(forEach);
+ REGISTER_MATCHER(forEachArgumentWithParam);
REGISTER_MATCHER(forEachConstructorInitializer);
REGISTER_MATCHER(forEachDescendant);
REGISTER_MATCHER(forEachSwitchCase);
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=258042&r1=258041&r2=258042&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Mon Jan 18 05:20:09 2016
@@ -1608,6 +1608,91 @@ TEST(Matcher, AnyArgument) {
EXPECT_TRUE(notMatches("void x(int, int) { x(1, 2); }", CallArgumentY));
}
+TEST(ForEachArgumentWithParam, ReportsNoFalsePositives) {
+ 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));
+}
+
+TEST(ForEachArgumentWithParam, MatchesCXXMemberCallExpr) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher CallExpr =
+ callExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "struct S {"
+ " const S& operator[](int i) { return *this; }"
+ "};"
+ "void f(S S1) {"
+ " int y = 1;"
+ " S1[y];"
+ "}",
+ CallExpr, new VerifyIdIsBoundTo<ParmVarDecl>("param", 1)));
+}
+
+TEST(ForEachArgumentWithParam, MatchesCallExpr) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher CallExpr =
+ callExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+
+ EXPECT_TRUE(
+ matchAndVerifyResultTrue("void f(int i) { int y; f(y); }", CallExpr,
+ new VerifyIdIsBoundTo<ParmVarDecl>("param")));
+ EXPECT_TRUE(
+ matchAndVerifyResultTrue("void f(int i) { int y; f(y); }", CallExpr,
+ new VerifyIdIsBoundTo<DeclRefExpr>("arg")));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f(int i, int j) { int y; f(y, y); }", CallExpr,
+ new VerifyIdIsBoundTo<ParmVarDecl>("param", 2)));
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void f(int i, int j) { int y; f(y, y); }", CallExpr,
+ new VerifyIdIsBoundTo<DeclRefExpr>("arg", 2)));
+}
+
+TEST(ForEachArgumentWithParam, MatchesConstructExpr) {
+ StatementMatcher ArgumentY =
+ declRefExpr(to(varDecl(hasName("y")))).bind("arg");
+ DeclarationMatcher IntParam = parmVarDecl(hasType(isInteger())).bind("param");
+ StatementMatcher ConstructExpr =
+ cxxConstructExpr(forEachArgumentWithParam(ArgumentY, IntParam));
+
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "struct C {"
+ " C(int i) {}"
+ "};"
+ "int y = 0;"
+ "C Obj(y);",
+ ConstructExpr, new VerifyIdIsBoundTo<ParmVarDecl>("param")));
+}
+
+TEST(ForEachArgumentWithParam, HandlesBoundNodesForNonMatches) {
+ EXPECT_TRUE(matchAndVerifyResultTrue(
+ "void g(int i, int j) {"
+ " int a;"
+ " int b;"
+ " int c;"
+ " g(a, 0);"
+ " g(a, b);"
+ " g(0, b);"
+ "}",
+ functionDecl(
+ forEachDescendant(varDecl().bind("v")),
+ forEachDescendant(callExpr(forEachArgumentWithParam(
+ declRefExpr(to(decl(equalsBoundNode("v")))), parmVarDecl())))),
+ new VerifyIdIsBoundTo<VarDecl>("v", 4)));
+}
+
TEST(Matcher, ArgumentCount) {
StatementMatcher Call1Arg = callExpr(argumentCountIs(1));
More information about the cfe-commits
mailing list