diff options
author | Samuel Benzaquen <sbenza@google.com> | 2013-06-20 14:28:32 +0000 |
---|---|---|
committer | Samuel Benzaquen <sbenza@google.com> | 2013-06-20 14:28:32 +0000 |
commit | 76c2f92c4b4ab7e02857661a05e53ba4b501d87a (patch) | |
tree | ad748a8f9c5291b4cf6d7dbee5c3ac4c975ef4ce /unittests/ASTMatchers | |
parent | cf52ca6bb6dd76a1bd967bc422287fafafa1e45a (diff) | |
download | clang-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.h | 35 | ||||
-rw-r--r-- | unittests/ASTMatchers/Dynamic/ParserTest.cpp | 26 | ||||
-rw-r--r-- | unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 157 | ||||
-rw-r--r-- | unittests/ASTMatchers/Dynamic/VariantValueTest.cpp | 71 |
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 |