r186836 - Add support for overloaded matchers. ie different matcher function signatures with the same name.

Samuel Benzaquen sbenza at google.com
Mon Jul 22 09:13:58 PDT 2013


Author: sbenza
Date: Mon Jul 22 11:13:57 2013
New Revision: 186836

URL: http://llvm.org/viewvc/llvm-project?rev=186836&view=rev
Log:
Add support for overloaded matchers. ie different matcher function signatures with the same name.

Summary:
Add support for overloaded matchers.
This composes with other features, like supporting polymorphic matchers.

Reviewers: klimek

CC: cfe-commits, revane

Differential Revision: http://llvm-reviews.chandlerc.com/D1188

Modified:
    cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
    cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
    cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
    cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
    cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.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=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Mon Jul 22 11:13:57 2013
@@ -1536,24 +1536,25 @@ AST_MATCHER_P(CXXRecordDecl, isDerivedFr
 }
 
 /// \brief Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isDerivedFrom(StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, StringRef, BaseName, 1) {
   assert(!BaseName.empty());
-  return isDerivedFrom(hasName(BaseName));
+  return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
 }
 
 /// \brief Similar to \c isDerivedFrom(), but also matches classes that directly
 /// match \c Base.
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
-    internal::Matcher<NamedDecl> Base) {
-  return anyOf(Base, isDerivedFrom(Base));
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
+                       internal::Matcher<NamedDecl>, Base, 0) {
+  return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base)))
+      .matches(Node, Finder, Builder);
 }
 
 /// \brief Overloaded method as shortcut for
 /// \c isSameOrDerivedFrom(hasName(...)).
-inline internal::Matcher<CXXRecordDecl> isSameOrDerivedFrom(
-    StringRef BaseName) {
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, StringRef, BaseName,
+                       1) {
   assert(!BaseName.empty());
-  return isSameOrDerivedFrom(hasName(BaseName));
+  return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
 }
 
 /// \brief Matches the first method of a class or struct that satisfies \c
@@ -1822,9 +1823,9 @@ AST_MATCHER_P(CallExpr, callee, internal
 ///   class Y { public: void x(); };
 ///   void z() { Y y; y.x();
 /// \endcode
-inline internal::Matcher<CallExpr> callee(
-    const internal::Matcher<Decl> &InnerMatcher) {
-  return callExpr(hasDeclaration(InnerMatcher));
+AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
+                       1) {
+  return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder);
 }
 
 /// \brief Matches if the expression's or declaration's type matches a type
@@ -1836,9 +1837,9 @@ inline internal::Matcher<CallExpr> calle
 ///  class X {};
 ///  void y(X &x) { x; X z; }
 /// \endcode
-AST_POLYMORPHIC_MATCHER_P(hasType,
-                          AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
-                          internal::Matcher<QualType>, InnerMatcher) {
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+    hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+    internal::Matcher<QualType>, InnerMatcher, 0) {
   return InnerMatcher.matches(Node.getType(), Finder, Builder);
 }
 
@@ -1859,11 +1860,11 @@ AST_POLYMORPHIC_MATCHER_P(hasType,
 /// \endcode
 ///
 /// Usable as: Matcher<Expr>, Matcher<ValueDecl>
-inline internal::PolymorphicMatcherWithParam1<
-    internal::matcher_hasType0Matcher, internal::Matcher<QualType>,
-    AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl)>
-hasType(const internal::Matcher<Decl> &InnerMatcher) {
-  return hasType(qualType(hasDeclaration(InnerMatcher)));
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+    hasType, AST_POLYMORPHIC_SUPPORTED_TYPES_2(Expr, ValueDecl),
+    internal::Matcher<Decl>, InnerMatcher, 1) {
+  return qualType(hasDeclaration(InnerMatcher))
+      .matches(Node.getType(), Finder, Builder);
 }
 
 /// \brief Matches if the type location of the declarator decl's type matches
@@ -1912,9 +1913,10 @@ AST_MATCHER_P(
 }
 
 /// \brief Overloaded to match the pointee type's declaration.
-inline internal::Matcher<QualType> pointsTo(
-    const internal::Matcher<Decl> &InnerMatcher) {
-  return pointsTo(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, pointsTo, internal::Matcher<Decl>,
+                       InnerMatcher, 1) {
+  return pointsTo(qualType(hasDeclaration(InnerMatcher)))
+      .matches(Node, Finder, Builder);
 }
 
 /// \brief Matches if the matched type is a reference type and the referenced
@@ -1955,9 +1957,10 @@ AST_MATCHER_P(QualType, hasCanonicalType
 }
 
 /// \brief Overloaded to match the referenced type's declaration.
-inline internal::Matcher<QualType> references(
-    const internal::Matcher<Decl> &InnerMatcher) {
-  return references(qualType(hasDeclaration(InnerMatcher)));
+AST_MATCHER_P_OVERLOAD(QualType, references, internal::Matcher<Decl>,
+                       InnerMatcher, 1) {
+  return references(qualType(hasDeclaration(InnerMatcher)))
+      .matches(Node, Finder, Builder);
 }
 
 AST_MATCHER_P(CXXMemberCallExpr, onImplicitObjectArgument,
@@ -1969,17 +1972,19 @@ AST_MATCHER_P(CXXMemberCallExpr, onImpli
 
 /// \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<CXXMemberCallExpr> thisPointerType(
-    const internal::Matcher<QualType> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+                       internal::Matcher<QualType>, InnerMatcher, 0) {
   return onImplicitObjectArgument(
-      anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+      anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+      .matches(Node, Finder, Builder);
 }
 
 /// \brief Overloaded to match the type's declaration.
-inline internal::Matcher<CXXMemberCallExpr> thisPointerType(
-    const internal::Matcher<Decl> &InnerMatcher) {
+AST_MATCHER_P_OVERLOAD(CXXMemberCallExpr, thisPointerType,
+                       internal::Matcher<Decl>, InnerMatcher, 1) {
   return onImplicitObjectArgument(
-      anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))));
+      anyOf(hasType(InnerMatcher), hasType(pointsTo(InnerMatcher))))
+      .matches(Node, Finder, Builder);
 }
 
 /// \brief Matches a DeclRefExpr that refers to a declaration that matches the

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersMacros.h Mon Jul 22 11:13:57 2013
@@ -49,23 +49,19 @@
 ///
 /// The code should return true if 'Node' matches.
 #define AST_MATCHER(Type, DefineMatcher)                                       \
-  AST_MATCHER_OVERLOAD(Type, DefineMatcher, 0)
-
-#define AST_MATCHER_OVERLOAD(Type, DefineMatcher, OverloadId)                  \
   namespace internal {                                                         \
-  class matcher_##DefineMatcher##OverloadId##Matcher                           \
-      : public MatcherInterface<Type> {                                        \
+  class matcher_##DefineMatcher##Matcher : public MatcherInterface<Type> {     \
   public:                                                                      \
-    explicit matcher_##DefineMatcher##OverloadId##Matcher() {}                 \
+    explicit matcher_##DefineMatcher##Matcher() {}                             \
     virtual bool matches(const Type &Node, ASTMatchFinder *Finder,             \
                          BoundNodesTreeBuilder *Builder) const;                \
   };                                                                           \
   }                                                                            \
   inline internal::Matcher<Type> DefineMatcher() {                             \
     return internal::makeMatcher(                                              \
-        new internal::matcher_##DefineMatcher##OverloadId##Matcher());         \
+        new internal::matcher_##DefineMatcher##Matcher());                     \
   }                                                                            \
-  inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
+  inline bool internal::matcher_##DefineMatcher##Matcher::matches(             \
       const Type &Node, ASTMatchFinder *Finder,                                \
       BoundNodesTreeBuilder *Builder) const
 
@@ -93,10 +89,10 @@
   public:                                                                      \
     explicit matcher_##DefineMatcher##OverloadId##Matcher(                     \
         const ParamType &A##Param)                                             \
-        : Param(A##Param) {                                                    \
-    }                                                                          \
+        : Param(A##Param) {}                                                   \
     virtual bool matches(const Type &Node, ASTMatchFinder *Finder,             \
                          BoundNodesTreeBuilder *Builder) const;                \
+                                                                               \
   private:                                                                     \
     const ParamType Param;                                                     \
   };                                                                           \
@@ -105,6 +101,8 @@
     return internal::makeMatcher(                                              \
         new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param));    \
   }                                                                            \
+  typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)(          \
+      const ParamType &Param);                                                 \
   inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
       const Type &Node, ASTMatchFinder *Finder,                                \
       BoundNodesTreeBuilder *Builder) const
@@ -136,21 +134,23 @@
   public:                                                                      \
     matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1,  \
                                                  const ParamType2 &A##Param2)  \
-        : Param1(A##Param1), Param2(A##Param2) {                               \
-    }                                                                          \
+        : Param1(A##Param1), Param2(A##Param2) {}                              \
     virtual bool matches(const Type &Node, ASTMatchFinder *Finder,             \
                          BoundNodesTreeBuilder *Builder) const;                \
+                                                                               \
   private:                                                                     \
     const ParamType1 Param1;                                                   \
     const ParamType2 Param2;                                                   \
   };                                                                           \
   }                                                                            \
-  inline internal::Matcher<Type>                                               \
-  DefineMatcher(const ParamType1 &Param1, const ParamType2 &Param2) {          \
+  inline internal::Matcher<Type> DefineMatcher(const ParamType1 &Param1,       \
+                                               const ParamType2 &Param2) {     \
     return internal::makeMatcher(                                              \
         new internal::matcher_##DefineMatcher##OverloadId##Matcher(Param1,     \
                                                                    Param2));   \
   }                                                                            \
+  typedef internal::Matcher<Type>(&DefineMatcher##_Type##OverloadId)(          \
+      const ParamType1 &Param1, const ParamType2 &Param2);                     \
   inline bool internal::matcher_##DefineMatcher##OverloadId##Matcher::matches( \
       const Type &Node, ASTMatchFinder *Finder,                                \
       BoundNodesTreeBuilder *Builder) const
@@ -180,30 +180,24 @@
 /// The variables are the same as for AST_MATCHER, but NodeType will be deduced
 /// from the calling context.
 #define AST_POLYMORPHIC_MATCHER(DefineMatcher, ReturnTypesF)                   \
-  AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, ReturnTypesF, 0)
-
-#define AST_POLYMORPHIC_MATCHER_OVERLOAD(DefineMatcher, ReturnTypesF,          \
-                                         OverloadId)                           \
   namespace internal {                                                         \
   template <typename NodeType>                                                 \
-  class matcher_##DefineMatcher##OverloadId##Matcher                           \
-      : public MatcherInterface<NodeType> {                                    \
+  class matcher_##DefineMatcher##Matcher : public MatcherInterface<NodeType> { \
   public:                                                                      \
     virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                          BoundNodesTreeBuilder *Builder) const;                \
   };                                                                           \
   }                                                                            \
   inline internal::PolymorphicMatcherWithParam0<                               \
-      internal::matcher_##DefineMatcher##OverloadId##Matcher, ReturnTypesF>    \
+      internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>                \
   DefineMatcher() {                                                            \
     return internal::PolymorphicMatcherWithParam0<                             \
-        internal::matcher_##DefineMatcher##OverloadId##Matcher,                \
-        ReturnTypesF>();                                                       \
+        internal::matcher_##DefineMatcher##Matcher, ReturnTypesF>();           \
   }                                                                            \
   template <typename NodeType>                                                 \
-  bool internal::matcher_##DefineMatcher##OverloadId##Matcher<                 \
-      NodeType>::matches(const NodeType &Node, ASTMatchFinder *Finder,         \
-                         BoundNodesTreeBuilder *Builder) const
+  bool internal::matcher_##DefineMatcher##Matcher<NodeType>::matches(          \
+      const NodeType &Node, ASTMatchFinder *Finder,                            \
+      BoundNodesTreeBuilder *Builder) const
 
 /// \brief AST_POLYMORPHIC_MATCHER_P(DefineMatcher, ParamType, Param) { ... }
 /// defines a single-parameter function named DefineMatcher() that is
@@ -228,21 +222,25 @@
   public:                                                                      \
     explicit matcher_##DefineMatcher##OverloadId##Matcher(                     \
         const ParamType &A##Param)                                             \
-        : Param(A##Param) {                                                    \
-    }                                                                          \
+        : Param(A##Param) {}                                                   \
     virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                          BoundNodesTreeBuilder *Builder) const;                \
+                                                                               \
   private:                                                                     \
     const ParamType Param;                                                     \
   };                                                                           \
   }                                                                            \
   inline internal::PolymorphicMatcherWithParam1<                               \
       internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType,       \
-      ReturnTypesF> DefineMatcher(const ParamType & Param) {                   \
+      ReturnTypesF> DefineMatcher(const ParamType &Param) {                    \
     return internal::PolymorphicMatcherWithParam1<                             \
         internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType,     \
         ReturnTypesF>(Param);                                                  \
   }                                                                            \
+  typedef internal::PolymorphicMatcherWithParam1<                              \
+      internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType,       \
+      ReturnTypesF>(&DefineMatcher##_Type##OverloadId)(                        \
+      const ParamType &Param);                                                 \
   template <typename NodeType, typename ParamT>                                \
   bool internal::matcher_##DefineMatcher##OverloadId##Matcher<                 \
       NodeType, ParamT>::matches(const NodeType &Node, ASTMatchFinder *Finder, \
@@ -271,10 +269,10 @@
   public:                                                                      \
     matcher_##DefineMatcher##OverloadId##Matcher(const ParamType1 &A##Param1,  \
                                                  const ParamType2 &A##Param2)  \
-        : Param1(A##Param1), Param2(A##Param2) {                               \
-    }                                                                          \
+        : Param1(A##Param1), Param2(A##Param2) {}                              \
     virtual bool matches(const NodeType &Node, ASTMatchFinder *Finder,         \
                          BoundNodesTreeBuilder *Builder) const;                \
+                                                                               \
   private:                                                                     \
     const ParamType1 Param1;                                                   \
     const ParamType2 Param2;                                                   \
@@ -282,12 +280,16 @@
   }                                                                            \
   inline internal::PolymorphicMatcherWithParam2<                               \
       internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1,      \
-      ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 & Param1,       \
-                                              const ParamType2 & Param2) {     \
+      ParamType2, ReturnTypesF> DefineMatcher(const ParamType1 &Param1,        \
+                                              const ParamType2 &Param2) {      \
     return internal::PolymorphicMatcherWithParam2<                             \
         internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1,    \
         ParamType2, ReturnTypesF>(Param1, Param2);                             \
   }                                                                            \
+  typedef internal::PolymorphicMatcherWithParam2<                              \
+      internal::matcher_##DefineMatcher##OverloadId##Matcher, ParamType1,      \
+      ParamType2, ReturnTypesF>(&DefineMatcher##_Type##OverloadId)(            \
+      const ParamType1 &Param1, const ParamType2 &Param2);                     \
   template <typename NodeType, typename ParamT1, typename ParamT2>             \
   bool internal::matcher_##DefineMatcher##OverloadId##Matcher<                 \
       NodeType, ParamT1, ParamT2>::matches(                                    \

Modified: cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/Dynamic/Diagnostics.h Mon Jul 22 11:13:57 2013
@@ -65,6 +65,7 @@ public:
     ET_RegistryWrongArgCount = 2,
     ET_RegistryWrongArgType = 3,
     ET_RegistryNotBindable = 4,
+    ET_RegistryAmbiguousOverload = 5,
 
     ET_ParserStringError = 100,
     ET_ParserNoOpenParen = 101,
@@ -114,6 +115,23 @@ public:
     Diagnostics *const Error;
   };
 
+  /// \brief Context for overloaded matcher construction.
+  ///
+  /// This context will take care of merging all errors that happen within it
+  /// as "candidate" overloads for the same matcher.
+  struct OverloadContext {
+  public:
+   OverloadContext(Diagnostics* Error);
+   ~OverloadContext();
+
+   /// \brief Revert all errors that happened within this context.
+   void revertErrors();
+
+  private:
+    Diagnostics *const Error;
+    unsigned BeginIndex;
+  };
+
   /// \brief Add an error to the diagnostics.
   ///
   /// All the context information will be kept on the error message.
@@ -131,9 +149,12 @@ public:
   /// \brief Information stored for each error found.
   struct ErrorContent {
     std::vector<ContextFrame> ContextStack;
-    SourceRange Range;
-    ErrorType Type;
-    std::vector<std::string> Args;
+    struct Message {
+      SourceRange Range;
+      ErrorType Type;
+      std::vector<std::string> Args;
+    };
+    std::vector<Message> Messages;
   };
   ArrayRef<ErrorContent> errors() const { return Errors; }
 

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Diagnostics.cpp Mon Jul 22 11:13:57 2013
@@ -40,6 +40,25 @@ Diagnostics::Context::Context(MatcherArg
 
 Diagnostics::Context::~Context() { Error->ContextStack.pop_back(); }
 
+Diagnostics::OverloadContext::OverloadContext(Diagnostics *Error)
+    : Error(Error), BeginIndex(Error->Errors.size()) {}
+
+Diagnostics::OverloadContext::~OverloadContext() {
+  // Merge all errors that happened while in this context.
+  if (BeginIndex < Error->Errors.size()) {
+    Diagnostics::ErrorContent &Dest = Error->Errors[BeginIndex];
+    for (size_t i = BeginIndex + 1, e = Error->Errors.size(); i < e; ++i) {
+      Dest.Messages.push_back(Error->Errors[i].Messages[0]);
+    }
+    Error->Errors.resize(BeginIndex + 1);
+  }
+}
+
+void Diagnostics::OverloadContext::revertErrors() {
+  // Revert the errors.
+  Error->Errors.resize(BeginIndex);
+}
+
 Diagnostics::ArgStream &Diagnostics::ArgStream::operator<<(const Twine &Arg) {
   Out->push_back(Arg.str());
   return *this;
@@ -50,9 +69,10 @@ Diagnostics::ArgStream Diagnostics::addE
   Errors.push_back(ErrorContent());
   ErrorContent &Last = Errors.back();
   Last.ContextStack = ContextStack;
-  Last.Range = Range;
-  Last.Type = Error;
-  return ArgStream(&Last.Args);
+  Last.Messages.push_back(ErrorContent::Message());
+  Last.Messages.back().Range = Range;
+  Last.Messages.back().Type = Error;
+  return ArgStream(&Last.Messages.back().Args);
 }
 
 StringRef contextTypeToFormatString(Diagnostics::ContextType Type) {
@@ -75,6 +95,9 @@ StringRef errorTypeToFormatString(Diagno
     return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
   case Diagnostics::ET_RegistryNotBindable:
     return "Matcher does not support binding.";
+  case Diagnostics::ET_RegistryAmbiguousOverload:
+    // TODO: Add type info about the overload error.
+    return "Ambiguous matcher overload.";
 
   case Diagnostics::ET_ParserStringError:
     return "Error parsing string token: <$0>";
@@ -138,10 +161,25 @@ static void printContextFrameToStream(co
   formatErrorString(contextTypeToFormatString(Frame.Type), Frame.Args, OS);
 }
 
+static void
+printMessageToStream(const Diagnostics::ErrorContent::Message &Message,
+                     const Twine Prefix, llvm::raw_ostream &OS) {
+  maybeAddLineAndColumn(Message.Range, OS);
+  OS << Prefix;
+  formatErrorString(errorTypeToFormatString(Message.Type), Message.Args, OS);
+}
+
 static void printErrorContentToStream(const Diagnostics::ErrorContent &Content,
                                       llvm::raw_ostream &OS) {
-  maybeAddLineAndColumn(Content.Range, OS);
-  formatErrorString(errorTypeToFormatString(Content.Type), Content.Args, OS);
+  if (Content.Messages.size() == 1) {
+    printMessageToStream(Content.Messages[0], "", OS);
+  } else {
+    for (size_t i = 0, e = Content.Messages.size(); i != e; ++i) {
+      if (i != 0) OS << "\n";
+      printMessageToStream(Content.Messages[i],
+                           "Candidate " + Twine(i + 1) + ": ", OS);
+    }
+  }
 }
 
 void Diagnostics::printToStream(llvm::raw_ostream &OS) const {

Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Mon Jul 22 11:13:57 2013
@@ -48,10 +48,67 @@ void RegistryMaps::registerMatcher(Strin
   Constructors[MatcherName] = Callback;
 }
 
+/// \brief MatcherCreateCallback that wraps multiple "overloads" of the same
+///   matcher.
+///
+/// It will try every overload and generate appropriate errors for when none or
+/// more than one overloads match the arguments.
+class OverloadedMatcherCreateCallback : public MatcherCreateCallback {
+ public:
+   OverloadedMatcherCreateCallback(ArrayRef<MatcherCreateCallback *> Callbacks)
+       : Overloads(Callbacks) {}
+
+  virtual ~OverloadedMatcherCreateCallback() {
+    for (size_t i = 0, e = Overloads.size(); i != e; ++i)
+      delete Overloads[i];
+  }
+
+  virtual MatcherList run(const SourceRange &NameRange,
+                          ArrayRef<ParserValue> Args,
+                          Diagnostics *Error) const {
+    std::vector<MatcherList> Constructed;
+    Diagnostics::OverloadContext Ctx(Error);
+    for (size_t i = 0, e = Overloads.size(); i != e; ++i) {
+      MatcherList SubMatcher = Overloads[i]->run(NameRange, Args, Error);
+      if (!SubMatcher.empty()) {
+        Constructed.push_back(SubMatcher);
+      }
+    }
+
+    if (Constructed.empty()) return MatcherList();  // No overload matched.
+    // We ignore the errors if any matcher succeeded.
+    Ctx.revertErrors();
+    if (Constructed.size() > 1) {
+      // More than one constructed. It is ambiguous.
+      Error->addError(NameRange, Error->ET_RegistryAmbiguousOverload);
+      return MatcherList();
+    }
+    return Constructed[0];
+  }
+
+ private:
+  std::vector<MatcherCreateCallback*> Overloads;
+};
+
 #define REGISTER_MATCHER(name)                                                 \
   registerMatcher(#name, internal::makeMatcherAutoMarshall(                    \
                              ::clang::ast_matchers::name, #name));
 
+#define SPECIFIC_MATCHER_OVERLOAD(name, Id)                                    \
+  static_cast< ::clang::ast_matchers::name##_Type##Id>(                        \
+      ::clang::ast_matchers::name)
+
+#define REGISTER_OVERLOADED_2(name)                                            \
+  do {                                                                         \
+    MatcherCreateCallback *Callbacks[] = {                                     \
+      internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0),    \
+                                        #name),                                \
+      internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1),    \
+                                        #name)                                 \
+    };                                                                         \
+    registerMatcher(#name, new OverloadedMatcherCreateCallback(Callbacks));    \
+  } 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.
@@ -59,16 +116,6 @@ RegistryMaps::RegistryMaps() {
   // Need Variant/Parser fixes:
   // ofKind
   //
-  // Function overloaded by args:
-  // hasType
-  // callee
-  // hasPrefix
-  // isDerivedFrom
-  // isSameOrDerivedFrom
-  // pointsTo
-  // references
-  // thisPointerType
-  //
   // Polymorphic + argument overload:
   // unless
   // eachOf
@@ -90,6 +137,15 @@ RegistryMaps::RegistryMaps() {
   // equalsNode
   // hasDeclaration
 
+  REGISTER_OVERLOADED_2(callee);
+  REGISTER_OVERLOADED_2(hasPrefix);
+  REGISTER_OVERLOADED_2(hasType);
+  REGISTER_OVERLOADED_2(isDerivedFrom);
+  REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
+  REGISTER_OVERLOADED_2(pointsTo);
+  REGISTER_OVERLOADED_2(references);
+  REGISTER_OVERLOADED_2(thisPointerType);
+
   REGISTER_MATCHER(accessSpecDecl);
   REGISTER_MATCHER(alignOfExpr);
   REGISTER_MATCHER(anything);

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/ParserTest.cpp Mon Jul 22 11:13:57 2013
@@ -256,6 +256,15 @@ TEST(ParserTest, Errors) {
             ParseMatcherWithError("hasBody(stmt())"));
 }
 
+TEST(ParserTest, OverloadErrors) {
+  EXPECT_EQ("1:1: Error building matcher callee.\n"
+            "1:8: Candidate 1: Incorrect type for arg 1. "
+            "(Expected = Matcher<Stmt>) != (Actual = String)\n"
+            "1:8: Candidate 2: Incorrect type for arg 1. "
+            "(Expected = Matcher<Decl>) != (Actual = String)",
+            ParseWithError("callee(\"A\")"));
+}
+
 }  // end anonymous namespace
 }  // end namespace dynamic
 }  // end namespace ast_matchers

Modified: cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp?rev=186836&r1=186835&r2=186836&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/Dynamic/RegistryTest.cpp Mon Jul 22 11:13:57 2013
@@ -124,6 +124,30 @@ TEST_F(RegistryTest, ConstructWithMatche
   EXPECT_FALSE(matches("void f(int x, int a);", HasParameter));
 }
 
+TEST_F(RegistryTest, OverloadedMatchers) {
+  Matcher<Stmt> CallExpr0 = constructMatcher(
+      "callExpr",
+      constructMatcher("callee", constructMatcher("memberExpr",
+                                                  constructMatcher("isArrow"))))
+      .getTypedMatcher<Stmt>();
+
+  Matcher<Stmt> CallExpr1 = constructMatcher(
+      "callExpr",
+      constructMatcher(
+          "callee",
+          constructMatcher("methodDecl",
+                           constructMatcher("hasName", std::string("x")))))
+      .getTypedMatcher<Stmt>();
+
+  std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
+  EXPECT_FALSE(matches(Code, CallExpr0));
+  EXPECT_TRUE(matches(Code, CallExpr1));
+
+  Code = "class Z { public: void z() { this->z(); } };";
+  EXPECT_TRUE(matches(Code, CallExpr0));
+  EXPECT_FALSE(matches(Code, CallExpr1));
+}
+
 TEST_F(RegistryTest, PolymorphicMatchers) {
   const MatcherList IsDefinition = constructMatcher("isDefinition");
   Matcher<Decl> Var =





More information about the cfe-commits mailing list