forked from OSchip/llvm-project
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 llvm-svn: 258042
This commit is contained in:
parent
9c47e0681c
commit
ce28f9ebd3
|
@ -2871,6 +2871,57 @@ AST_MATCHER_P2(FunctionDecl, hasParameter,
|
|||
*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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in New Issue