Author: sbenza Date: Wed Jul 24 09:48:01 2013 New Revision: 187044 URL: http://llvm.org/viewvc/llvm-project?rev=187044&view=rev Log: Add support for Adaptative matchers on the dynamic registry.
Summary: Add support for Adaptative matchers on the dynamic registry. Each adaptative matcher is created with a function template. We instantiate the function N times, one for each possible From type and apply the techniques used on argument overloaded and polymorphic matchers to add them to the registry. Reviewers: klimek CC: cfe-commits, revane Differential Revision: http://llvm-reviews.chandlerc.com/D1201 Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=187044&r1=187043&r2=187044&view=diff ============================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Wed Jul 24 09:48:01 2013 @@ -1708,11 +1708,13 @@ findAll(const internal::Matcher<T> &Matc /// /// Usable as: Any Matcher template <typename ParentT> -internal::ArgumentAdaptingMatcher<internal::HasParentMatcher, ParentT> +internal::ArgumentAdaptingMatcher<internal::HasParentMatcher, ParentT, + internal::TypeList<Decl, Stmt>, + internal::TypeList<Decl, Stmt> > hasParent(const internal::Matcher<ParentT> &ParentMatcher) { return internal::ArgumentAdaptingMatcher< - internal::HasParentMatcher, - ParentT>(ParentMatcher); + internal::HasParentMatcher, ParentT, internal::TypeList<Decl, Stmt>, + internal::TypeList<Decl, Stmt> >(ParentMatcher); } /// \brief Matches AST nodes that have an ancestor that matches the provided @@ -1727,11 +1729,13 @@ hasParent(const internal::Matcher<Parent /// /// Usable as: Any Matcher template <typename AncestorT> -internal::ArgumentAdaptingMatcher<internal::HasAncestorMatcher, AncestorT> +internal::ArgumentAdaptingMatcher<internal::HasAncestorMatcher, AncestorT, + internal::TypeList<Decl, Stmt>, + internal::TypeList<Decl, Stmt> > hasAncestor(const internal::Matcher<AncestorT> &AncestorMatcher) { return internal::ArgumentAdaptingMatcher< - internal::HasAncestorMatcher, - AncestorT>(AncestorMatcher); + internal::HasAncestorMatcher, AncestorT, internal::TypeList<Decl, Stmt>, + internal::TypeList<Decl, Stmt> >(AncestorMatcher); } /// \brief Matches if the provided matcher does not match. Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=187044&r1=187043&r2=187044&view=diff ============================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Wed Jul 24 09:48:01 2013 @@ -732,35 +732,6 @@ protected: AncestorMatchMode MatchMode) = 0; }; -/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by -/// "adapting" a \c To into a \c T. -/// -/// The \c ArgumentAdapterT argument specifies how the adaptation is done. -/// -/// For example: -/// \c ArgumentAdaptingMatcher<HasMatcher, T>(InnerMatcher); -/// Given that \c InnerMatcher is of type \c Matcher<T>, this returns a matcher -/// that is convertible into any matcher of type \c To by constructing -/// \c HasMatcher<To, T>(InnerMatcher). -/// -/// If a matcher does not need knowledge about the inner type, prefer to use -/// PolymorphicMatcherWithParam1. -template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, - typename T> -class ArgumentAdaptingMatcher { -public: - explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher) - : InnerMatcher(InnerMatcher) {} - - template <typename To> - operator Matcher<To>() const { - return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); - } - -private: - const Matcher<T> InnerMatcher; -}; - /// \brief A simple type-list implementation. /// /// It is implemented as a flat struct with a maximum number of arguments to @@ -813,6 +784,43 @@ template <class T> struct ExtractFunctio typedef T type; }; +/// \brief Default type lists for ArgumentAdaptingMatcher matchers. +typedef AllNodeBaseTypes AdaptativeDefaultFromTypes; +typedef TypeList<Decl, Stmt, NestedNameSpecifier, NestedNameSpecifierLoc, + TypeLoc, QualType> AdaptativeDefaultToTypes; + +/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by +/// "adapting" a \c To into a \c T. +/// +/// The \c ArgumentAdapterT argument specifies how the adaptation is done. +/// +/// For example: +/// \c ArgumentAdaptingMatcher<HasMatcher, T>(InnerMatcher); +/// Given that \c InnerMatcher is of type \c Matcher<T>, this returns a matcher +/// that is convertible into any matcher of type \c To by constructing +/// \c HasMatcher<To, T>(InnerMatcher). +/// +/// If a matcher does not need knowledge about the inner type, prefer to use +/// PolymorphicMatcherWithParam1. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename T, typename FromTypes = AdaptativeDefaultFromTypes, + typename ToTypes = AdaptativeDefaultToTypes> +class ArgumentAdaptingMatcher { +public: + explicit ArgumentAdaptingMatcher(const Matcher<T> &InnerMatcher) + : InnerMatcher(InnerMatcher) {} + + typedef ToTypes ReturnTypes; + + template <typename To> + operator Matcher<To>() const { + return Matcher<To>(new ArgumentAdapterT<To, T>(InnerMatcher)); + } + +private: + const Matcher<T> InnerMatcher; +}; + /// \brief A PolymorphicMatcherWithParamN<MatcherT, P1, ..., PN> object can be /// created from N parameters p1, ..., pN (of type P1, ..., PN) and /// used as a Matcher<T> where a MatcherT<T, P1, ..., PN>(p1, ..., pN) Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=187044&r1=187043&r2=187044&view=diff ============================================================================== --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original) +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Wed Jul 24 09:48:01 2013 @@ -109,6 +109,64 @@ class OverloadedMatcherCreateCallback : registerMatcher(#name, new OverloadedMatcherCreateCallback(Callbacks)); \ } while (0) +/// \brief Class that allows us to bind to the constructor of an +/// \c ArgumentAdaptingMatcher. +/// This class, together with \c collectAdaptativeMatcherOverloads below, help +/// us detect the Adapter class and create overload functions for the +/// appropriate To/From types. +/// We instantiate the \c createAdatingMatcher function for every type in +/// \c FromTypes. \c ToTypes is handled on the marshaller side by using the +/// \c ReturnTypes typedef in \c ArgumentAdaptingMatcher. +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename FromTypes, typename ToTypes> +struct AdaptativeMatcherWrapper { + template <typename FromArg> + static ast_matchers::internal::ArgumentAdaptingMatcher< + ArgumentAdapterT, FromArg, FromTypes, ToTypes> + createAdatingMatcher( + const ast_matchers::internal::Matcher<FromArg> &InnerMatcher) { + return ast_matchers::internal::ArgumentAdaptingMatcher< + ArgumentAdapterT, FromArg, FromTypes, ToTypes>(InnerMatcher); + } + + static void collectOverloads(StringRef Name, + std::vector<MatcherCreateCallback *> &Out, + ast_matchers::internal::EmptyTypeList) {} + + template <typename FromTypeList> + static void collectOverloads(StringRef Name, + std::vector<MatcherCreateCallback *> &Out, + FromTypeList TypeList) { + Out.push_back(internal::makeMatcherAutoMarshall( + &createAdatingMatcher<typename FromTypeList::head>, Name)); + collectOverloads(Name, Out, typename FromTypeList::tail()); + } + + static void collectOverloads(StringRef Name, + std::vector<MatcherCreateCallback *> &Out) { + collectOverloads(Name, Out, FromTypes()); + } +}; + +template <template <typename ToArg, typename FromArg> class ArgumentAdapterT, + typename DummyArg, typename FromTypes, typename ToTypes> +void collectAdaptativeMatcherOverloads( + StringRef Name, + ast_matchers::internal::ArgumentAdaptingMatcher<ArgumentAdapterT, DummyArg, + FromTypes, ToTypes>( + *func)(const ast_matchers::internal::Matcher<DummyArg> &), + std::vector<MatcherCreateCallback *> &Out) { + AdaptativeMatcherWrapper<ArgumentAdapterT, FromTypes, + ToTypes>::collectOverloads(Name, Out); +} + +#define REGISTER_ADAPTATIVE(name) \ + do { \ + std::vector<MatcherCreateCallback *> Overloads; \ + collectAdaptativeMatcherOverloads(#name, &name<Decl>, Overloads); \ + registerMatcher(#name, new OverloadedMatcherCreateCallback(Overloads)); \ + } while (0) + /// \brief Generate a registry map with all the known matchers. RegistryMaps::RegistryMaps() { // TODO: Here is the list of the missing matchers, grouped by reason. @@ -123,14 +181,6 @@ RegistryMaps::RegistryMaps() { // allOf // findAll // - // Adaptative matcher (similar to polymorphic matcher): - // has - // forEach - // forEachDescendant - // hasDescendant - // hasParent - // hasAncestor - // // Other: // loc // equals @@ -146,6 +196,13 @@ RegistryMaps::RegistryMaps() { REGISTER_OVERLOADED_2(references); REGISTER_OVERLOADED_2(thisPointerType); + REGISTER_ADAPTATIVE(forEach); + REGISTER_ADAPTATIVE(forEachDescendant); + REGISTER_ADAPTATIVE(has); + REGISTER_ADAPTATIVE(hasAncestor); + REGISTER_ADAPTATIVE(hasDescendant); + REGISTER_ADAPTATIVE(hasParent); + REGISTER_MATCHER(accessSpecDecl); REGISTER_MATCHER(alignOfExpr); REGISTER_MATCHER(anything); Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=187044&r1=187043&r2=187044&view=diff ============================================================================== --- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Wed Jul 24 09:48:01 2013 @@ -222,6 +222,37 @@ TEST_F(RegistryTest, CXXCtorInitializer) EXPECT_FALSE(matches("struct Foo { Foo() : bar(1) {} int bar; };", CtorDecl)); } +TEST_F(RegistryTest, Adaptative) { + Matcher<Decl> D = constructMatcher( + "recordDecl", + constructMatcher( + "has", + constructMatcher("recordDecl", + constructMatcher("hasName", std::string("X"))))) + .getTypedMatcher<Decl>(); + EXPECT_TRUE(matches("class X {};", D)); + EXPECT_TRUE(matches("class Y { class X {}; };", D)); + EXPECT_FALSE(matches("class Y { class Z {}; };", D)); + + Matcher<Stmt> S = constructMatcher( + "forStmt", + constructMatcher( + "hasDescendant", + constructMatcher("varDecl", + constructMatcher("hasName", std::string("X"))))) + .getTypedMatcher<Stmt>(); + EXPECT_TRUE(matches("void foo() { for(int X;;); }", S)); + EXPECT_TRUE(matches("void foo() { for(;;) { int X; } }", S)); + EXPECT_FALSE(matches("void foo() { for(;;); }", S)); + EXPECT_FALSE(matches("void foo() { if (int X = 0){} }", S)); + + S = constructMatcher( + "compoundStmt", constructMatcher("hasParent", constructMatcher("ifStmt"))) + .getTypedMatcher<Stmt>(); + EXPECT_TRUE(matches("void foo() { if (true) { int x = 42; } }", S)); + EXPECT_FALSE(matches("void foo() { if (true) return; }", S)); +} + TEST_F(RegistryTest, Errors) { // Incorrect argument count. OwningPtr<Diagnostics> Error(new Diagnostics()); _______________________________________________ cfe-commits mailing list [email protected] http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
