r176251 - First step towards adding a parent map to the ASTContext.

Manuel Klimek klimek at google.com
Thu Feb 28 05:21:39 PST 2013


Author: klimek
Date: Thu Feb 28 07:21:39 2013
New Revision: 176251

URL: http://llvm.org/viewvc/llvm-project?rev=176251&view=rev
Log:
First step towards adding a parent map to the ASTContext.

This does not yet implement the LimitNode approach discussed.

The impact of this is an O(n) in the number of nodes in the AST
reduction of complexity for certain kinds of matchers (as otherwise the
parent map gets recreated for every new MatchFinder).

See FIXMEs in the comments for the direction of future work.

Added:
    cfe/trunk/include/clang/AST/ASTTypeTraits.h
      - copied, changed from r176245, cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
    cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp
Removed:
    cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
    cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
    cfe/trunk/unittests/AST/CMakeLists.txt
    cfe/trunk/unittests/AST/MatchVerifier.h

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=176251&r1=176250&r2=176251&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Feb 28 07:21:39 2013
@@ -15,6 +15,7 @@
 #ifndef LLVM_CLANG_AST_ASTCONTEXT_H
 #define LLVM_CLANG_AST_ASTCONTEXT_H
 
+#include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/CanonicalType.h"
 #include "clang/AST/CommentCommandTraits.h"
 #include "clang/AST/Decl.h"
@@ -22,6 +23,7 @@
 #include "clang/AST/NestedNameSpecifier.h"
 #include "clang/AST/PrettyPrinter.h"
 #include "clang/AST/RawCommentList.h"
+#include "clang/AST/RecursiveASTVisitor.h"
 #include "clang/AST/TemplateName.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/AddressSpaces.h"
@@ -382,6 +384,58 @@ public:
   OwningPtr<ExternalASTSource> ExternalSource;
   ASTMutationListener *Listener;
 
+  /// \brief Contains parents of a node.
+  typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;
+
+  /// \brief Maps from a node to its parents.
+  typedef llvm::DenseMap<const void *, ParentVector> ParentMap;
+
+  /// \brief Returns the parents of the given node.
+  ///
+  /// Note that this will lazily compute the parents of all nodes
+  /// and store them for later retrieval. Thus, the first call is O(n)
+  /// in the number of AST nodes.
+  ///
+  /// Caveats and FIXMEs:
+  /// Calculating the parent map over all AST nodes will need to load the
+  /// full AST. This can be undesirable in the case where the full AST is
+  /// expensive to create (for example, when using precompiled header
+  /// preambles). Thus, there are good opportunities for optimization here.
+  /// One idea is to walk the given node downwards, looking for references
+  /// to declaration contexts - once a declaration context is found, compute
+  /// the parent map for the declaration context; if that can satisfy the
+  /// request, loading the whole AST can be avoided. Note that this is made
+  /// more complex by statements in templates having multiple parents - those
+  /// problems can be solved by building closure over the templated parts of
+  /// the AST, which also avoids touching large parts of the AST.
+  /// Additionally, we will want to add an interface to already give a hint
+  /// where to search for the parents, for example when looking at a statement
+  /// inside a certain function.
+  ///
+  /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,
+  /// NestedNameSpecifier or NestedNameSpecifierLoc.
+  template <typename NodeT>
+  ParentVector getParents(const NodeT &Node) {
+    return getParents(ast_type_traits::DynTypedNode::create(Node));
+  }
+
+  ParentVector getParents(const ast_type_traits::DynTypedNode &Node) {
+    assert(Node.getMemoizationData() &&
+           "Invariant broken: only nodes that support memoization may be "
+           "used in the parent map.");
+    if (!AllParents) {
+      // We always need to run over the whole translation unit, as
+      // hasAncestor can escape any subtree.
+      AllParents.reset(
+          ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));
+    }
+    ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());
+    if (I == AllParents->end()) {
+      return ParentVector();
+    }
+    return I->second;
+  }
+
   const clang::PrintingPolicy &getPrintingPolicy() const {
     return PrintingPolicy;
   }
@@ -2136,8 +2190,81 @@ private:
   friend class DeclContext;
   friend class DeclarationNameTable;
   void ReleaseDeclContextMaps();
+
+  /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
+  /// parents as defined by the \c RecursiveASTVisitor.
+  ///
+  /// Note that the relationship described here is purely in terms of AST
+  /// traversal - there are other relationships (for example declaration context)
+  /// in the AST that are better modeled by special matchers.
+  ///
+  /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
+  class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
+  public:
+    /// \brief Builds and returns the translation unit's parent map.
+    ///
+    ///  The caller takes ownership of the returned \c ParentMap.
+    static ParentMap *buildMap(TranslationUnitDecl &TU) {
+      ParentMapASTVisitor Visitor(new ParentMap);
+      Visitor.TraverseDecl(&TU);
+      return Visitor.Parents;
+    }
+
+  private:
+    typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
+
+    ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {
+    }
+
+    bool shouldVisitTemplateInstantiations() const {
+      return true;
+    }
+    bool shouldVisitImplicitCode() const {
+      return true;
+    }
+    // Disables data recursion. We intercept Traverse* methods in the RAV, which
+    // are not triggered during data recursion.
+    bool shouldUseDataRecursionFor(clang::Stmt *S) const {
+      return false;
+    }
+
+    template <typename T>
+    bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {
+      if (Node == NULL)
+        return true;
+      if (ParentStack.size() > 0)
+        // FIXME: Currently we add the same parent multiple times, for example
+        // when we visit all subexpressions of template instantiations; this is
+        // suboptimal, bug benign: the only way to visit those is with
+        // hasAncestor / hasParent, and those do not create new matches.
+        // The plan is to enable DynTypedNode to be storable in a map or hash
+        // map. The main problem there is to implement hash functions /
+        // comparison operators for all types that DynTypedNode supports that
+        // do not have pointer identity.
+        (*Parents)[Node].push_back(ParentStack.back());
+      ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
+      bool Result = (this ->* traverse) (Node);
+      ParentStack.pop_back();
+      return Result;
+    }
+
+    bool TraverseDecl(Decl *DeclNode) {
+      return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
+    }
+
+    bool TraverseStmt(Stmt *StmtNode) {
+      return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
+    }
+
+    ParentMap *Parents;
+    llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
+
+    friend class RecursiveASTVisitor<ParentMapASTVisitor>;
+  };
+
+  llvm::OwningPtr<ParentMap> AllParents;
 };
-  
+
 /// \brief Utility function for constructing a nullary selector.
 static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {
   IdentifierInfo* II = &Ctx.Idents.get(name);

Copied: cfe/trunk/include/clang/AST/ASTTypeTraits.h (from r176245, cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h)
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTTypeTraits.h?p2=cfe/trunk/include/clang/AST/ASTTypeTraits.h&p1=cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h&r1=176245&r2=176251&rev=176251&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)
+++ cfe/trunk/include/clang/AST/ASTTypeTraits.h Thu Feb 28 07:21:39 2013
@@ -1,4 +1,4 @@
-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//
+//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//
 //
 //                     The LLVM Compiler Infrastructure
 //
@@ -12,8 +12,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
+#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H
+#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H
 
 #include "clang/AST/Decl.h"
 #include "clang/AST/Stmt.h"
@@ -88,8 +88,9 @@ private:
   /// 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*, QualType, TypeLoc, NestedNameSpecifierLoc>
-    Storage;
+  llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,
+                              NestedNameSpecifierLoc, QualType, Type,
+                              TypeLoc> Storage;
 };
 
 // FIXME: Pull out abstraction for the following.
@@ -207,4 +208,4 @@ inline const void *DynTypedNode::getMemo
 } // end namespace ast_type_traits
 } // end namespace clang
 
-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
+#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H

Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=176251&r1=176250&r2=176251&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Feb 28 07:21:39 2013
@@ -35,13 +35,13 @@
 #ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
 #define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H
 
-#include "clang/AST/Decl.h"
+#include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/Decl.h"
 #include "clang/AST/ExprCXX.h"
-#include "clang/AST/Stmt.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/AST/Stmt.h"
 #include "clang/AST/Type.h"
-#include "clang/ASTMatchers/ASTTypeTraits.h"
 #include "llvm/ADT/VariadicFunction.h"
 #include "llvm/Support/type_traits.h"
 #include <map>

Removed: cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=176250&view=auto
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (removed)
@@ -1,210 +0,0 @@
-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//
-//
-//                     The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-//  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.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H
-
-#include "clang/AST/Decl.h"
-#include "clang/AST/Stmt.h"
-#include "clang/AST/TypeLoc.h"
-#include "llvm/Support/AlignOf.h"
-
-namespace clang {
-namespace ast_type_traits {
-
-/// \brief A dynamically typed AST node container.
-///
-/// Stores an AST node in a type safe way. This allows writing code that
-/// works with different kinds of AST nodes, despite the fact that they don't
-/// have a common base class.
-///
-/// Use \c create(Node) to create a \c DynTypedNode from an AST node,
-/// and \c get<T>() to retrieve the node as type T if the types match.
-///
-/// See \c NodeTypeTag for which node base types are currently supported;
-/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of
-/// the supported base types.
-class DynTypedNode {
-public:
-  /// \brief Creates a \c DynTypedNode from \c Node.
-  template <typename T>
-  static DynTypedNode create(const T &Node) {
-    return BaseConverter<T>::create(Node);
-  }
-
-  /// \brief Retrieve the stored node as type \c T.
-  ///
-  /// Returns NULL if the stored node does not have a type that is
-  /// convertible to \c T.
-  ///
-  /// For types that have identity via their pointer in the AST
-  /// (like \c Stmt and \c Decl) the returned pointer points to the
-  /// referenced AST node.
-  /// For other types (like \c QualType) the value is stored directly
-  /// in the \c DynTypedNode, and the returned pointer points at
-  /// the storage inside DynTypedNode. For those nodes, do not
-  /// use the pointer outside the scope of the DynTypedNode.
-  template <typename T>
-  const T *get() const {
-    return BaseConverter<T>::get(Tag, Storage.buffer);
-  }
-
-  /// \brief Returns a pointer that identifies the stored AST node.
-  ///
-  /// Note that this is not supported by all AST nodes. For AST nodes
-  /// that don't have a pointer-defined identity inside the AST, this
-  /// method returns NULL.
-  const void *getMemoizationData() const;
-
-private:
-  /// \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;
-
-  /// \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*, QualType, TypeLoc, NestedNameSpecifierLoc>
-    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)
-      return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));
-    return NULL;
-  }
-  static DynTypedNode create(const Decl &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_Decl;
-    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)
-      return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));
-    return NULL;
-  }
-  static DynTypedNode create(const Stmt &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_Stmt;
-    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)
-      return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));
-    return NULL;
-  }
-  static DynTypedNode create(const Type &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_Type;
-    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)
-      return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);
-    return NULL;
-  }
-  static DynTypedNode create(const NestedNameSpecifier &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_NestedNameSpecifier;
-    new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);
-    return Result;
-  }
-};
-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {
-  static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,
-                                           const char Storage[]) {
-    if (Tag == NT_NestedNameSpecifierLoc)
-      return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);
-    return NULL;
-  }
-  static DynTypedNode create(const NestedNameSpecifierLoc &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_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)
-      return reinterpret_cast<const QualType*>(Storage);
-    return NULL;
-  }
-  static DynTypedNode create(const QualType &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_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)
-      return reinterpret_cast<const TypeLoc*>(Storage);
-    return NULL;
-  }
-  static DynTypedNode create(const TypeLoc &Node) {
-    DynTypedNode Result;
-    Result.Tag = NT_TypeLoc;
-    new (Result.Storage.buffer) TypeLoc(Node);
-    return Result;
-  }
-};
-// The only operation we allow on unsupported types is \c get.
-// This allows to conveniently use \c DynTypedNode when having an arbitrary
-// 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; }
-};
-
-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;
-  };
-}
-
-} // end namespace ast_type_traits
-} // end namespace clang
-
-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H

Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=176251&r1=176250&r2=176251&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Feb 28 07:21:39 2013
@@ -29,76 +29,6 @@ namespace {
 
 typedef MatchFinder::MatchCallback MatchCallback;
 
-/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their
-/// parents as defined by the \c RecursiveASTVisitor.
-///
-/// Note that the relationship described here is purely in terms of AST
-/// traversal - there are other relationships (for example declaration context)
-/// in the AST that are better modeled by special matchers.
-///
-/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.
-class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {
-public:
-  /// \brief Contains parents of a node.
-  typedef SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;
-
-  /// \brief Maps from a node to its parents.
-  typedef llvm::DenseMap<const void *, ParentVector> ParentMap;
-
-  /// \brief Builds and returns the translation unit's parent map.
-  ///
-  ///  The caller takes ownership of the returned \c ParentMap.
-  static ParentMap *buildMap(TranslationUnitDecl &TU) {
-    ParentMapASTVisitor Visitor(new ParentMap);
-    Visitor.TraverseDecl(&TU);
-    return Visitor.Parents;
-  }
-
-private:
-  typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;
-
-  ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {}
-
-  bool shouldVisitTemplateInstantiations() const { return true; }
-  bool shouldVisitImplicitCode() const { return true; }
-  // Disables data recursion. We intercept Traverse* methods in the RAV, which
-  // are not triggered during data recursion.
-  bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }
-
-  template <typename T>
-  bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) {
-    if (Node == NULL)
-      return true;
-    if (ParentStack.size() > 0)
-      // FIXME: Currently we add the same parent multiple times, for example
-      // when we visit all subexpressions of template instantiations; this is
-      // suboptimal, bug benign: the only way to visit those is with
-      // hasAncestor / hasParent, and those do not create new matches.
-      // The plan is to enable DynTypedNode to be storable in a map or hash
-      // map. The main problem there is to implement hash functions /
-      // comparison operators for all types that DynTypedNode supports that
-      // do not have pointer identity.
-      (*Parents)[Node].push_back(ParentStack.back());
-    ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));
-    bool Result = (this->*traverse)(Node);
-    ParentStack.pop_back();
-    return Result;
-  }
-
-  bool TraverseDecl(Decl *DeclNode) {
-    return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);
-  }
-
-  bool TraverseStmt(Stmt *StmtNode) {
-    return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);
-  }
-
-  ParentMap *Parents;
-  SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;
-
-  friend class RecursiveASTVisitor<ParentMapASTVisitor>;
-};
-
 // We use memoization to avoid running the same matcher on the same
 // AST node twice.  This pair is the key for looking up match
 // result.  It consists of an ID of the MatcherInterface (for
@@ -458,12 +388,6 @@ public:
                                  const DynTypedMatcher &Matcher,
                                  BoundNodesTreeBuilder *Builder,
                                  AncestorMatchMode MatchMode) {
-    if (!Parents) {
-      // We always need to run over the whole translation unit, as
-      // \c hasAncestor can escape any subtree.
-      Parents.reset(ParentMapASTVisitor::buildMap(
-        *ActiveASTContext->getTranslationUnitDecl()));
-    }
     return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);
   }
 
@@ -506,22 +430,21 @@ private:
     assert(Node.getMemoizationData() &&
            "Invariant broken: only nodes that support memoization may be "
            "used in the parent map.");
-    ParentMapASTVisitor::ParentMap::const_iterator I =
-        Parents->find(Node.getMemoizationData());
-    if (I == Parents->end()) {
+    ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);
+    if (Parents.empty()) {
       assert(false && "Found node that is not in the parent map.");
       return false;
     }
-    for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =
-             I->second.begin(), AncestorE = I->second.end();
+    for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),
+                                                  AncestorE = Parents.end();
          AncestorI != AncestorE; ++AncestorI) {
       if (Matcher.matches(*AncestorI, this, Builder))
         return true;
     }
     if (MatchMode == ASTMatchFinder::AMM_ParentOnly)
       return false;
-    for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =
-             I->second.begin(), AncestorE = I->second.end();
+    for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),
+                                                  AncestorE = Parents.end();
          AncestorI != AncestorE; ++AncestorI) {
       if (matchesAncestorOfRecursively(*AncestorI, Matcher, Builder, MatchMode))
         return true;
@@ -574,8 +497,6 @@ private:
   // Maps (matcher, node) -> the match result for memoization.
   typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;
   MemoizationMap ResultCache;
-
-  OwningPtr<ParentMapASTVisitor::ParentMap> Parents;
 };
 
 // Returns true if the given class is directly or indirectly derived

Added: cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp?rev=176251&view=auto
==============================================================================
--- cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp (added)
+++ cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp Thu Feb 28 07:21:39 2013
@@ -0,0 +1,71 @@
+//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for the getParents(...) methods of ASTContext.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+#include "MatchVerifier.h"
+
+namespace clang {
+namespace ast_matchers {
+
+using clang::tooling::newFrontendActionFactory;
+using clang::tooling::runToolOnCodeWithArgs;
+using clang::tooling::FrontendActionFactory;
+
+TEST(GetParents, ReturnsParentForDecl) {
+  MatchVerifier<Decl> Verifier;
+  EXPECT_TRUE(Verifier.match("class C { void f(); };",
+                             methodDecl(hasParent(recordDecl(hasName("C"))))));
+}
+
+TEST(GetParents, ReturnsParentForStmt) {
+  MatchVerifier<Stmt> Verifier;
+  EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };",
+                             ifStmt(hasParent(compoundStmt()))));
+}
+
+TEST(GetParents, ReturnsParentInsideTemplateInstantiations) {
+  MatchVerifier<Decl> DeclVerifier;
+  EXPECT_TRUE(DeclVerifier.match(
+      "template<typename T> struct C { void f() {} };"
+      "void g() { C<int> c; c.f(); }",
+      methodDecl(hasName("f"),
+                 hasParent(recordDecl(isTemplateInstantiation())))));
+  EXPECT_TRUE(DeclVerifier.match(
+      "template<typename T> struct C { void f() {} };"
+      "void g() { C<int> c; c.f(); }",
+      methodDecl(hasName("f"),
+                 hasParent(recordDecl(unless(isTemplateInstantiation()))))));
+  EXPECT_FALSE(DeclVerifier.match(
+      "template<typename T> struct C { void f() {} };"
+      "void g() { C<int> c; c.f(); }",
+      methodDecl(hasName("f"),
+                 allOf(hasParent(recordDecl(unless(isTemplateInstantiation()))),
+                       hasParent(recordDecl(isTemplateInstantiation()))))));
+}
+
+TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) {
+  MatchVerifier<Stmt> TemplateVerifier;
+  EXPECT_TRUE(TemplateVerifier.match(
+      "template<typename T> struct C { void f() {} };"
+      "void g() { C<int> c; c.f(); }",
+      compoundStmt(
+          allOf(hasAncestor(recordDecl(isTemplateInstantiation())),
+                hasAncestor(recordDecl(unless(isTemplateInstantiation())))))));
+}
+
+} // end namespace ast_matchers
+} // end namespace clang

Modified: cfe/trunk/unittests/AST/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=176251&r1=176250&r2=176251&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/CMakeLists.txt (original)
+++ cfe/trunk/unittests/AST/CMakeLists.txt Thu Feb 28 07:21:39 2013
@@ -1,4 +1,5 @@
 add_clang_unittest(ASTTests
+  ASTContextParentMapTest.cpp
   CommentLexer.cpp
   CommentParser.cpp
   DeclPrinterTest.cpp

Modified: cfe/trunk/unittests/AST/MatchVerifier.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/MatchVerifier.h?rev=176251&r1=176250&r2=176251&view=diff
==============================================================================
--- cfe/trunk/unittests/AST/MatchVerifier.h (original)
+++ cfe/trunk/unittests/AST/MatchVerifier.h Thu Feb 28 07:21:39 2013
@@ -44,7 +44,7 @@ public:
 protected:
   virtual void run(const MatchFinder::MatchResult &Result);
   virtual void verify(const MatchFinder::MatchResult &Result,
-                      const NodeType &Node) = 0;
+                      const NodeType &Node) {}
 
   void setFailure(const Twine &Result) {
     Verified = false;





More information about the cfe-commits mailing list