aboutsummaryrefslogtreecommitdiff
path: root/unittests/ASTMatchers
diff options
context:
space:
mode:
authorSamuel Benzaquen <sbenza@google.com>2013-06-20 14:28:32 +0000
committerSamuel Benzaquen <sbenza@google.com>2013-06-20 14:28:32 +0000
commit76c2f92c4b4ab7e02857661a05e53ba4b501d87a (patch)
treead748a8f9c5291b4cf6d7dbee5c3ac4c975ef4ce /unittests/ASTMatchers
parentcf52ca6bb6dd76a1bd967bc422287fafafa1e45a (diff)
downloadclang-76c2f92c4b4ab7e02857661a05e53ba4b501d87a.tar.gz
Enhancements for the DynTypedMatcher system.
- Added conversion routines and checks in Matcher<T> that take a DynTypedMatcher. - Added type information on the error messages for the marshallers. - Allows future work on Polymorphic/overloaded matchers. We should be able to disambiguate at runtime and choose the appropriate overload. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@184429 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/ASTMatchers')
-rw-r--r--unittests/ASTMatchers/ASTMatchersTest.h35
-rw-r--r--unittests/ASTMatchers/Dynamic/ParserTest.cpp26
-rw-r--r--unittests/ASTMatchers/Dynamic/RegistryTest.cpp157
-rw-r--r--unittests/ASTMatchers/Dynamic/VariantValueTest.cpp71
4 files changed, 152 insertions, 137 deletions
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index 05258f7fe2..5fed85bb30 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -84,41 +84,6 @@ testing::AssertionResult notMatches(const std::string &Code,
return matchesConditionally(Code, AMatcher, false, "-std=c++11");
}
-inline testing::AssertionResult
-matchesConditionallyDynamic(const std::string &Code,
- const internal::DynTypedMatcher &AMatcher,
- bool ExpectMatch, llvm::StringRef CompileArg) {
- bool Found = false;
- MatchFinder Finder;
- Finder.addDynamicMatcher(AMatcher, new VerifyMatch(0, &Found));
- OwningPtr<FrontendActionFactory> Factory(newFrontendActionFactory(&Finder));
- // Some tests use typeof, which is a gnu extension.
- std::vector<std::string> Args(1, CompileArg);
- if (!runToolOnCodeWithArgs(Factory->create(), Code, Args)) {
- return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
- }
- if (!Found && ExpectMatch) {
- return testing::AssertionFailure()
- << "Could not find match in \"" << Code << "\"";
- } else if (Found && !ExpectMatch) {
- return testing::AssertionFailure()
- << "Found unexpected match in \"" << Code << "\"";
- }
- return testing::AssertionSuccess();
-}
-
-inline testing::AssertionResult
-matchesDynamic(const std::string &Code,
- const internal::DynTypedMatcher &AMatcher) {
- return matchesConditionallyDynamic(Code, AMatcher, true, "-std=c++11");
-}
-
-inline testing::AssertionResult
-notMatchesDynamic(const std::string &Code,
- const internal::DynTypedMatcher &AMatcher) {
- return matchesConditionallyDynamic(Code, AMatcher, false, "-std=c++11");
-}
-
template <typename T>
testing::AssertionResult
matchAndVerifyResultConditionally(const std::string &Code, const T &AMatcher,
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index b20c1ac6e9..d7973c957f 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -49,6 +49,9 @@ public:
StringRef boundID() const { return BoundID; }
+ virtual ast_type_traits::ASTNodeKind getSupportedKind() const {
+ return ast_type_traits::ASTNodeKind();
+ }
private:
uint64_t ID;
std::string BoundID;
@@ -172,15 +175,19 @@ TEST(ParserTest, ParseMatcher) {
using ast_matchers::internal::Matcher;
TEST(ParserTest, FullParserTest) {
- OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression(
- "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL));
- EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher));
- EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher));
+ OwningPtr<DynTypedMatcher> VarDecl(Parser::parseMatcherExpression(
+ "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))",
+ NULL));
+ Matcher<Decl> M = Matcher<Decl>::constructFrom(*VarDecl);
+ EXPECT_TRUE(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));
+ M = Matcher<Decl>::constructFrom(*HasParameter);
- Matcher.reset(
- Parser::parseMatcherExpression("hasParameter(1, hasName(\"x\"))", NULL));
- EXPECT_TRUE(matchesDynamic("void f(int a, int x);", *Matcher));
- EXPECT_FALSE(matchesDynamic("void f(int x, int a);", *Matcher));
+ EXPECT_TRUE(matches("void f(int a, int x);", M));
+ EXPECT_FALSE(matches("void f(int x, int a);", M));
Diagnostics Error;
EXPECT_TRUE(Parser::parseMatcherExpression(
@@ -188,7 +195,8 @@ TEST(ParserTest, FullParserTest) {
EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
"2:5: Error parsing argument 1 for matcher binaryOperator.\n"
"2:20: Error building matcher hasLHS.\n"
- "2:27: Incorrect type on function hasLHS for arg 1.",
+ "2:27: Incorrect type for arg 1. "
+ "(Expected = Matcher<Expr>) != (Actual = String)",
Error.ToStringFull());
}
diff --git a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 1055233846..fd6eaef2ea 100644
--- a/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -20,98 +20,131 @@ namespace {
using ast_matchers::internal::Matcher;
-DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) {
- const std::vector<ParserValue> Args;
- return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
- const VariantValue &Arg1,
- Diagnostics *Error) {
- std::vector<ParserValue> Args(1);
- Args[0].Value = Arg1;
- return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
- const VariantValue &Arg1,
- const VariantValue &Arg2,
- Diagnostics *Error) {
- std::vector<ParserValue> Args(2);
- Args[0].Value = Arg1;
- Args[1].Value = Arg2;
- return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-TEST(RegistryTest, CanConstructNoArgs) {
- OwningPtr<DynTypedMatcher> IsArrowValue(constructMatcher("isArrow", NULL));
- OwningPtr<DynTypedMatcher> BoolValue(constructMatcher("boolLiteral", NULL));
+class RegistryTest : public ::testing::Test {
+public:
+ std::vector<ParserValue> Args() { return std::vector<ParserValue>(); }
+ std::vector<ParserValue> Args(const VariantValue &Arg1) {
+ std::vector<ParserValue> Out(1);
+ Out[0].Value = Arg1;
+ return Out;
+ }
+ std::vector<ParserValue> Args(const VariantValue &Arg1,
+ const VariantValue &Arg2) {
+ std::vector<ParserValue> Out(2);
+ Out[0].Value = Arg1;
+ Out[1].Value = Arg2;
+ return Out;
+ }
+
+ template <class T>
+ Matcher<T> constructMatcher(StringRef MatcherName, Diagnostics *Error) {
+ OwningPtr<DynTypedMatcher> Out(
+ Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error));
+ return Matcher<T>::constructFrom(*Out);
+ }
+
+ 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);
+ }
+
+ 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);
+ }
+};
+
+TEST_F(RegistryTest, CanConstructNoArgs) {
+ Matcher<Stmt> IsArrowValue = constructMatcher<Stmt>(
+ "memberExpr", constructMatcher<MemberExpr>("isArrow", NULL), NULL);
+ Matcher<Stmt> BoolValue = constructMatcher<Stmt>("boolLiteral", NULL);
const std::string ClassSnippet = "struct Foo { int x; };\n"
"Foo *foo = new Foo;\n"
"int i = foo->x;\n";
const std::string BoolSnippet = "bool Foo = true;\n";
- EXPECT_TRUE(matchesDynamic(ClassSnippet, *IsArrowValue));
- EXPECT_TRUE(matchesDynamic(BoolSnippet, *BoolValue));
- EXPECT_FALSE(matchesDynamic(ClassSnippet, *BoolValue));
- EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue));
+ EXPECT_TRUE(matches(ClassSnippet, IsArrowValue));
+ EXPECT_TRUE(matches(BoolSnippet, BoolValue));
+ EXPECT_FALSE(matches(ClassSnippet, BoolValue));
+ EXPECT_FALSE(matches(BoolSnippet, IsArrowValue));
}
-TEST(RegistryTest, ConstructWithSimpleArgs) {
- OwningPtr<DynTypedMatcher> Value(
- constructMatcher("hasName", std::string("X"), NULL));
- EXPECT_TRUE(matchesDynamic("class X {};", *Value));
- EXPECT_FALSE(matchesDynamic("int x;", *Value));
-
- Value.reset(constructMatcher("parameterCountIs", 2, NULL));
- EXPECT_TRUE(matchesDynamic("void foo(int,int);", *Value));
- EXPECT_FALSE(matchesDynamic("void foo(int);", *Value));
+TEST_F(RegistryTest, ConstructWithSimpleArgs) {
+ Matcher<Decl> Value = constructMatcher<Decl>(
+ "namedDecl",
+ constructMatcher<NamedDecl>("hasName", std::string("X"), NULL), NULL);
+ EXPECT_TRUE(matches("class X {};", Value));
+ EXPECT_FALSE(matches("int x;", Value));
+
+ Value =
+ functionDecl(constructMatcher<FunctionDecl>("parameterCountIs", 2, NULL));
+ EXPECT_TRUE(matches("void foo(int,int);", Value));
+ EXPECT_FALSE(matches("void foo(int);", Value));
}
-TEST(RegistryTest, ConstructWithMatcherArgs) {
- OwningPtr<DynTypedMatcher> HasInitializerSimple(
- constructMatcher("hasInitializer", stmt(), NULL));
- OwningPtr<DynTypedMatcher> HasInitializerComplex(
- constructMatcher("hasInitializer", callExpr(), NULL));
+TEST_F(RegistryTest, ConstructWithMatcherArgs) {
+ Matcher<Decl> HasInitializerSimple = constructMatcher<Decl>(
+ "varDecl", constructMatcher<VarDecl>("hasInitializer", stmt(), NULL),
+ NULL);
+ Matcher<Decl> HasInitializerComplex = constructMatcher<Decl>(
+ "varDecl", constructMatcher<VarDecl>("hasInitializer", callExpr(), NULL),
+ NULL);
std::string code = "int i;";
- EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple));
- EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+ EXPECT_FALSE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
code = "int i = 1;";
- EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
- EXPECT_FALSE(matchesDynamic(code, *HasInitializerComplex));
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_FALSE(matches(code, HasInitializerComplex));
code = "int y(); int i = y();";
- EXPECT_TRUE(matchesDynamic(code, *HasInitializerSimple));
- EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex));
+ EXPECT_TRUE(matches(code, HasInitializerSimple));
+ EXPECT_TRUE(matches(code, HasInitializerComplex));
- OwningPtr<DynTypedMatcher> HasParameter(
- constructMatcher("hasParameter", 1, hasName("x"), NULL));
- EXPECT_TRUE(matchesDynamic("void f(int a, int x);", *HasParameter));
- EXPECT_FALSE(matchesDynamic("void f(int x, int a);", *HasParameter));
+ Matcher<Decl> HasParameter = functionDecl(
+ constructMatcher<FunctionDecl>("hasParameter", 1, hasName("x"), NULL));
+ EXPECT_TRUE(matches("void f(int a, int x);", HasParameter));
+ EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
}
-TEST(RegistryTest, Errors) {
+TEST_F(RegistryTest, Errors) {
// Incorrect argument count.
OwningPtr<Diagnostics> Error(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get()));
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher("hasInitializer", SourceRange(),
+ Args(), Error.get()));
EXPECT_EQ("Incorrect argument count. (Expected = 1) != (Actual = 0)",
Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("isArrow", std::string(), Error.get()));
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher("isArrow", SourceRange(),
+ Args(std::string()), Error.get()));
EXPECT_EQ("Incorrect argument count. (Expected = 0) != (Actual = 1)",
Error->ToString());
// Bad argument type
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get()));
- EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString());
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher("ofClass", SourceRange(),
+ Args(std::string()), Error.get()));
+ EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
+ "(Actual = String)",
+ Error->ToString());
Error.reset(new Diagnostics());
- EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(),
- ::std::string(), Error.get()));
- EXPECT_EQ("Incorrect type on function recordDecl for arg 2.",
+ EXPECT_TRUE(NULL ==
+ Registry::constructMatcher(
+ "recordDecl", SourceRange(),
+ Args(recordDecl(), parameterCountIs(3)), Error.get()));
+ 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 2aa0e425ca..8206d00b81 100644
--- a/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -28,8 +28,8 @@ TEST(VariantValueTest, Unsigned) {
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
}
TEST(VariantValueTest, String) {
@@ -38,11 +38,12 @@ TEST(VariantValueTest, String) {
EXPECT_TRUE(Value.isString());
EXPECT_EQ(kString, Value.getString());
+ EXPECT_EQ("String", Value.getTypeAsString());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
- EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
}
TEST(VariantValueTest, DynTypedMatcher) {
@@ -52,22 +53,25 @@ TEST(VariantValueTest, DynTypedMatcher) {
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
- // Conversion to any type of matcher works.
- // If they are not compatible it would just return a matcher that matches
- // nothing. We test this below.
+ // Can only convert to compatible matchers.
Value = recordDecl();
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
- Value = unaryOperator();
+ Value = ignoringImpCasts(expr());
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Stmt>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ 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_EQ("Matcher<Expr>", Value.getTypeAsString());
}
TEST(VariantValueTest, Assignment) {
@@ -76,13 +80,15 @@ TEST(VariantValueTest, Assignment) {
EXPECT_EQ("A", Value.getString());
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("String", Value.getTypeAsString());
Value = recordDecl();
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_TRUE(Value.isMatcher());
- EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
- EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+ EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+ EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+ EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
Value = 17;
EXPECT_TRUE(Value.isUnsigned());
@@ -94,25 +100,28 @@ TEST(VariantValueTest, Assignment) {
EXPECT_FALSE(Value.isUnsigned());
EXPECT_FALSE(Value.isString());
EXPECT_FALSE(Value.isMatcher());
+ EXPECT_EQ("Nothing", Value.getTypeAsString());
}
TEST(GeneicValueTest, Matcher) {
- EXPECT_TRUE(matchesDynamic(
- "class X {};", VariantValue(recordDecl(hasName("X"))).getMatcher()));
- EXPECT_TRUE(matchesDynamic(
- "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Decl>()));
- EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }",
- VariantValue(functionDecl()).getMatcher()));
- // Going through the wrong Matcher<T> will fail to match, even if the
- // underlying matcher is correct.
- EXPECT_FALSE(matchesDynamic(
- "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Stmt>()));
+ EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X")))
+ .getTypedMatcher<Decl>()));
+ EXPECT_TRUE(
+ matches("int x;", VariantValue(varDecl()).getTypedMatcher<Decl>()));
+ EXPECT_TRUE(matches("int foo() { return 1 + 1; }",
+ VariantValue(functionDecl()).getTypedMatcher<Decl>()));
+ // Can't get the wrong matcher.
+ EXPECT_FALSE(VariantValue(varDecl()).hasTypedMatcher<Stmt>());
+#if GTEST_HAS_DEATH_TEST and DEBUG
+ // Trying to get the wrong matcher fails an assertion in Matcher<T>.
+ EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher<Stmt>(),
+ "canConstructFrom");
+#endif
EXPECT_FALSE(
- matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher()));
- EXPECT_FALSE(matchesDynamic(
- "int foo() { return 1 + 1; }",
- VariantValue(declRefExpr()).getTypedMatcher<clang::DeclRefExpr>()));
+ matches("int x;", VariantValue(functionDecl()).getTypedMatcher<Decl>()));
+ EXPECT_FALSE(matches("int foo() { return 1 + 1; }",
+ VariantValue(declRefExpr()).getTypedMatcher<Stmt>()));
}
} // end anonymous namespace