Add support for polymorphic matchers. Use runtime type checking to determine the right polymorphic overload to use.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184558 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index 839c447..8df0274 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -2250,10 +2250,9 @@
}
AST_POLYMORPHIC_MATCHER_P(
- polymorphicHas, internal::Matcher<Decl>, AMatcher) {
- TOOLING_COMPILE_ASSERT((llvm::is_same<NodeType, Decl>::value) ||
- (llvm::is_same<NodeType, Stmt>::value),
- assert_node_type_is_accessible);
+ polymorphicHas,
+ AST_POLYMORPHIC_SUPPORTED_TYPES_2(Decl, Stmt),
+ internal::Matcher<Decl>, AMatcher) {
return Finder->matchesChildOf(
Node, AMatcher, Builder,
ASTMatchFinder::TK_IgnoreImplicitCastsAndParentheses,
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index d7973c9..e6b04e0 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -52,6 +52,7 @@
virtual ast_type_traits::ASTNodeKind getSupportedKind() const {
return ast_type_traits::ASTNodeKind();
}
+
private:
uint64_t ID;
std::string BoundID;
@@ -75,15 +76,16 @@
Errors.push_back(Error.ToStringFull());
}
- DynTypedMatcher *actOnMatcherExpression(StringRef MatcherName,
- const SourceRange &NameRange,
- StringRef BindID,
- ArrayRef<ParserValue> Args,
- Diagnostics *Error) {
+ MatcherList actOnMatcherExpression(StringRef MatcherName,
+ const SourceRange &NameRange,
+ StringRef BindID,
+ ArrayRef<ParserValue> Args,
+ Diagnostics *Error) {
MatcherInfo ToStore = { MatcherName, NameRange, Args, BindID };
Matchers.push_back(ToStore);
DummyDynTypedMatcher Matcher(ExpectedMatchers[MatcherName]);
- return Matcher.tryBind(BindID);
+ OwningPtr<DynTypedMatcher> Out(Matcher.tryBind(BindID));
+ return *Out;
}
struct MatcherInfo {
@@ -146,9 +148,9 @@
}
EXPECT_EQ(1ULL, Sema.Values.size());
- EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatcher().getID());
- EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher &>(
- Sema.Values[0].getMatcher()).boundID());
+ EXPECT_EQ(ExpectedFoo, Sema.Values[0].getMatchers().matchers()[0]->getID());
+ EXPECT_EQ("Yo!", static_cast<const DummyDynTypedMatcher *>(
+ Sema.Values[0].getMatchers().matchers()[0])->boundID());
EXPECT_EQ(3ULL, Sema.Matchers.size());
const MockSema::MatcherInfo Bar = Sema.Matchers[0];
@@ -167,8 +169,10 @@
EXPECT_EQ("Foo", Foo.MatcherName);
EXPECT_TRUE(matchesRange(Foo.NameRange, 1, 2, 2, 12));
EXPECT_EQ(2ULL, Foo.Args.size());
- EXPECT_EQ(ExpectedBar, Foo.Args[0].Value.getMatcher().getID());
- EXPECT_EQ(ExpectedBaz, Foo.Args[1].Value.getMatcher().getID());
+ EXPECT_EQ(ExpectedBar,
+ Foo.Args[0].Value.getMatchers().matchers()[0]->getID());
+ EXPECT_EQ(ExpectedBaz,
+ Foo.Args[1].Value.getMatchers().matchers()[0]->getID());
EXPECT_EQ("Yo!", Foo.BoundID);
}
@@ -176,11 +180,14 @@
TEST(ParserTest, FullParserTest) {
OwningPtr<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
- "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))",
+ "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()),"
+ " hasOperatorName(\"+\"))))",
NULL));
Matcher<Decl> M = Matcher<Decl>::constructFrom(*VarDecl);
EXPECT_TRUE(matches("int x = 1 + false;", M));
EXPECT_FALSE(matches("int x = true + 1;", M));
+ EXPECT_FALSE(matches("int x = 1 - false;", M));
+ EXPECT_FALSE(matches("int x = true - 1;", M));
OwningPtr<DynTypedMatcher> HasParameter(Parser::parseMatcherExpression(
"functionDecl(hasParameter(1, hasName(\"x\")))", NULL));
@@ -242,6 +249,9 @@
EXPECT_EQ("1:1: Error building matcher isArrow.\n"
"1:1: Matcher does not support binding.",
ParseWithError("isArrow().bind(\"foo\")"));
+ EXPECT_EQ("Input value has unresolved overloaded type: "
+ "Matcher<DoStmt|ForStmt|WhileStmt>",
+ ParseMatcherWithError("hasBody(stmt())"));
}
} // end anonymous namespace
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index fd6eaef..357a371 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -38,25 +38,23 @@
template <class T>
Matcher<T> constructMatcher(StringRef MatcherName, Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(
- Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error));
- return Matcher<T>::constructFrom(*Out);
+ return Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error)
+ .getTypedMatcher<T>();
}
template <class T>
Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
- MatcherName, SourceRange(), Args(Arg1), Error));
- return Matcher<T>::constructFrom(*Out);
+ return Registry::constructMatcher(MatcherName, SourceRange(), Args(Arg1),
+ Error).getTypedMatcher<T>();
}
template <class T>
Matcher<T> constructMatcher(StringRef MatcherName, const VariantValue &Arg1,
const VariantValue &Arg2, Diagnostics *Error) {
- OwningPtr<DynTypedMatcher> Out(Registry::constructMatcher(
- MatcherName, SourceRange(), Args(Arg1, Arg2), Error));
- return Matcher<T>::constructFrom(*Out);
+ return Registry::constructMatcher(MatcherName, SourceRange(),
+ Args(Arg1, Arg2), Error)
+ .getTypedMatcher<T>();
}
};
@@ -115,34 +113,57 @@
EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
}
+TEST_F(RegistryTest, PolymorphicMatchers) {
+ const MatcherList IsDefinition =
+ Registry::constructMatcher("isDefinition", SourceRange(), Args(), NULL);
+ Matcher<Decl> Var = constructMatcher<Decl>("varDecl", IsDefinition, NULL);
+ Matcher<Decl> Class =
+ constructMatcher<Decl>("recordDecl", IsDefinition, NULL);
+ Matcher<Decl> Func =
+ constructMatcher<Decl>("functionDecl", IsDefinition, NULL);
+ EXPECT_TRUE(matches("int a;", Var));
+ EXPECT_FALSE(matches("extern int a;", Var));
+ EXPECT_TRUE(matches("class A {};", Class));
+ EXPECT_FALSE(matches("class A;", Class));
+ EXPECT_TRUE(matches("void f(){};", Func));
+ EXPECT_FALSE(matches("void f();", Func));
+
+ Matcher<Decl> Anything = constructMatcher<Decl>("anything", NULL);
+ Matcher<Decl> RecordDecl =
+ constructMatcher<Decl>("recordDecl", Anything, NULL);
+
+ EXPECT_TRUE(matches("int a;", Anything));
+ EXPECT_TRUE(matches("class A {};", Anything));
+ EXPECT_TRUE(matches("void f(){};", Anything));
+ EXPECT_FALSE(matches("int a;", RecordDecl));
+ EXPECT_TRUE(matches("class A {};", RecordDecl));
+ EXPECT_FALSE(matches("void f(){};", RecordDecl));
+}
+
TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
OwningPtr<Diagnostics> Error(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher("hasInitializer", SourceRange(),
- Args(), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher("hasInitializer", SourceRange(),
+ Args(), Error.get()).empty());
EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher("isArrow", SourceRange(),
- Args(std::string()), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher(
+ "isArrow", SourceRange(), Args(std::string()), Error.get()).empty());
EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
Error->ToString());
// Bad argument type
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher("ofClass", SourceRange(),
- Args(std::string()), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher(
+ "ofClass", SourceRange(), Args(std::string()), Error.get()).empty());
EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = String)",
Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL ==
- Registry::constructMatcher(
- "recordDecl", SourceRange(),
- Args(recordDecl(), parameterCountIs(3)), Error.get()));
+ EXPECT_TRUE(Registry::constructMatcher(
+ "recordDecl", SourceRange(), Args(recordDecl(), parameterCountIs(3)),
+ Error.get()).empty());
EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
"(Actual = Matcher<FunctionDecl>)",
Error->ToString());
diff --git a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
index c941672..625f70b 100644
--- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -27,9 +27,9 @@
EXPECT_EQ(kUnsigned, Value.getUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.isMatchers());
+ EXPECT_FALSE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<UnaryOperator>());
}
TEST(VariantValueTest, String) {
@@ -41,9 +41,7 @@
EXPECT_EQ("String", Value.getTypeAsString());
EXPECT_FALSE(Value.isUnsigned());
- EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.isMatchers());
}
TEST(VariantValueTest, DynTypedMatcher) {
@@ -52,25 +50,25 @@
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_FALSE(Value.hasTypedMatcher<Decl>());
+ EXPECT_TRUE(Value.hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
// Can only convert to compatible matchers.
Value = recordDecl();
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_TRUE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
Value = ignoringImpCasts(expr());
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::Stmt>());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::Expr>());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::IntegerLiteral>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::GotoStmt>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_FALSE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<Stmt>());
+ EXPECT_TRUE(Value.hasTypedMatcher<Expr>());
+ EXPECT_TRUE(Value.hasTypedMatcher<IntegerLiteral>());
+ EXPECT_FALSE(Value.hasTypedMatcher<GotoStmt>());
EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
}
@@ -79,31 +77,31 @@
EXPECT_TRUE(Value.isString());
EXPECT_EQ("A", Value.getString());
EXPECT_FALSE(Value.isUnsigned());
- EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isMatchers());
EXPECT_EQ("String", Value.getTypeAsString());
Value = recordDecl();
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.isMatchers());
+ EXPECT_TRUE(Value.hasTypedMatcher<Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<UnaryOperator>());
EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
EXPECT_EQ(17U, Value.getUnsigned());
- EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isMatchers());
EXPECT_FALSE(Value.isString());
Value = VariantValue();
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
- EXPECT_FALSE(Value.isMatcher());
+ EXPECT_FALSE(Value.isMatchers());
EXPECT_EQ("Nothing", Value.getTypeAsString());
}
-TEST(GenericValueTest, Matcher) {
+TEST(VariantValueTest, Matcher) {
EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X")))
.getTypedMatcher<Decl>()));
EXPECT_TRUE(
@@ -117,13 +115,15 @@
// do this test when building with MSVC because its debug C runtime prints the
// assertion failure message as a wide string, which gtest doesn't understand.
EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher<Stmt>(),
- "canConstructFrom");
+ "hasTypedMatcher");
#endif
EXPECT_FALSE(
matches("int x;", VariantValue(functionDecl()).getTypedMatcher<Decl>()));
- EXPECT_FALSE(matches("int foo() { return 1 + 1; }",
- VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
+ EXPECT_FALSE(
+ matches("int foo() { return 1 + 1; }",
+
+ VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
}
} // end anonymous namespace