diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchers.h | 16 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchersInternal.h | 66 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Registry.cpp | 73 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 31 |
4 files changed, 143 insertions, 43 deletions
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index b151985a16e..fc36227cbe2 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -1708,11 +1708,13 @@ findAll(const internal::Matcher<T> &Matcher) { /// /// 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<ParentT> &ParentMatcher) { /// /// 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. diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 915f1bd6afe..711e67dc137 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -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 ExtractFunctionArgMeta<void(T)> { 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) diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 2daaa88af52..ac3241c466e 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -109,6 +109,64 @@ class OverloadedMatcherCreateCallback : public MatcherCreateCallback { 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); diff --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp index e69017e531d..7f49b6a4ac7 100644 --- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp +++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp @@ -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()); |

