[cfe-commits] r160673 - in /cfe/trunk: include/clang/ASTMatchers/ASTMatchers.h include/clang/ASTMatchers/ASTMatchersInternal.h unittests/ASTMatchers/ASTMatchersTest.cpp

Manuel Klimek klimek at google.com
Tue Jul 24 06:37:29 PDT 2012


Author: klimek
Date: Tue Jul 24 08:37:29 2012
New Revision: 160673

URL: http://llvm.org/viewvc/llvm-project?rev=160673&view=rev
Log:
Introduces a new concept for binding results to matchers
as per Chandler's request:
- introduces a new matcher base type BindableMatcher that
  provides the bind() call
- makes all dynamic-cast matcher creation functions return
  BindableMatchers; the special case about dynamic-cast
  matchers is that the node they match on and the node
  their child matchers match on are the same node, just
  casted to a different type; thus, there is no ambiguity
  on what bind() matches on; additionally, those are the
  matchers that we name with nouns in the matcher language,
  so it's easy for users to intuitively know which matchers
  are bindable

To make this change possible, we got rid of a non-orthogonal
implementation of thisPointerType, which had an implicit
dynamic-cast matcher from CallExpr to CXXMemberCallExpr; as
alternative, we now provide a memberCall dynamic-cast matcher
and thisPointerType is a predicate on CXXMemberCallExpr.

Last, the ArgumentAdaptingMatcher is actually not required
for the implementation of makeDynCastAllOfComposite - this
simplification makes it more obvious where the bind() call
can be used based on the matcher creation function types.


Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
    cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=160673&r1=160672&r2=160673&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Tue Jul 24 08:37:29 2012
@@ -104,8 +104,8 @@
 /// FIXME: Add example for accessing it.
 template <typename T>
 internal::Matcher<T> id(const std::string &ID,
-                        const internal::Matcher<T> &InnerMatcher) {
-  return internal::Matcher<T>(new internal::IdMatcher<T>(ID, InnerMatcher));
+                        const internal::BindableMatcher<T> &InnerMatcher) {
+  return InnerMatcher.bind(ID);
 }
 
 /// \brief Types of matchers for the top-level classes in the AST class
@@ -338,11 +338,19 @@
 
 /// \brief Matches call expressions.
 ///
-/// Example matches x.y()
+/// Example matches x.y() and y()
 ///   X x;
 ///   x.y();
+///   y();
 const internal::VariadicDynCastAllOfMatcher<Stmt, CallExpr> call;
 
+/// \brief Matches member call expressions.
+///
+/// Example matches x.y()
+///   X x;
+///   x.y();
+const internal::VariadicDynCastAllOfMatcher<Stmt, CXXMemberCallExpr> memberCall;
+
 /// \brief Matches init list expressions.
 ///
 /// Given
@@ -1120,14 +1128,14 @@
 
 /// \brief Matches if the expression's type either matches the specified
 /// matcher, or is a pointer to a type that matches the InnerMatcher.
-inline internal::Matcher<CallExpr> thisPointerType(
+inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
     const internal::Matcher<QualType> &InnerMatcher) {
   return onImplicitObjectArgument(
       anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
 }
 
 /// \brief Overloaded to match the type's declaration.
-inline internal::Matcher<CallExpr> thisPointerType(
+inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
     const internal::Matcher<Decl> &InnerMatcher) {
   return onImplicitObjectArgument(
       anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=160673&r1=160672&r2=160673&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Tue Jul 24 08:37:29 2012
@@ -440,20 +440,19 @@
                                    BindKind Bind) = 0;
 };
 
-/// \brief Converts a Matcher<T> to a matcher of desired type To by "adapting"
-/// a To into a T.
+/// \brief Converts a \c Matcher<T> to a matcher of desired type \c To by
+/// "adapting" a \c To into a \c T.
 ///
-/// The ArgumentAdapterT argument specifies how the adaptation is done.
+/// The \c ArgumentAdapterT argument specifies how the adaptation is done.
 ///
 /// For example:
-///   ArgumentAdaptingMatcher<DynCastMatcher, T>(InnerMatcher);
-/// returns a matcher that can be used where a Matcher<To> is required, if
-/// To and T are in the same type hierarchy, and thus dyn_cast can be
-/// called to convert a To to a T.
-///
-/// FIXME: Make sure all our applications of this class actually require
-/// knowledge about the inner type. DynCastMatcher obviously does, but the
-/// Has *matchers require the inner type solely for COMPILE_ASSERT purposes.
+///   \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 {
@@ -567,19 +566,6 @@
   const Matcher<To> InnerMatcher;
 };
 
-/// \brief Enables the user to pass a Matcher<CXXMemberCallExpr> to
-/// Call().
-///
-/// FIXME: Alternatives are using more specific methods than Call, like
-/// MemberCall, or not using VariadicFunction for Call and overloading it.
-template <>
-template <>
-inline Matcher<CXXMemberCallExpr>::
-operator Matcher<CallExpr>() const {
-  return makeMatcher(
-    new DynCastMatcher<CallExpr, CXXMemberCallExpr>(*this));
-}
-
 /// \brief Matcher<T> that wraps an inner Matcher<T> and binds the matched node
 /// to an ID if the inner matcher matches on the node.
 template <typename T>
@@ -605,6 +591,28 @@
   const Matcher<T> InnerMatcher;
 };
 
+/// \brief A Matcher that allows binding the node it matches to an id.
+///
+/// BindableMatcher provides a \a bind() method that allows binding the
+/// matched node to an id if the match was successful.
+template <typename T>
+class BindableMatcher : public Matcher<T> {
+public:
+  BindableMatcher(MatcherInterface<T> *Implementation)
+    : Matcher<T>(Implementation) {}
+
+  /// \brief Returns a matcher that will bind the matched node on a match.
+  ///
+  /// The returned matcher is equivalent to this matcher, but will
+  /// bind the matched node on a match.
+  Matcher<T> bind(StringRef ID) const {
+    TOOLING_COMPILE_ASSERT((llvm::is_base_of<Stmt, T>::value ||
+                            llvm::is_base_of<Decl, T>::value),
+      trying_to_bind_unsupported_node_type__only_decl_and_stmt_supported);
+    return Matcher<T>(new IdMatcher<T>(ID, *this));
+  }
+};
+
 /// \brief Matches nodes of type T that have child nodes of type ChildT for
 /// which a specified child matcher matches.
 ///
@@ -727,12 +735,16 @@
 
 /// \brief Creates a Matcher<T> that matches if
 /// T is dyn_cast'able into InnerT and all inner matchers match.
+///
+/// Returns BindableMatcher, as matchers that use dyn_cast have
+/// the same object both to match on and to run submatchers on,
+/// so there is no ambiguity with what gets bound.
 template<typename T, typename InnerT>
-Matcher<T> makeDynCastAllOfComposite(
+BindableMatcher<T> makeDynCastAllOfComposite(
     ArrayRef<const Matcher<InnerT> *> InnerMatchers) {
   if (InnerMatchers.empty()) {
-    return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(
-        makeMatcher(new TrueMatcher<InnerT>));
+    Matcher<InnerT> InnerMatcher = makeMatcher(new TrueMatcher<InnerT>);
+    return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
   }
   Matcher<InnerT> InnerMatcher = *InnerMatchers.back();
   for (int i = InnerMatchers.size() - 2; i >= 0; --i) {
@@ -740,7 +752,7 @@
         new AllOfMatcher<InnerT, Matcher<InnerT>, Matcher<InnerT> >(
             *InnerMatchers[i], InnerMatcher));
   }
-  return ArgumentAdaptingMatcher<DynCastMatcher, InnerT>(InnerMatcher);
+  return BindableMatcher<T>(new DynCastMatcher<T, InnerT>(InnerMatcher));
 }
 
 /// \brief Matches nodes of type T that have at least one descendant node of
@@ -876,7 +888,7 @@
 template <typename SourceT, typename TargetT>
 class VariadicDynCastAllOfMatcher
     : public llvm::VariadicFunction<
-        Matcher<SourceT>, Matcher<TargetT>,
+        BindableMatcher<SourceT>, Matcher<TargetT>,
         makeDynCastAllOfComposite<SourceT, TargetT> > {
 public:
   VariadicDynCastAllOfMatcher() {}

Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=160673&r1=160672&r2=160673&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Tue Jul 24 08:37:29 2012
@@ -283,7 +283,7 @@
 
   EXPECT_TRUE(matches(
       "class X {}; class Y : public X {};",
-      record(isDerivedFrom(id("test", record(hasName("X")))))));
+      record(isDerivedFrom(record(hasName("X")).bind("test")))));
 }
 
 TEST(AllOf, AllOverloadsWork) {
@@ -620,7 +620,7 @@
 };
 
 TEST(Matcher, BindMatchedNodes) {
-  DeclarationMatcher ClassX = has(id("x", record(hasName("X"))));
+  DeclarationMatcher ClassX = has(record(hasName("::X")).bind("x"));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class X {};",
       ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("x")));
@@ -629,13 +629,13 @@
       ClassX, new VerifyIdIsBoundToDecl<CXXRecordDecl>("other-id")));
 
   TypeMatcher TypeAHasClassB = hasDeclaration(
-      record(hasName("A"), has(id("b", record(hasName("B"))))));
+      record(hasName("A"), has(record(hasName("B")).bind("b"))));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { public: A *a; class B {}; };",
       TypeAHasClassB,
       new VerifyIdIsBoundToDecl<Decl>("b")));
 
-  StatementMatcher MethodX = id("x", call(callee(method(hasName("x")))));
+  StatementMatcher MethodX = call(callee(method(hasName("x")))).bind("x");
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { void x() { x(); } };",
       MethodX,
@@ -645,11 +645,11 @@
 TEST(Matcher, BindTheSameNameInAlternatives) {
   StatementMatcher matcher = anyOf(
       binaryOperator(hasOperatorName("+"),
-                     hasLHS(id("x", expression())),
+                     hasLHS(expression().bind("x")),
                      hasRHS(integerLiteral(equals(0)))),
       binaryOperator(hasOperatorName("+"),
                      hasLHS(integerLiteral(equals(0))),
-                     hasRHS(id("x", expression()))));
+                     hasRHS(expression().bind("x"))));
 
   EXPECT_TRUE(matchAndVerifyResultTrue(
       // The first branch of the matcher binds x to 0 but then fails.
@@ -707,7 +707,7 @@
   EXPECT_TRUE(matches("class Y { void x() { x(); } };", MethodX));
   EXPECT_TRUE(notMatches("class Y { void x() {} };", MethodX));
 
-  StatementMatcher MethodOnY = call(on(hasType(record(hasName("Y")))));
+  StatementMatcher MethodOnY = memberCall(on(hasType(record(hasName("Y")))));
 
   EXPECT_TRUE(
       matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
@@ -726,7 +726,7 @@
                  MethodOnY));
 
   StatementMatcher MethodOnYPointer =
-      call(on(hasType(pointsTo(record(hasName("Y"))))));
+      memberCall(on(hasType(pointsTo(record(hasName("Y"))))));
 
   EXPECT_TRUE(
       matches("class Y { public: void x(); }; void z() { Y *y; y->x(); }",
@@ -748,7 +748,7 @@
 TEST(HasType, MatchesAsString) {
   EXPECT_TRUE(
       matches("class Y { public: void x(); }; void z() {Y* y; y->x(); }",
-              call(on(hasType(asString("class Y *"))))));
+              memberCall(on(hasType(asString("class Y *"))))));
   EXPECT_TRUE(matches("class X { void x(int x) {} };",
       method(hasParameter(0, hasType(asString("int"))))));
   EXPECT_TRUE(matches("namespace ns { struct A {}; }  struct B { ns::A a; };",
@@ -798,7 +798,8 @@
 }
 
 TEST(Matcher, ThisPointerType) {
-  StatementMatcher MethodOnY = call(thisPointerType(record(hasName("Y"))));
+  StatementMatcher MethodOnY =
+    memberCall(thisPointerType(record(hasName("Y"))));
 
   EXPECT_TRUE(
       matches("class Y { public: void x(); }; void z() { Y y; y.x(); }",
@@ -830,7 +831,7 @@
   StatementMatcher Reference =
       declarationReference(to(
           variable(hasInitializer(
-              call(thisPointerType(record(hasName("Y"))))))));
+              memberCall(thisPointerType(record(hasName("Y"))))))));
 
   EXPECT_TRUE(matches(
       "class Y {"
@@ -854,7 +855,7 @@
 
 TEST(Matcher, CalledVariable) {
   StatementMatcher CallOnVariableY = expression(
-      call(on(declarationReference(to(variable(hasName("y")))))));
+      memberCall(on(declarationReference(to(variable(hasName("y")))))));
 
   EXPECT_TRUE(matches(
       "class Y { public: void x() { Y y; y.x(); } };", CallOnVariableY));
@@ -1739,7 +1740,7 @@
 }
 
 TEST(AstMatcherPMacro, Works) {
-  DeclarationMatcher HasClassB = just(has(id("b", record(hasName("B")))));
+  DeclarationMatcher HasClassB = just(has(record(hasName("B")).bind("b")));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
       HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
@@ -1764,7 +1765,7 @@
 }
 
 TEST(AstPolymorphicMatcherPMacro, Works) {
-  DeclarationMatcher HasClassB = polymorphicHas(id("b", record(hasName("B"))));
+  DeclarationMatcher HasClassB = polymorphicHas(record(hasName("B")).bind("b"));
 
   EXPECT_TRUE(matchAndVerifyResultTrue("class A { class B {}; };",
       HasClassB, new VerifyIdIsBoundToDecl<Decl>("b")));
@@ -2133,26 +2134,26 @@
 
 TEST(ForEach, BindsOneNode) {
   EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; };",
-      record(hasName("C"), forEach(id("x", field(hasName("x"))))),
+      record(hasName("C"), forEach(field(hasName("x")).bind("x"))),
       new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
 }
 
 TEST(ForEach, BindsMultipleNodes) {
   EXPECT_TRUE(matchAndVerifyResultTrue("class C { int x; int y; int z; };",
-      record(hasName("C"), forEach(id("f", field()))),
+      record(hasName("C"), forEach(field().bind("f"))),
       new VerifyIdIsBoundToDecl<FieldDecl>("f", 3)));
 }
 
 TEST(ForEach, BindsRecursiveCombinations) {
   EXPECT_TRUE(matchAndVerifyResultTrue(
       "class C { class D { int x; int y; }; class E { int y; int z; }; };",
-      record(hasName("C"), forEach(record(forEach(id("f", field()))))),
+      record(hasName("C"), forEach(record(forEach(field().bind("f"))))),
       new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
 }
 
 TEST(ForEachDescendant, BindsOneNode) {
   EXPECT_TRUE(matchAndVerifyResultTrue("class C { class D { int x; }; };",
-      record(hasName("C"), forEachDescendant(id("x", field(hasName("x"))))),
+      record(hasName("C"), forEachDescendant(field(hasName("x")).bind("x"))),
       new VerifyIdIsBoundToDecl<FieldDecl>("x", 1)));
 }
 
@@ -2160,7 +2161,7 @@
   EXPECT_TRUE(matchAndVerifyResultTrue(
       "class C { class D { int x; int y; }; "
       "          class E { class F { int y; int z; }; }; };",
-      record(hasName("C"), forEachDescendant(id("f", field()))),
+      record(hasName("C"), forEachDescendant(field().bind("f"))),
       new VerifyIdIsBoundToDecl<FieldDecl>("f", 4)));
 }
 
@@ -2169,7 +2170,7 @@
       "class C { class D { "
       "          class E { class F { class G { int y; int z; }; }; }; }; };",
       record(hasName("C"), forEachDescendant(record(
-          forEachDescendant(id("f", field()))))),
+          forEachDescendant(field().bind("f"))))),
       new VerifyIdIsBoundToDecl<FieldDecl>("f", 8)));
 }
 





More information about the cfe-commits mailing list