///
/// 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
///
/// 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.
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
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)
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.
// allOf
// findAll
//
- // Adaptative matcher (similar to polymorphic matcher):
- // has
- // forEach
- // forEachDescendant
- // hasDescendant
- // hasParent
- // hasAncestor
- //
// Other:
// loc
// equals
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);
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());