Hi klimek,

http://llvm-reviews.chandlerc.com/D815

Files:
  include/clang/AST/ASTTypeTraits.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  include/clang/ASTMatchers/Dynamic/VariantValue.h
  lib/AST/ASTTypeTraits.cpp
  lib/AST/CMakeLists.txt
  lib/ASTMatchers/ASTMatchFinder.cpp
  lib/ASTMatchers/Dynamic/Diagnostics.cpp
  lib/ASTMatchers/Dynamic/Marshallers.h
  lib/ASTMatchers/Dynamic/VariantValue.cpp
  unittests/AST/ASTTypeTraitsTest.cpp
  unittests/AST/CMakeLists.txt
  unittests/ASTMatchers/ASTMatchersTest.cpp
  unittests/ASTMatchers/Dynamic/ParserTest.cpp
  unittests/ASTMatchers/Dynamic/RegistryTest.cpp
  unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
Index: include/clang/AST/ASTTypeTraits.h
===================================================================
--- include/clang/AST/ASTTypeTraits.h
+++ include/clang/AST/ASTTypeTraits.h
@@ -7,8 +7,9 @@
 //
 //===----------------------------------------------------------------------===//
 //
-//  Provides a dynamically typed node container that can be used to store
-//  an AST base node at runtime in the same storage in a type safe way.
+//  Provides a dynamic type identifier and a dynamically typed node container
+//  that can be used to store an AST base node at runtime in the same storage in
+//  a type safe way.
 //
 //===----------------------------------------------------------------------===//
 
@@ -18,11 +19,126 @@
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/TypeLoc.h"
+#include "clang/Basic/LLVM.h"
 #include "llvm/Support/AlignOf.h"
 
 namespace clang {
+
+/// \brief Forward declare the types to be used below.
+#define DECL(DERIVED, BASE) class DERIVED##Decl;
+#include "clang/AST/DeclNodes.inc"
+#define STMT(DERIVED, BASE) class DERIVED;
+#include "clang/AST/StmtNodes.inc"
+#define TYPE(DERIVED, BASE) class DERIVED##Type;
+#include "clang/AST/TypeNodes.def"
+
 namespace ast_type_traits {
 
+/// \brief Dynamic type identifier.
+///
+/// It can be constructed from any node type and allows for runtime type
+/// hierarchy checks.
+/// Use getFromNodeType<T>() to construct them. There are also shortcut
+/// functions defined for each base type.
+class DynNodeType {
+public:
+  /// \brief Empty identifier. It matches nothing.
+  DynNodeType() : TypeId(NTI_None) {}
+
+  /// \brief Some shortcuts for base types.
+  static DynNodeType decl() { return DynNodeType(NTI_Decl); }
+  static DynNodeType stmt() { return DynNodeType(NTI_Stmt); }
+  static DynNodeType nestedNameSpecifier() {
+    return DynNodeType(NTI_NestedNameSpecifier);
+  }
+  static DynNodeType nestedNameSpecifierLoc() {
+    return DynNodeType(NTI_NestedNameSpecifierLoc);
+  }
+  static DynNodeType qualType() { return DynNodeType(NTI_QualType); }
+  static DynNodeType type() { return DynNodeType(NTI_Type); }
+  static DynNodeType typeLoc() { return DynNodeType(NTI_TypeLoc); }
+
+  /// \brief Construct an identifier for T.
+  template <class T>
+  static DynNodeType getFromNodeType() {
+    return DynNodeType(TypeToTypeId<T>::Id);
+  }
+
+  /// \brief Returns \c true if \c this and \c Other represent the same type.
+  bool isSame(DynNodeType Other);
+
+  /// \brief Returns \c true if \c this is a base type of (or same as) \c Other
+  bool isBaseOf(DynNodeType Other);
+
+  /// \brief A string representation of the type.
+  StringRef asStringRef() const;
+
+private:
+  /// \brief Type ids.
+  ///
+  /// Includes all possible base and derived types.
+  enum NodeTypeId {
+    NTI_None,
+    NTI_NestedNameSpecifier,
+    NTI_NestedNameSpecifierLoc,
+    NTI_QualType,
+    NTI_TypeLoc,
+    NTI_Decl,
+#define DECL(DERIVED, BASE) NTI_##DERIVED##Decl,
+#include "clang/AST/DeclNodes.inc"
+    NTI_Stmt,
+#define STMT(DERIVED, BASE) NTI_##DERIVED,
+#include "clang/AST/StmtNodes.inc"
+    NTI_Type,
+#define TYPE(DERIVED, BASE) NTI_##DERIVED##Type,
+#include "clang/AST/TypeNodes.def"
+    NTI_NumberOfTypes
+  };
+
+  /// \brief Use getFromNodeType<T>() to construct the type.
+  DynNodeType(NodeTypeId TypeId) : TypeId(TypeId) {}
+
+  /// \brief Returns \c true if \c Base is a base type of (or same as) \c
+  ///   Derived
+  static bool isBaseOf(NodeTypeId Base, NodeTypeId Derived);
+
+  /// \brief Helper meta-function to convert a type T to its enum value.
+  ///
+  /// This struct is specialized below for all known types.
+  template <class T> struct TypeToTypeId {
+    static const NodeTypeId Id = NTI_None;
+  };
+
+  /// \brief Per type info.
+  struct TypeInfo {
+    /// \brief The id of the parent type, or None if it has no parent.
+    NodeTypeId ParentId;
+    /// \brief Name of the type.
+    const char *Name;
+  };
+  static const TypeInfo AllTypeInfo[NTI_NumberOfTypes];
+
+  NodeTypeId TypeId;
+};
+
+#define TYPE_TO_TYPE_ID(Class)                                                 \
+  template <> struct DynNodeType::TypeToTypeId<Class> {                        \
+    static const NodeTypeId Id = NTI_##Class;                                  \
+  };
+TYPE_TO_TYPE_ID(NestedNameSpecifier)
+TYPE_TO_TYPE_ID(NestedNameSpecifierLoc)
+TYPE_TO_TYPE_ID(QualType)
+TYPE_TO_TYPE_ID(TypeLoc)
+TYPE_TO_TYPE_ID(Decl)
+TYPE_TO_TYPE_ID(Stmt)
+TYPE_TO_TYPE_ID(Type)
+#define DECL(DERIVED, BASE) TYPE_TO_TYPE_ID(DERIVED##Decl)
+#include "clang/AST/DeclNodes.inc"
+#define STMT(DERIVED, BASE) TYPE_TO_TYPE_ID(DERIVED)
+#include "clang/AST/StmtNodes.inc"
+#define TYPE(DERIVED, BASE) TYPE_TO_TYPE_ID(DERIVED##Type)
+#include "clang/AST/TypeNodes.def"
+
 /// \brief A dynamically typed AST node container.
 ///
 /// Stores an AST node in a type safe way. This allows writing code that
@@ -57,7 +173,7 @@
   /// use the pointer outside the scope of the DynTypedNode.
   template <typename T>
   const T *get() const {
-    return BaseConverter<T>::get(Tag, Storage.buffer);
+    return BaseConverter<T>::get(NodeType, Storage.buffer);
   }
 
   /// \brief Returns a pointer that identifies the stored AST node.
@@ -71,120 +187,112 @@
   /// \brief Takes care of converting from and to \c T.
   template <typename T, typename EnablerT = void> struct BaseConverter;
 
-  /// \brief Supported base node types.
-  enum NodeTypeTag {
-    NT_Decl,
-    NT_Stmt,
-    NT_NestedNameSpecifier,
-    NT_NestedNameSpecifierLoc,
-    NT_QualType,
-    NT_Type,
-    NT_TypeLoc
-  } Tag;
+  DynNodeType NodeType;
 
   /// \brief Stores the data of the node.
   ///
   /// Note that we can store \c Decls and \c Stmts by pointer as they are
   /// guaranteed to be unique pointers pointing to dedicated storage in the
   /// AST. \c QualTypes on the other hand do not have storage or unique
   /// pointers and thus need to be stored by value.
-  llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
-                              NestedNameSpecifierLoc, QualType, Type,
+  llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier *,
+                              NestedNameSpecifierLoc *, QualType, Type *,
                               TypeLoc> Storage;
 };
 
 // FIXME: Pull out abstraction for the following.
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_Decl)
+  static const T *get(DynNodeType NodeType, const char Storage[]) {
+    if (DynNodeType::decl().isBaseOf(NodeType))
       return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
     return NULL;
   }
   static DynTypedNode create(const Decl &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_Decl;
+    Result.NodeType = DynNodeType::getFromNodeType<T>();
     new (Result.Storage.buffer) const Decl*(&Node);
     return Result;
   }
 };
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_Stmt)
+  static const T *get(DynNodeType NodeType, const char Storage[]) {
+    if (DynNodeType::stmt().isBaseOf(NodeType))
       return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
     return NULL;
   }
   static DynTypedNode create(const Stmt &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_Stmt;
+    Result.NodeType = DynNodeType::getFromNodeType<T>();
     new (Result.Storage.buffer) const Stmt*(&Node);
     return Result;
   }
 };
 template<typename T> struct DynTypedNode::BaseConverter<T,
     typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_Type)
+  static const T *get(DynNodeType NodeType, const char Storage[]) {
+    if (DynNodeType::type().isBaseOf(NodeType))
       return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
     return NULL;
   }
   static DynTypedNode create(const Type &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_Type;
+    Result.NodeType = DynNodeType::getFromNodeType<T>();
     new (Result.Storage.buffer) const Type*(&Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {
-  static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_NestedNameSpecifier)
+  static const NestedNameSpecifier *get(DynNodeType NodeType,
+                                        const char Storage[]) {
+    if (DynNodeType::nestedNameSpecifier().isBaseOf(NodeType))
       return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const NestedNameSpecifier &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_NestedNameSpecifier;
+    Result.NodeType = DynNodeType::getFromNodeType<NestedNameSpecifier>();
     new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
-  static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
+  static const NestedNameSpecifierLoc *get(DynNodeType NodeType,
                                            const char Storage[]) {
-    if (Tag == NT_NestedNameSpecifierLoc)
+    if (DynNodeType::nestedNameSpecifierLoc().isBaseOf(NodeType))
       return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_NestedNameSpecifierLoc;
+    Result.NodeType = DynNodeType::getFromNodeType<NestedNameSpecifierLoc>();
     new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<QualType, void> {
-  static const QualType *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_QualType)
+  static const QualType *get(DynNodeType NodeType, const char Storage[]) {
+    if (DynNodeType::qualType().isBaseOf(NodeType))
       return reinterpret_cast<const QualType*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const QualType &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_QualType;
+    Result.NodeType = DynNodeType::getFromNodeType<QualType>();
     new (Result.Storage.buffer) QualType(Node);
     return Result;
   }
 };
 template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {
-  static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {
-    if (Tag == NT_TypeLoc)
+  static const TypeLoc *get(DynNodeType NodeType, const char Storage[]) {
+    if (DynNodeType::typeLoc().isBaseOf(NodeType))
       return reinterpret_cast<const TypeLoc*>(Storage);
     return NULL;
   }
   static DynTypedNode create(const TypeLoc &Node) {
     DynTypedNode Result;
-    Result.Tag = NT_TypeLoc;
+    Result.NodeType = DynNodeType::getFromNodeType<TypeLoc>();
     new (Result.Storage.buffer) TypeLoc(Node);
     return Result;
   }
@@ -194,15 +302,18 @@
 // AST node that is not supported, but prevents misuse - a user cannot create
 // a DynTypedNode from arbitrary types.
 template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {
-  static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }
+  static const T *get(DynNodeType NodeType, const char Storage[]) {
+    return NULL;
+  }
 };
 
 inline const void *DynTypedNode::getMemoizationData() const {
-  switch (Tag) {
-    case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);
-    case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);
-    default: return NULL;
-  };
+  if (DynNodeType::decl().isBaseOf(NodeType)) {
+    return BaseConverter<Decl>::get(NodeType, Storage.buffer);
+  } else if (DynNodeType::stmt().isBaseOf(NodeType)) {
+    return BaseConverter<Stmt>::get(NodeType, Storage.buffer);
+  }
+  return NULL;
 }
 
 } // end namespace ast_type_traits
Index: include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchersInternal.h
+++ include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -225,6 +225,8 @@
   }
 };
 
+template <typename T> class Matcher;
+
 /// \brief Base class for all matchers that works on a \c DynTypedNode.
 ///
 /// Matcher implementations will check whether the \c DynTypedNode is
@@ -244,6 +246,12 @@
 
   /// \brief Returns a unique ID for the matcher.
   virtual uint64_t getID() const = 0;
+
+  /// \brief Returns the type this matcher works on.
+  ///
+  /// \c matches() will always return false unless the node passed is of this
+  /// or a derived type.
+  virtual ast_type_traits::DynNodeType getSupportedType() const = 0;
 };
 
 /// \brief Wrapper of a MatcherInterface<T> *that allows copying.
@@ -281,6 +289,26 @@
             llvm::is_same<TypeT, Type>::value >::type* = 0)
       : Implementation(new TypeToQualType<TypeT>(Other)) {}
 
+  /// \brief Returns \c true if the pass DynTypedMatcher can be converted to \c
+  ///   Matcher<T>.
+  ///
+  /// This method verifies that the underlying matcher in \c Other can process
+  /// nodes of types T.
+  static bool canConstructFrom(const DynTypedMatcher &Other) {
+    return Other.getSupportedType()
+        .isBaseOf(ast_type_traits::DynNodeType::getFromNodeType<T>());
+  }
+
+  /// \brief Construct a Matcher<T> interface around the dynamic \c Other.
+  ///
+  /// This method asserts that canConstructFrom(Other) is \c true. Callers
+  /// should call canConstructFrom(Other) first to make sure that Other is
+  /// compatible with T.
+  static Matcher<T> constructFrom(const DynTypedMatcher &Other) {
+    assert(canConstructFrom(Other));
+    return Matcher<T>(new WrappedMatcher(Other));
+  }
+
   /// \brief Forwards the call to the underlying MatcherInterface<T> pointer.
   bool matches(const T &Node,
                ASTMatchFinder *Finder,
@@ -295,6 +323,11 @@
     return reinterpret_cast<uint64_t>(Implementation.getPtr());
   }
 
+  /// \brief Returns the type this matcher works on.
+  ast_type_traits::DynNodeType getSupportedType() const {
+    return ast_type_traits::DynNodeType::getFromNodeType<T>();
+  }
+
   /// \brief Returns whether the matcher matches on the given \c DynNode.
   virtual bool matches(const ast_type_traits::DynTypedNode DynNode,
                        ASTMatchFinder *Finder,
@@ -349,6 +382,23 @@
     const Matcher<Base> From;
   };
 
+  /// \brief Simple MatcherInterface<T> wrapper around a DynTypedMatcher.
+  class WrappedMatcher : public MatcherInterface<T> {
+  public:
+    explicit WrappedMatcher(const DynTypedMatcher &Matcher)
+        : Inner(Matcher.clone()) {}
+    virtual ~WrappedMatcher() {}
+
+    bool matches(const T &Node, ASTMatchFinder *Finder,
+                 BoundNodesTreeBuilder *Builder) const {
+      return Inner->matches(ast_type_traits::DynTypedNode::create(Node), Finder,
+                            Builder);
+    }
+
+  private:
+    const OwningPtr<DynTypedMatcher> Inner;
+  };
+
   IntrusiveRefCntPtr< MatcherInterface<T> > Implementation;
 };  // class Matcher
 
@@ -359,6 +409,31 @@
   return Matcher<T>(Implementation);
 }
 
+/// \brief Specialization of the conversion functions for QualType.
+///
+/// These specializations provide the Matcher<Type>->Matcher<QualType>
+/// conversion that the static API does.
+template <>
+inline bool
+Matcher<QualType>::canConstructFrom(const DynTypedMatcher &Other) {
+  ast_type_traits::DynNodeType SourceType = Other.getSupportedType();
+  // We support implicit conversion from Matcher<Type> to Matcher<QualType>
+  return SourceType.isSame(ast_type_traits::DynNodeType::type()) ||
+         SourceType.isSame(ast_type_traits::DynNodeType::qualType());
+}
+
+template <>
+inline Matcher<QualType>
+Matcher<QualType>::constructFrom(const DynTypedMatcher &Other) {
+  assert(canConstructFrom(Other));
+  ast_type_traits::DynNodeType SourceType = Other.getSupportedType();
+  if (SourceType.isSame(ast_type_traits::DynNodeType::type())) {
+    // We support implicit conversion from Matcher<Type> to Matcher<QualType>
+    return Matcher<Type>::constructFrom(Other);
+  }
+  return makeMatcher(new WrappedMatcher(Other));
+}
+
 /// \brief Metafunction to determine if type T has a member called getDecl.
 template <typename T> struct has_getDecl {
   struct Default { int getDecl; };
Index: include/clang/ASTMatchers/Dynamic/VariantValue.h
===================================================================
--- include/clang/ASTMatchers/Dynamic/VariantValue.h
+++ include/clang/ASTMatchers/Dynamic/VariantValue.h
@@ -63,44 +63,24 @@
   /// \brief Set the value to be \c Matcher by taking ownership of the object.
   void takeMatcher(DynTypedMatcher *Matcher);
 
-  /// \brief Specialized Matcher<T> is/get functions.
+  /// \brief Specialized Matcher<T> functions.
   template <class T>
-  bool isTypedMatcher() const {
-    // TODO: Add some logic to test if T is actually valid for the underlying
-    // type of the matcher.
-    return isMatcher();
+  bool hasTypedMatcher() const {
+    return isMatcher() &&
+           ast_matchers::internal::Matcher<T>::canConstructFrom(getMatcher());
   }
 
   template <class T>
   ast_matchers::internal::Matcher<T> getTypedMatcher() const {
-    return ast_matchers::internal::makeMatcher(
-        new DerivedTypeMatcher<T>(getMatcher()));
+    return ast_matchers::internal::Matcher<T>::constructFrom(getMatcher());
   }
 
+  /// \brief String representation of the type of the value.
+  std::string getTypeAsString() const;
+
 private:
   void reset();
 
-  /// \brief Matcher bridge between a Matcher<T> and a generic DynTypedMatcher.
-  template <class T>
-  class DerivedTypeMatcher :
-      public ast_matchers::internal::MatcherInterface<T> {
-  public:
-    explicit DerivedTypeMatcher(const DynTypedMatcher &DynMatcher)
-        : DynMatcher(DynMatcher.clone()) {}
-    virtual ~DerivedTypeMatcher() {}
-
-    typedef ast_matchers::internal::ASTMatchFinder ASTMatchFinder;
-    typedef ast_matchers::internal::BoundNodesTreeBuilder BoundNodesTreeBuilder;
-    bool matches(const T &Node, ASTMatchFinder *Finder,
-                 BoundNodesTreeBuilder *Builder) const {
-      return DynMatcher->matches(ast_type_traits::DynTypedNode::create(Node),
-                                 Finder, Builder);
-    }
-
-  private:
-    const OwningPtr<DynTypedMatcher> DynMatcher;
-  };
-
   /// \brief All supported value types.
   enum ValueType {
     VT_Nothing,
Index: lib/AST/ASTTypeTraits.cpp
===================================================================
--- /dev/null
+++ lib/AST/ASTTypeTraits.cpp
@@ -0,0 +1,56 @@
+//===--- ASTTypeTraits.cpp --------------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  Provides a dynamic type identifier and a dynamically typed node container
+//  that can be used to store an AST base node at runtime in the same storage in
+//  a type safe way.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTTypeTraits.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+const DynNodeType::TypeInfo DynNodeType::AllTypeInfo[] = {
+  { NTI_None, "<None>" },
+  { NTI_None, "NestedNameSpecifier" },
+  { NTI_None, "NestedNameSpecifierLoc" },
+  { NTI_None, "QualType" },
+  { NTI_None, "TypeLoc" },
+  { NTI_None, "Decl" },
+#define DECL(DERIVED, BASE) { NTI_##BASE, #DERIVED "Decl" },
+#include "clang/AST/DeclNodes.inc"
+  { NTI_None, "Stmt" },
+#define STMT(DERIVED, BASE) { NTI_##BASE, #DERIVED },
+#include "clang/AST/StmtNodes.inc"
+  { NTI_None, "Type" },
+#define TYPE(DERIVED, BASE) { NTI_##BASE, #DERIVED "Type" },
+#include "clang/AST/TypeNodes.def"
+};
+
+bool DynNodeType::isBaseOf(DynNodeType Other) {
+  return isBaseOf(TypeId, Other.TypeId);
+}
+
+bool DynNodeType::isSame(DynNodeType Other) {
+  return TypeId != NTI_None && TypeId == Other.TypeId;
+}
+
+bool DynNodeType::isBaseOf(NodeTypeId Base, NodeTypeId Derived) {
+  if (Base == NTI_None || Derived == NTI_None) return false;
+  while (Derived != Base && Derived != NTI_None)
+    Derived = AllTypeInfo[Derived].ParentId;
+  return Derived == Base;
+}
+
+StringRef DynNodeType::asStringRef() const { return AllTypeInfo[TypeId].Name; }
+
+} // end namespace ast_type_traits
+} // end namespace clang
Index: lib/AST/CMakeLists.txt
===================================================================
--- lib/AST/CMakeLists.txt
+++ lib/AST/CMakeLists.txt
@@ -7,6 +7,7 @@
   ASTDiagnostic.cpp
   ASTDumper.cpp
   ASTImporter.cpp
+  ASTTypeTraits.cpp
   AttrImpl.cpp
   CXXInheritance.cpp
   Comment.cpp
Index: lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- lib/ASTMatchers/ASTMatchFinder.cpp
+++ lib/ASTMatchers/ASTMatchFinder.cpp
@@ -746,10 +746,29 @@
 
 bool MatchFinder::addDynamicMatcher(const internal::DynTypedMatcher &NodeMatch,
                                     MatchCallback *Action) {
-  MatcherCallbackPairs.push_back(std::make_pair(NodeMatch.clone(), Action));
-  // TODO: Do runtime type checking to make sure the matcher is one of the valid
-  // top-level matchers.
-  return true;
+  // We only accept through this method the same types we accept through the
+  // statically typed interface. If the passed matcher is not of any of those
+  // types, we return false.
+  if (DeclarationMatcher::canConstructFrom(NodeMatch)) {
+    addMatcher(DeclarationMatcher::constructFrom(NodeMatch), Action);
+    return true;
+  } else if (TypeMatcher::canConstructFrom(NodeMatch)) {
+    addMatcher(TypeMatcher::constructFrom(NodeMatch), Action);
+    return true;
+  } else if (StatementMatcher::canConstructFrom(NodeMatch)) {
+    addMatcher(StatementMatcher::constructFrom(NodeMatch), Action);
+    return true;
+  } else if (NestedNameSpecifierMatcher::canConstructFrom(NodeMatch)) {
+    addMatcher(NestedNameSpecifierMatcher::constructFrom(NodeMatch), Action);
+    return true;
+  } else if (NestedNameSpecifierLocMatcher::canConstructFrom(NodeMatch)) {
+    addMatcher(NestedNameSpecifierLocMatcher::constructFrom(NodeMatch), Action);
+    return true;
+  } else if (TypeLocMatcher::canConstructFrom(NodeMatch)) {
+    addMatcher(TypeLocMatcher::constructFrom(NodeMatch), Action);
+    return true;
+  }
+  return false;
 }
 
 ASTConsumer *MatchFinder::newASTConsumer() {
Index: lib/ASTMatchers/Dynamic/Diagnostics.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Diagnostics.cpp
+++ lib/ASTMatchers/Dynamic/Diagnostics.cpp
@@ -36,7 +36,7 @@
   case Diagnostics::ET_RegistryWrongArgCount:
     return "Incorrect argument count. (Expected = $0) != (Actual = $1)";
   case Diagnostics::ET_RegistryWrongArgType:
-    return "Incorrect type on function $0 for arg $1.";
+    return "Incorrect type for arg $0. (Expected = $1) != (Actual = $2)";
 
   case Diagnostics::ET_ParserStringError:
     return "Error parsing string token: <$0>";
Index: lib/ASTMatchers/Dynamic/Marshallers.h
===================================================================
--- lib/ASTMatchers/Dynamic/Marshallers.h
+++ lib/ASTMatchers/Dynamic/Marshallers.h
@@ -44,14 +44,22 @@
 };
 
 template <> struct ArgTypeTraits<std::string> {
+  static StringRef asString() { return "String"; }
   static bool is(const VariantValue &Value) { return Value.isString(); }
   static const std::string &get(const VariantValue &Value) {
     return Value.getString();
   }
 };
 
 template <class T> struct ArgTypeTraits<ast_matchers::internal::Matcher<T> > {
-  static bool is(const VariantValue &Value) { return Value.isMatcher(); }
+  static std::string asString() {
+    return (Twine("Matcher<") +
+            ast_type_traits::DynNodeType::getFromNodeType<T>().asStringRef() +
+            ">").str();
+  }
+  static bool is(const VariantValue &Value) {
+    return Value.hasTypedMatcher<T>();
+  }
   static ast_matchers::internal::Matcher<T> get(const VariantValue &Value) {
     return Value.getTypedMatcher<T>();
   }
@@ -112,7 +120,8 @@
 #define CHECK_ARG_TYPE(index, type)                                            \
   if (!ArgTypeTraits<type>::is(Args[index].Value)) {                           \
     Error->pushErrorFrame(Args[index].Range, Error->ET_RegistryWrongArgType)   \
-        << MatcherName << (index + 1);                                         \
+        << (index + 1) << ArgTypeTraits<type>::asString()                      \
+        << Args[index].Value.getTypeAsString();                                \
     return NULL;                                                               \
   }
 
Index: lib/ASTMatchers/Dynamic/VariantValue.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/VariantValue.cpp
+++ lib/ASTMatchers/Dynamic/VariantValue.cpp
@@ -14,6 +14,8 @@
 
 #include "clang/ASTMatchers/Dynamic/VariantValue.h"
 
+#include "clang/Basic/LLVM.h"
+
 namespace clang {
 namespace ast_matchers {
 namespace dynamic {
@@ -100,6 +102,17 @@
   Value.Matcher = NewValue;
 }
 
+std::string VariantValue::getTypeAsString() const {
+  switch (Type) {
+  case VT_String: return "String";
+  case VT_Matcher:
+    return (Twine("Matcher<") + getMatcher().getSupportedType().asStringRef() +
+            ">").str();
+  case VT_Nothing: return "Nothing";
+  }
+  llvm_unreachable("Invalid Type");
+}
+
 } // end namespace dynamic
 } // end namespace ast_matchers
 } // end namespace clang
Index: unittests/AST/ASTTypeTraitsTest.cpp
===================================================================
--- /dev/null
+++ unittests/AST/ASTTypeTraitsTest.cpp
@@ -0,0 +1,62 @@
+//===- unittest/AST/ASTTypeTraits.cpp - AST type traits unit tests ------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--------------------------------------------------------------------===//
+
+
+#include "clang/AST/ASTTypeTraits.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace ast_type_traits {
+
+TEST(DynNodeType, NoType) {
+  EXPECT_FALSE(DynNodeType().isBaseOf(DynNodeType()));
+  EXPECT_FALSE(DynNodeType().isSame(DynNodeType()));
+}
+
+template <typename T> static DynNodeType DNT() {
+  return DynNodeType::getFromNodeType<T>();
+}
+
+TEST(DynNodeType, Bases) {
+  EXPECT_TRUE(DynNodeType::decl().isBaseOf(DNT<VarDecl>()));
+  EXPECT_FALSE(DynNodeType::decl().isSame(DNT<VarDecl>()));
+  EXPECT_FALSE(DNT<VarDecl>().isBaseOf(DynNodeType::decl()));
+
+  EXPECT_TRUE(DynNodeType::decl().isSame(DNT<Decl>()));
+}
+
+TEST(DynNodeType, SameBase) {
+  EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<CallExpr>()));
+  EXPECT_TRUE(DNT<Expr>().isBaseOf(DNT<BinaryOperator>()));
+  EXPECT_FALSE(DNT<CallExpr>().isBaseOf(DNT<BinaryOperator>()));
+  EXPECT_FALSE(DNT<BinaryOperator>().isBaseOf(DNT<CallExpr>()));
+}
+
+TEST(DynNodeType, DiffBase) {
+  EXPECT_FALSE(DNT<Expr>().isBaseOf(DNT<ArrayType>()));
+  EXPECT_FALSE(DNT<QualType>().isBaseOf(DNT<FunctionDecl>()));
+  EXPECT_FALSE(DNT<Type>().isSame(DNT<QualType>()));
+}
+
+struct Foo {};
+
+TEST(DynNodeType, UnknownType) {
+  // We can construct one, but it is nowhere in the hierarchy.
+  EXPECT_FALSE(DNT<Foo>().isSame(DNT<Foo>()));
+}
+
+TEST(DynNodeType, Name) {
+  EXPECT_EQ("Decl", DNT<Decl>().asStringRef());
+  EXPECT_EQ("CallExpr", DNT<CallExpr>().asStringRef());
+  EXPECT_EQ("ConstantArrayType", DNT<ConstantArrayType>().asStringRef());
+  EXPECT_EQ("<None>", DynNodeType().asStringRef());
+}
+
+}  // namespace ast_type_traits
+}  // namespace clang
Index: unittests/AST/CMakeLists.txt
===================================================================
--- unittests/AST/CMakeLists.txt
+++ unittests/AST/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_clang_unittest(ASTTests
   ASTContextParentMapTest.cpp
+  ASTTypeTraitsTest.cpp
   CommentLexer.cpp
   CommentParser.cpp
   DeclPrinterTest.cpp
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -40,6 +40,18 @@
 }
 #endif
 
+TEST(Finder, DynamicOnlyAcceptsSomeMatchers) {
+  MatchFinder Finder;
+  EXPECT_TRUE(Finder.addDynamicMatcher(decl(), NULL));
+  EXPECT_TRUE(Finder.addDynamicMatcher(callExpr(), NULL));
+  EXPECT_TRUE(Finder.addDynamicMatcher(constantArrayType(hasSize(42)), NULL));
+
+  // Do not accept non-toplevel matchers.
+  EXPECT_FALSE(Finder.addDynamicMatcher(isArrow(), NULL));
+  EXPECT_FALSE(Finder.addDynamicMatcher(hasSize(2), NULL));
+  EXPECT_FALSE(Finder.addDynamicMatcher(hasName("x"), NULL));
+}
+
 TEST(Decl, MatchesDeclarations) {
   EXPECT_TRUE(notMatches("", decl(usingDecl())));
   EXPECT_TRUE(matches("namespace x { class X {}; } using x::X;",
Index: unittests/ASTMatchers/Dynamic/ParserTest.cpp
===================================================================
--- unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -41,6 +41,10 @@
   /// \brief Returns a unique ID for the matcher.
   virtual uint64_t getID() const { return ID; }
 
+  virtual ast_type_traits::DynNodeType getSupportedType() const {
+    return ast_type_traits::DynNodeType();
+  }
+
 private:
   uint64_t ID;
 };
@@ -142,7 +146,8 @@
 
 TEST(ParserTest, FullParserTest) {
   OwningPtr<DynTypedMatcher> Matcher(Parser::parseMatcherExpression(
-      "hasInitializer(binaryOperator(hasLHS(integerLiteral())))", NULL));
+      "varDecl(hasInitializer(binaryOperator(hasLHS(integerLiteral()))))",
+      NULL));
   EXPECT_TRUE(matchesDynamic("int x = 1 + false;", *Matcher));
   EXPECT_FALSE(matchesDynamic("int x = true + 1;", *Matcher));
 
@@ -152,7 +157,8 @@
   EXPECT_EQ("1:1: Error parsing argument 1 for matcher hasInitializer.\n"
             "2:5: Error parsing argument 1 for matcher binaryOperator.\n"
             "2:20: Error building matcher hasLHS.\n"
-            "2:27: Incorrect type on function hasLHS for arg 1.",
+            "2:27: Incorrect type for arg 1. "
+            "(Expected = Matcher<Expr>) != (Actual = String)",
             Error.ToStringFull());
 }
 
Index: unittests/ASTMatchers/Dynamic/RegistryTest.cpp
===================================================================
--- unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -20,32 +20,55 @@
 
 using ast_matchers::internal::Matcher;
 
-DynTypedMatcher *constructMatcher(StringRef MatcherName, Diagnostics *Error) {
-  const std::vector<ParserValue> Args;
-  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
-                                  const VariantValue &Arg1,
-                                  Diagnostics *Error) {
-  std::vector<ParserValue> Args(1);
-  Args[0].Value = Arg1;
-  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-DynTypedMatcher *constructMatcher(StringRef MatcherName,
-                                  const VariantValue &Arg1,
-                                  const VariantValue &Arg2,
-                                  Diagnostics *Error) {
-  std::vector<ParserValue> Args(2);
-  Args[0].Value = Arg1;
-  Args[1].Value = Arg2;
-  return Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
-}
-
-TEST(RegistryTest, CanConstructNoArgs) {
-  OwningPtr<DynTypedMatcher> IsArrowValue(constructMatcher("isArrow", NULL));
-  OwningPtr<DynTypedMatcher> BoolValue(constructMatcher("boolLiteral", NULL));
+class RegistryTest : public ::testing::Test {
+public:
+  ~RegistryTest() {
+    for (size_t I = 0, E = ToDelete.size(); I != E; ++I) {
+      delete ToDelete[I];
+    }
+  }
+
+  const DynTypedMatcher *constructMatcher(StringRef MatcherName,
+                                          Diagnostics *Error) {
+    const std::vector<ParserValue> Args;
+    DynTypedMatcher *Out =
+        Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
+    ToDelete.push_back(Out);
+    return Out;
+  }
+
+  const DynTypedMatcher *constructMatcher(StringRef MatcherName,
+                                          const VariantValue &Arg1,
+                                          Diagnostics *Error) {
+    std::vector<ParserValue> Args(1);
+    Args[0].Value = Arg1;
+    DynTypedMatcher *Out =
+        Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
+    ToDelete.push_back(Out);
+    return Out;
+  }
+
+  const DynTypedMatcher *constructMatcher(StringRef MatcherName,
+                                          const VariantValue &Arg1,
+                                          const VariantValue &Arg2,
+                                          Diagnostics *Error) {
+    std::vector<ParserValue> Args(2);
+    Args[0].Value = Arg1;
+    Args[1].Value = Arg2;
+    DynTypedMatcher *Out =
+        Registry::constructMatcher(MatcherName, SourceRange(), Args, Error);
+    ToDelete.push_back(Out);
+    return Out;
+  }
+
+private:
+  std::vector<DynTypedMatcher *> ToDelete;
+};
+
+TEST_F(RegistryTest, CanConstructNoArgs) {
+  const DynTypedMatcher *IsArrowValue =
+      constructMatcher("memberExpr", *constructMatcher("isArrow", NULL), NULL);
+  const DynTypedMatcher *BoolValue = constructMatcher("boolLiteral", NULL);
 
   const std::string ClassSnippet = "struct Foo { int x; };\n"
                                    "Foo *foo = new Foo;\n"
@@ -58,18 +81,18 @@
   EXPECT_FALSE(matchesDynamic(BoolSnippet, *IsArrowValue));
 }
 
-TEST(RegistryTest, ConstructWithSimpleArgs) {
-  OwningPtr<DynTypedMatcher> Value(
-      constructMatcher("hasName", std::string("X"), NULL));
+TEST_F(RegistryTest, ConstructWithSimpleArgs) {
+  const DynTypedMatcher *Value = constructMatcher(
+      "namedDecl", *constructMatcher("hasName", std::string("X"), NULL), NULL);
   EXPECT_TRUE(matchesDynamic("class X {};", *Value));
   EXPECT_FALSE(matchesDynamic("int x;", *Value));
 }
 
-TEST(RegistryTest, ConstructWithMatcherArgs) {
-  OwningPtr<DynTypedMatcher> HasInitializerSimple(
-      constructMatcher("hasInitializer", stmt(), NULL));
-  OwningPtr<DynTypedMatcher> HasInitializerComplex(
-      constructMatcher("hasInitializer", callExpr(), NULL));
+TEST_F(RegistryTest, ConstructWithMatcherArgs) {
+  const DynTypedMatcher *HasInitializerSimple = constructMatcher(
+      "varDecl", *constructMatcher("hasInitializer", stmt(), NULL), NULL);
+  const DynTypedMatcher *HasInitializerComplex = constructMatcher(
+      "varDecl", *constructMatcher("hasInitializer", callExpr(), NULL), NULL);
 
   std::string code = "int i;";
   EXPECT_FALSE(matchesDynamic(code, *HasInitializerSimple));
@@ -84,7 +107,7 @@
   EXPECT_TRUE(matchesDynamic(code, *HasInitializerComplex));
 }
 
-TEST(RegistryTest, Errors) {
+TEST_F(RegistryTest, Errors) {
   // Incorrect argument count.
   OwningPtr<Diagnostics> Error(new Diagnostics());
   EXPECT_TRUE(NULL == constructMatcher("hasInitializer", Error.get()));
@@ -98,11 +121,14 @@
   // Bad argument type
   Error.reset(new Diagnostics());
   EXPECT_TRUE(NULL == constructMatcher("ofClass", std::string(), Error.get()));
-  EXPECT_EQ("Incorrect type on function ofClass for arg 1.", Error->ToString());
+  EXPECT_EQ("Incorrect type for arg 1. (Expected = Matcher<CXXRecordDecl>) != "
+            "(Actual = String)",
+            Error->ToString());
   Error.reset(new Diagnostics());
   EXPECT_TRUE(NULL == constructMatcher("recordDecl", recordDecl(),
-                                       ::std::string(), Error.get()));
-  EXPECT_EQ("Incorrect type on function recordDecl for arg 2.",
+                                       parameterCountIs(3), Error.get()));
+  EXPECT_EQ("Incorrect type for arg 2. (Expected = Matcher<CXXRecordDecl>) != "
+            "(Actual = Matcher<FunctionDecl>)",
             Error->ToString());
 }
 
Index: unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
===================================================================
--- unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
+++ unittests/ASTMatchers/Dynamic/VariantValueTest.cpp
@@ -25,51 +25,58 @@
 
   EXPECT_TRUE(Value.isString());
   EXPECT_EQ(kString, Value.getString());
+  EXPECT_EQ("String", Value.getTypeAsString());
 
   EXPECT_FALSE(Value.isMatcher());
-  EXPECT_FALSE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_FALSE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
 }
 
 TEST(VariantValueTest, DynTypedMatcher) {
   VariantValue Value = stmt();
 
   EXPECT_FALSE(Value.isString());
 
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::UnaryOperator>());
+  EXPECT_EQ("Matcher<Stmt>", Value.getTypeAsString());
 
-  // Conversion to any type of matcher works.
-  // If they are not compatible it would just return a matcher that matches
-  // nothing. We test this below.
+  // Can only convert to compatible matchers.
   Value = recordDecl();
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+  EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
 
-  Value = unaryOperator();
+  Value = ignoringImpCasts(expr());
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Stmt>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::Stmt>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::Expr>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::IntegerLiteral>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::GotoStmt>());
+  EXPECT_EQ("Matcher<Expr>", Value.getTypeAsString());
 }
 
 TEST(VariantValueTest, Assignment) {
   VariantValue Value = std::string("A");
   EXPECT_TRUE(Value.isString());
   EXPECT_EQ("A", Value.getString());
   EXPECT_FALSE(Value.isMatcher());
+  EXPECT_EQ("String", Value.getTypeAsString());
 
   Value = recordDecl();
   EXPECT_FALSE(Value.isString());
   EXPECT_TRUE(Value.isMatcher());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::Decl>());
-  EXPECT_TRUE(Value.isTypedMatcher<clang::UnaryOperator>());
+  EXPECT_TRUE(Value.hasTypedMatcher<clang::Decl>());
+  EXPECT_FALSE(Value.hasTypedMatcher<clang::UnaryOperator>());
+  EXPECT_EQ("Matcher<Decl>", Value.getTypeAsString());
 
   Value = VariantValue();
   EXPECT_FALSE(Value.isString());
   EXPECT_FALSE(Value.isMatcher());
+  EXPECT_EQ("Nothing", Value.getTypeAsString());
 }
 
 TEST(GeneicValueTest, Matcher) {
@@ -79,10 +86,13 @@
       "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Decl>()));
   EXPECT_TRUE(matchesDynamic("int foo() { return 1 + 1; }",
                              VariantValue(functionDecl()).getMatcher()));
-  // Going through the wrong Matcher<T> will fail to match, even if the
-  // underlying matcher is correct.
-  EXPECT_FALSE(matchesDynamic(
-      "int x;", VariantValue(varDecl()).getTypedMatcher<clang::Stmt>()));
+  // Can't get the wrong matcher.
+  EXPECT_FALSE(VariantValue(varDecl()).hasTypedMatcher<clang::Stmt>());
+#if GTEST_HAS_DEATH_TEST
+  // Trying to get the wrong matcher fails an assertion in Matcher<T>.
+  EXPECT_DEBUG_DEATH(VariantValue(varDecl()).getTypedMatcher<clang::Stmt>(),
+                     "canConstructFrom");
+#endif
 
   EXPECT_FALSE(
       matchesDynamic("int x;", VariantValue(functionDecl()).getMatcher()));
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to