diff options
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchFinder.h | 11 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchersInternal.h | 77 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/Dynamic/VariantValue.h | 36 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/ASTMatchFinder.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Marshallers.h | 26 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/VariantValue.cpp | 14 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/ASTMatchersTest.h | 35 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp | 26 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 157 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp | 71 |
11 files changed, 271 insertions, 192 deletions
diff --git a/clang/include/clang/ASTMatchers/ASTMatchFinder.h b/clang/include/clang/ASTMatchers/ASTMatchFinder.h index 18a0cf5ac92..d2b71d30df7 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchFinder.h +++ b/clang/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/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 7d09e67cbe9..9e6d4bf3482 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/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<T> *that allows copying. @@ -261,6 +267,27 @@ public: llvm::is_same<TypeT, Type>::value >::type* = 0) : Implementation(new TypeToQualType<TypeT>(Other)) {} + /// \brief Returns \c true if the passed DynTypedMatcher can be converted + /// to a \c Matcher<T>. + /// + /// 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<T>()); + } + + /// \brief Construct a Matcher<T> 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<T> constructFrom(const DynTypedMatcher &Other) { + assert(canConstructFrom(Other)); + return Matcher<T>(new WrappedMatcher(Other)); + } + /// \brief Forwards the call to the underlying MatcherInterface<T> pointer. bool matches(const T &Node, ASTMatchFinder *Finder, @@ -281,6 +308,11 @@ public: return reinterpret_cast<uint64_t>(Implementation.getPtr()); } + /// \brief Returns the type this matcher works on. + ast_type_traits::ASTNodeKind getSupportedKind() const { + return ast_type_traits::ASTNodeKind::getFromNodeKind<T>(); + } + /// \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<Base> From; }; + /// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher. + class WrappedMatcher : public MatcherInterface<T> { + 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<DynTypedMatcher> Inner; + }; + IntrusiveRefCntPtr< MatcherInterface<T> > Implementation; }; // class Matcher @@ -345,6 +394,34 @@ inline Matcher<T> makeMatcher(MatcherInterface<T> *Implementation) { return Matcher<T>(Implementation); } +/// \brief Specialization of the conversion functions for QualType. +/// +/// These specializations provide the Matcher<Type>->Matcher<QualType> +/// conversion that the static API does. +template <> +inline bool +Matcher<QualType>::canConstructFrom(const DynTypedMatcher &Other) { + ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind(); + // We support implicit conversion from Matcher<Type> to Matcher<QualType> + return SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<Type>()) || + SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<QualType>()); +} + +template <> +inline Matcher<QualType> +Matcher<QualType>::constructFrom(const DynTypedMatcher &Other) { + assert(canConstructFrom(Other)); + ast_type_traits::ASTNodeKind SourceKind = Other.getSupportedKind(); + if (SourceKind.isSame( + ast_type_traits::ASTNodeKind::getFromNodeKind<Type>())) { + // We support implicit conversion from Matcher<Type> to Matcher<QualType> + return Matcher<Type>::constructFrom(Other); + } + return makeMatcher(new WrappedMatcher(Other)); +} + /// \brief Finds the first node in a range that matches the given matcher. template <typename MatcherT, typename IteratorT> bool matchesFirstInRange(const MatcherT &Matcher, IteratorT Start, diff --git a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h b/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h index fa6f08e67ae..c2e60e1ce9e 100644 --- a/clang/include/clang/ASTMatchers/Dynamic/VariantValue.h +++ b/clang/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<T> is/get functions. + /// \brief Specialized Matcher<T> functions. template <class T> - 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<T>::canConstructFrom(getMatcher()); } template <class T> ast_matchers::internal::Matcher<T> getTypedMatcher() const { - return ast_matchers::internal::makeMatcher( - new DerivedTypeMatcher<T>(getMatcher())); + return ast_matchers::internal::Matcher<T>::constructFrom(getMatcher()); } + /// \brief String representation of the type of the value. + std::string getTypeAsString() const; + private: void reset(); - /// \brief Matcher bridge between a Matcher<T> and a generic DynTypedMatcher. - template <class T> - class DerivedTypeMatcher : - public ast_matchers::internal::MatcherInterface<T> { - 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<DynTypedMatcher> DynMatcher; - }; - /// \brief All supported value types. enum ValueType { VT_Nothing, diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index d8f058848dc..a68c7fdffe1 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/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/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp b/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp index 79c9389cf5f..6b1d6609a21 100644 --- a/clang/lib/ASTMatchers/Dynamic/Diagnostics.cpp +++ b/clang/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/clang/lib/ASTMatchers/Dynamic/Marshallers.h b/clang/lib/ASTMatchers/Dynamic/Marshallers.h index 4ba33b8d2d9..aceddc987fe 100644 --- a/clang/lib/ASTMatchers/Dynamic/Marshallers.h +++ b/clang/lib/ASTMatchers/Dynamic/Marshallers.h @@ -42,6 +42,7 @@ template <class T> struct ArgTypeTraits<const T &> : public ArgTypeTraits<T> { }; template <> struct ArgTypeTraits<std::string> { + 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<std::string> { }; template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > { - static bool is(const VariantValue &Value) { return Value.isMatcher(); } + static std::string asString() { + return (Twine("Matcher<") + + ast_type_traits::ASTNodeKind::getFromNodeKind<T>().asStringRef() + + ">").str(); + } + static bool is(const VariantValue &Value) { + return Value.hasTypedMatcher<T>(); + } static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) { return Value.getTypedMatcher<T>(); } }; template <> struct ArgTypeTraits<unsigned> { + 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<type>::is(Args[index].Value)) { \ Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType) \ - << MatcherName << (index + 1); \ + << (index + 1) << ArgTypeTraits<type>::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<DerivedType>()) { - Error->pushErrorFrame(Args[i].Range, Error->ET_RegistryWrongArgType) - << MatcherName << (i + 1); + typedef ArgTypeTraits<DerivedMatcherType> 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<DerivedType>()); + InnerArgs[i] = new DerivedMatcherType(DerivedTraits::get(Value)); } DynTypedMatcher *Out = NULL; diff --git a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp b/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp index 6fcbe7fc495..912858f5485 100644 --- a/clang/lib/ASTMatchers/Dynamic/VariantValue.cpp +++ b/clang/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/clang/unittests/ASTMatchers/ASTMatchersTest.h b/clang/unittests/ASTMatchers/ASTMatchersTest.h index 05258f7fe2a..5fed85bb30b 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.h +++ b/clang/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/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp index b20c1ac6e9a..d7973c957f1 100644 --- a/clang/unittests/ASTMatchers/Dynamic/ParserTest.cpp +++ b/clang/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/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index 1055233846d..fd6eaef2ea8 100644 --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/clang/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/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp b/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp index 2aa0e425ca8..8206d00b81a 100644 --- a/clang/unittests/ASTMatchers/Dynamic/VariantValueTest.cpp +++ b/clang/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 |

