From: Samuel Benzaquen Date: Thu, 20 Jun 2013 14:28:32 +0000 (+0000) Subject: Enhancements for the DynTypedMatcher system. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=76c2f92c4b4ab7e02857661a05e53ba4b501d87a;p=clang Enhancements for the DynTypedMatcher system. - Added conversion routines and checks in Matcher 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 --- diff --git a/include/clang/ASTMatchers/ASTMatchFinder.h b/include/clang/ASTMatchers/ASTMatchFinder.h index 18a0cf5ac9..d2b71d30df 100644 --- a/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/include/clang/ASTMatchers/ASTMatchFinder.h @@ -136,17 +136,6 @@ public: MatchCallback *Action); /// @} - /// \brief Adds a matcher to execute when running over the AST. - /// - /// This is similar to \c addMatcher(), but it uses the dynamic interface. It - /// is more flexible, but the lost type information enables a caller to pass - /// a matcher that cannot match anything. - /// - /// \returns \c true if the matcher is a valid top-level matcher, \c false - /// otherwise. - bool addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, - MatchCallback *Action); - /// \brief Creates a clang ASTConsumer that finds all matches. clang::ASTConsumer *newASTConsumer(); diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h index 7d09e67cbe..9e6d4bf348 100644 --- a/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -224,6 +224,12 @@ public: /// \return A new matcher with the \p ID bound to it if this matcher supports /// binding. Otherwise, returns NULL. Returns NULL by default. virtual DynTypedMatcher* tryBind(StringRef ID) const; + + /// \brief Returns the type this matcher works on. + /// + /// \c matches() will always return false unless the node passed is of this + /// or a derived type. + virtual ast_type_traits::ASTNodeKind getSupportedKind() const = 0; }; /// \brief Wrapper of a MatcherInterface *that allows copying. @@ -261,6 +267,27 @@ public: llvm::is_same::value >::type* = 0) : Implementation(new TypeToQualType(Other)) {} + /// \brief Returns \c true if the passed DynTypedMatcher can be converted + /// to a \c Matcher. + /// + /// This method verifies that the underlying matcher in \c Other can process + /// nodes of types T. + static bool canConstructFrom(const DynTypedMatcher &Other) { + return Other.getSupportedKind() + .isBaseOf(ast_type_traits::ASTNodeKind::getFromNodeKind()); + } + + /// \brief Construct a Matcher interface around the dynamic matcher + /// \c Other. + /// + /// This method asserts that canConstructFrom(Other) is \c true. Callers + /// should call canConstructFrom(Other) first to make sure that Other is + /// compatible with T. + static Matcher constructFrom(const DynTypedMatcher &Other) { + assert(canConstructFrom(Other)); + return Matcher(new WrappedMatcher(Other)); + } + /// \brief Forwards the call to the underlying MatcherInterface pointer. bool matches(const T &Node, ASTMatchFinder *Finder, @@ -281,6 +308,11 @@ public: return reinterpret_cast(Implementation.getPtr()); } + /// \brief Returns the type this matcher works on. + ast_type_traits::ASTNodeKind getSupportedKind() const { + return ast_type_traits::ASTNodeKind::getFromNodeKind(); + } + /// \brief Returns whether the matcher matches on the given \c DynNode. virtual bool matches(const ast_type_traits::DynTypedNode DynNode, ASTMatchFinder *Finder, @@ -335,6 +367,23 @@ private: const Matcher From; }; + /// \brief Simple MatcherInterface wrapper around a DynTypedMatcher. + class WrappedMatcher : public MatcherInterface { + public: + explicit WrappedMatcher(const DynTypedMatcher &Matcher) + : Inner(Matcher.clone()) {} + virtual ~WrappedMatcher() {} + + bool matches(const T &Node, ASTMatchFinder *Finder, + BoundNodesTreeBuilder *Builder) const { + return Inner->matches(ast_type_traits::DynTypedNode::create(Node), Finder, + Builder); + } + + private: + const OwningPtr Inner; + }; + IntrusiveRefCntPtr< MatcherInterface > Implementation; }; // class Matcher @@ -345,6 +394,34 @@ inline Matcher makeMatcher(MatcherInterface *Implementation) { return Matcher(Implementation); } +/// \brief Specialization of the conversion functions for QualType. +/// +/// These specializations provide the Matcher->Matcher +/// conversion that the static API does. +template <> +inline bool +Matcher::canConstructFrom(const DynTypedMatcher &Other) { + ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind(); + // We support implicit conversion from Matcher to Matcher + return SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind()) || + SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind()); +} + +template <> +inline Matcher +Matcher::constructFrom(const DynTypedMatcher &Other) { + assert(canConstructFrom(Other)); + ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind(); + if (SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind())) { + // We support implicit conversion from Matcher to Matcher + return Matcher::constructFrom(Other); + } + return makeMatcher(new WrappedMatcher(Other)); +} + /// \brief Finds the first node in a range that matches the given matcher. template bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, diff --git a/include/clang/ASTMatchers/Dynamic/VariantValue.h b/include/clang/ASTMatchers/Dynamic/VariantValue.h index fa6f08e67a..c2e60e1ce9 100644 --- a/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/include/clang/ASTMatchers/Dynamic/VariantValue.h @@ -70,44 +70,24 @@ public: /// \brief Set the value to be \c Matcher by taking ownership of the object. void takeMatcher(DynTypedMatcher *Matcher); - /// \brief Specialized Matcher is/get functions. + /// \brief Specialized Matcher functions. template - bool isTypedMatcher() const { - // TODO: Add some logic to test if T is actually valid for the underlying - // type of the matcher. - return isMatcher(); + bool hasTypedMatcher() const { + return isMatcher() && + ast_matchers::internal::Matcher::canConstructFrom(getMatcher()); } template ast_matchers::internal::Matcher getTypedMatcher() const { - return ast_matchers::internal::makeMatcher( - new DerivedTypeMatcher(getMatcher())); + return ast_matchers::internal::Matcher::constructFrom(getMatcher()); } + /// \brief String representation of the type of the value. + std::string getTypeAsString() const; + private: void reset(); - /// \brief Matcher bridge between a Matcher and a generic DynTypedMatcher. - template - class DerivedTypeMatcher : - public ast_matchers::internal::MatcherInterface { - public: - explicit DerivedTypeMatcher(const DynTypedMatcher &DynMatcher) - : DynMatcher(DynMatcher.clone()) {} - virtual ~DerivedTypeMatcher() {} - - typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder; - typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder; - bool matches(const T &Node, ASTMatchFinder *Finder, - BoundNodesTreeBuilder *Builder) const { - return DynMatcher->matches(ast_type_traits::DynTypedNode::create(Node), - Finder, Builder); - } - - private: - const OwningPtr DynMatcher; - }; - /// \brief All supported value types. enum ValueType { VT_Nothing, diff --git a/lib/ASTMatchers/ASTMatchFinder.cpp b/lib/ASTMatchers/ASTMatchFinder.cpp index d8f058848d..a68c7fdffe 100644 --- a/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/lib/ASTMatchers/ASTMatchFinder.cpp @@ -803,14 +803,6 @@ void MatchFinder::addMatcher(const TypeLocMatcher &NodeMatch, new TypeLocMatcher(NodeMatch), Action)); } -bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch, - MatchCallback *Action) { - MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action)); - // TODO: Do runtime type checking to make sure the matcher is one of the valid - // top-level matchers. - return true; -} - ASTConsumer *MatchFinder::newASTConsumer() { return new internal::MatchASTConsumer(&MatcherCallbackPairs, ParsingDone); } diff --git a/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/lib/ASTMatchers/Dynamic/Diagnostics.cpp index 79c9389cf5..6b1d6609a2 100644 --- a/lib/ASTMatchers/Dynamic/Diagnostics.cpp +++ b/lib/ASTMatchers/Dynamic/Diagnostics.cpp @@ -36,7 +36,7 @@ StringRef ErrorTypeToString(Diagnostics::ErrorType Type) { case Diagnostics::ET_RegistryWrongArgCount: return "Incorrect argument count. (Expected = $0) != (Actual = $1)"; case Diagnostics::ET_RegistryWrongArgType: - return "Incorrect type on function $0 for arg $1."; + return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)"; case Diagnostics::ET_RegistryNotBindable: return "Matcher does not support binding."; diff --git a/lib/ASTMatchers/Dynamic/Marshallers.h b/lib/ASTMatchers/Dynamic/Marshallers.h index 4ba33b8d2d..aceddc987f 100644 --- a/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/lib/ASTMatchers/Dynamic/Marshallers.h @@ -42,6 +42,7 @@ template struct ArgTypeTraits : public ArgTypeTraits { }; template <> struct ArgTypeTraits { + static StringRef asString() { return "String"; } static bool is(const VariantValue &Value) { return Value.isString(); } static const std::string &get(const VariantValue &Value) { return Value.getString(); @@ -49,13 +50,21 @@ template <> struct ArgTypeTraits { }; template struct ArgTypeTraits > { - static bool is(const VariantValue &Value) { return Value.isMatcher(); } + static std::string asString() { + return (Twine("Matcher<") + + ast_type_traits::ASTNodeKind::getFromNodeKind().asStringRef() + + ">").str(); + } + static bool is(const VariantValue &Value) { + return Value.hasTypedMatcher(); + } static ast_matchers::internal::Matcher get(const VariantValue &Value) { return Value.getTypedMatcher(); } }; template <> struct ArgTypeTraits { + static std::string asString() { return "Unsigned"; } static bool is(const VariantValue &Value) { return Value.isUnsigned(); } static unsigned get(const VariantValue &Value) { return Value.getUnsigned(); @@ -147,7 +156,8 @@ private: #define CHECK_ARG_TYPE(index, type) \ if (!ArgTypeTraits::is(Args[index].Value)) { \ Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType) \ - << MatcherName << (index + 1); \ + << (index + 1) << ArgTypeTraits::asString() \ + << Args[index].Value.getTypeAsString(); \ return NULL; \ } @@ -201,14 +211,16 @@ DynTypedMatcher *VariadicMatcherCreateCallback(StringRef MatcherName, bool HasError = false; for (size_t i = 0, e = Args.size(); i != e; ++i) { - if (!Args[i].Value.isTypedMatcher()) { - Error->pushErrorFrame(Args[i].Range, Error->ET_RegistryWrongArgType) - << MatcherName << (i + 1); + typedef ArgTypeTraits DerivedTraits; + const ParserValue &Arg = Args[i]; + const VariantValue &Value = Arg.Value; + if (!DerivedTraits::is(Value)) { + Error->pushErrorFrame(Arg.Range, Error->ET_RegistryWrongArgType) + << (i + 1) << DerivedTraits::asString() << Value.getTypeAsString(); HasError = true; break; } - InnerArgs[i] = - new DerivedMatcherType(Args[i].Value.getTypedMatcher()); + InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value)); } DynTypedMatcher *Out = NULL; diff --git a/lib/ASTMatchers/Dynamic/VariantValue.cpp b/lib/ASTMatchers/Dynamic/VariantValue.cpp index 6fcbe7fc49..912858f548 100644 --- a/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/lib/ASTMatchers/Dynamic/VariantValue.cpp @@ -14,6 +14,8 @@ #include "clang/ASTMatchers/Dynamic/VariantValue.h" +#include "clang/Basic/LLVM.h" + namespace clang { namespace ast_matchers { namespace dynamic { @@ -123,6 +125,18 @@ void VariantValue::takeMatcher(DynTypedMatcher *NewValue) { Value.Matcher = NewValue; } +std::string VariantValue::getTypeAsString() const { + switch (Type) { + case VT_String: return "String"; + case VT_Matcher: + return (Twine("Matcher<") + getMatcher().getSupportedKind().asStringRef() + + ">").str(); + case VT_Unsigned: return "Unsigned"; + case VT_Nothing: return "Nothing"; + } + llvm_unreachable("Invalid Type"); +} + } // end namespace dynamic } // end namespace ast_matchers } // end namespace clang 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 Factory(newFrontendActionFactory(&Finder)); - // Some tests use typeof, which is a gnu extension. - std::vector 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 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 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 VarDecl(Parser::parseMatcherExpression( + "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))", + NULL)); + Matcher M = Matcher::constructFrom(*VarDecl); + EXPECT_TRUE(matches("int x = 1 + false;", M)); + EXPECT_FALSE(matches("int x = true + 1;", M)); + + OwningPtr HasParameter(Parser::parseMatcherExpression( + "functionDecl(hasParameter(1, hasName(\"x\")))", NULL)); + M = Matcher::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) != (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 Args; - return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); -} - -DynTypedMatcher *constructMatcher(StringRef MatcherName, - const VariantValue &Arg1, - Diagnostics *Error) { - std::vector 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 Args(2); - Args[0].Value = Arg1; - Args[1].Value = Arg2; - return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error); -} - -TEST(RegistryTest, CanConstructNoArgs) { - OwningPtr IsArrowValue(constructMatcher("isArrow", NULL)); - OwningPtr BoolValue(constructMatcher("boolLiteral", NULL)); +class RegistryTest : public ::testing::Test { +public: + std::vector Args() { return std::vector(); } + std::vector Args(const VariantValue &Arg1) { + std::vector Out(1); + Out[0].Value = Arg1; + return Out; + } + std::vector Args(const VariantValue &Arg1, + const VariantValue &Arg2) { + std::vector Out(2); + Out[0].Value = Arg1; + Out[1].Value = Arg2; + return Out; + } + + template + Matcher constructMatcher(StringRef MatcherName, Diagnostics *Error) { + OwningPtr Out( + Registry::constructMatcher(MatcherName, SourceRange(), Args(), Error)); + return Matcher::constructFrom(*Out); + } + + template + Matcher constructMatcher(StringRef MatcherName, const VariantValue &Arg1, + Diagnostics *Error) { + OwningPtr Out(Registry::constructMatcher( + MatcherName, SourceRange(), Args(Arg1), Error)); + return Matcher::constructFrom(*Out); + } + + template + Matcher constructMatcher(StringRef MatcherName, const VariantValue &Arg1, + const VariantValue &Arg2, Diagnostics *Error) { + OwningPtr Out(Registry::constructMatcher( + MatcherName, SourceRange(), Args(Arg1, Arg2), Error)); + return Matcher::constructFrom(*Out); + } +}; + +TEST_F(RegistryTest, CanConstructNoArgs) { + Matcher IsArrowValue = constructMatcher( + "memberExpr", constructMatcher("isArrow", NULL), NULL); + Matcher BoolValue = constructMatcher("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 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 Value = constructMatcher( + "namedDecl", + constructMatcher("hasName", std::string("X"), NULL), NULL); + EXPECT_TRUE(matches("class X {};", Value)); + EXPECT_FALSE(matches("int x;", Value)); + + Value = + functionDecl(constructMatcher("parameterCountIs", 2, NULL)); + EXPECT_TRUE(matches("void foo(int,int);", Value)); + EXPECT_FALSE(matches("void foo(int);", Value)); } -TEST(RegistryTest, ConstructWithMatcherArgs) { - OwningPtr HasInitializerSimple( - constructMatcher("hasInitializer", stmt(), NULL)); - OwningPtr HasInitializerComplex( - constructMatcher("hasInitializer", callExpr(), NULL)); +TEST_F(RegistryTest, ConstructWithMatcherArgs) { + Matcher HasInitializerSimple = constructMatcher( + "varDecl", constructMatcher("hasInitializer", stmt(), NULL), + NULL); + Matcher HasInitializerComplex = constructMatcher( + "varDecl", constructMatcher("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 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 HasParameter = functionDecl( + constructMatcher("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 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) != " + "(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) != " + "(Actual = Matcher)", 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()); - EXPECT_FALSE(Value.isTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); } 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()); - EXPECT_FALSE(Value.isTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); } TEST(VariantValueTest, DynTypedMatcher) { @@ -52,22 +53,25 @@ TEST(VariantValueTest, DynTypedMatcher) { EXPECT_FALSE(Value.isString()); EXPECT_TRUE(Value.isMatcher()); - EXPECT_TRUE(Value.isTypedMatcher()); - EXPECT_TRUE(Value.isTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_TRUE(Value.hasTypedMatcher()); + EXPECT_EQ("Matcher", 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()); - EXPECT_TRUE(Value.isTypedMatcher()); + EXPECT_TRUE(Value.hasTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_EQ("Matcher", Value.getTypeAsString()); - Value = unaryOperator(); + Value = ignoringImpCasts(expr()); EXPECT_TRUE(Value.isMatcher()); - EXPECT_TRUE(Value.isTypedMatcher()); - EXPECT_TRUE(Value.isTypedMatcher()); - EXPECT_TRUE(Value.isTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_TRUE(Value.hasTypedMatcher()); + EXPECT_TRUE(Value.hasTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_EQ("Matcher", 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()); - EXPECT_TRUE(Value.isTypedMatcher()); + EXPECT_TRUE(Value.hasTypedMatcher()); + EXPECT_FALSE(Value.hasTypedMatcher()); + EXPECT_EQ("Matcher", 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())); - EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }", - VariantValue(functionDecl()).getMatcher())); - // Going through the wrong Matcher will fail to match, even if the - // underlying matcher is correct. - EXPECT_FALSE(matchesDynamic( - "int x;", VariantValue(varDecl()).getTypedMatcher())); + EXPECT_TRUE(matches("class X {};", VariantValue(recordDecl(hasName("X"))) + .getTypedMatcher())); + EXPECT_TRUE( + matches("int x;", VariantValue(varDecl()).getTypedMatcher())); + EXPECT_TRUE(matches("int foo() { return 1 + 1; }", + VariantValue(functionDecl()).getTypedMatcher())); + // Can't get the wrong matcher. + EXPECT_FALSE(VariantValue(varDecl()).hasTypedMatcher()); +#if GTEST_HAS_DEATH_TEST and DEBUG + // Trying to get the wrong matcher fails an assertion in Matcher. + EXPECT_DEATH(VariantValue(varDecl()).getTypedMatcher(), + "canConstructFrom"); +#endif EXPECT_FALSE( - matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher())); - EXPECT_FALSE(matchesDynamic( - "int foo() { return 1 + 1; }", - VariantValue(declRefExpr()).getTypedMatcher())); + matches("int x;", VariantValue(functionDecl()).getTypedMatcher())); + EXPECT_FALSE(matches("int foo() { return 1 + 1; }", + VariantValue(declRefExpr()).getTypedMatcher())); } } // end anonymous namespace