<div dir="ltr">Hopefully fixed in r176275</div><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Feb 28, 2013 at 6:55 PM, Anna Zaks <span dir="ltr"><<a href="mailto:ganna@apple.com" target="_blank">ganna@apple.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div>Manuel,</div><div><br></div>This commit has caused breakage on our internal MSVC buildbot:<div>
<br></div><div><div>279>.\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1715) : error C2872: 'clang' : ambiguous symbol</div><div>279>        could be 'clang'</div><div>279>        or       'clang::ento::clang'</div>
<div>279>        .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1688) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseFunctionHelper(clang::FunctionDecl *)'</div>
<div>279>        with</div><div>279>        [</div><div>279>            Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279>        ]</div><div>279>        .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1840) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseGCCAsmStmt(clang::GCCAsmStmt *)'</div>
<div>279>        with</div><div>279>        [</div><div>279>            Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279>        ]</div><div>279>        .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(522) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseStmt(clang::Stmt *)'</div>
<div>279>        with</div><div>279>        [</div><div>279>            Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279>        ]</div><div>279>        .\llvm\tools\clang\include\clang/AST/ASTContext.h(2202) : see reference to class template instantiation 'clang::RecursiveASTVisitor<Derived>' being compiled</div>
<div>279>        with</div><div>279>        [</div><div>279>            Derived=clang::ASTContext::ParentMapASTVisitor</div><div>279>        ]</div><div>275>   Creating library .\llvm\build\lib\Debug\clang-check.lib and object .\llvm\build\lib\Debug\clang-check.exp</div>
<div>2</div><div><div class="h5"><div><div>On Feb 28, 2013, at 5:21 AM, Manuel Klimek <<a href="mailto:klimek@google.com" target="_blank">klimek@google.com</a>> wrote:</div><br><blockquote type="cite"><div style="letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">
Author: klimek<br>Date: Thu Feb 28 07:21:39 2013<br>New Revision: 176251<br><br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project?rev=176251&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=176251&view=rev</a><br>
Log:<br>First step towards adding a parent map to the ASTContext.<br><br>This does not yet implement the LimitNode approach discussed.<br><br>The impact of this is an O(n) in the number of nodes in the AST<br>reduction of complexity for certain kinds of matchers (as otherwise the<br>
parent map gets recreated for every new MatchFinder).<br><br>See FIXMEs in the comments for the direction of future work.<br><br>Added:<br>   cfe/trunk/include/clang/AST/ASTTypeTraits.h<br>     - copied, changed from r176245, cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h<br>
   cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp<br>Removed:<br>   cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h<br>Modified:<br>   cfe/trunk/include/clang/AST/ASTContext.h<br>   cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h<br>
   cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp<br>   cfe/trunk/unittests/AST/CMakeLists.txt<br>   cfe/trunk/unittests/AST/MatchVerifier.h<br><br>Modified: cfe/trunk/include/clang/AST/ASTContext.h<br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=176251&r1=176250&r2=176251&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=176251&r1=176250&r2=176251&view=diff</a><br>
==============================================================================<br>--- cfe/trunk/include/clang/AST/ASTContext.h (original)<br>+++ cfe/trunk/include/clang/AST/ASTContext.h Thu Feb 28 07:21:39 2013<br>@@ -15,6 +15,7 @@<br>
#ifndef LLVM_CLANG_AST_ASTCONTEXT_H<br>#define LLVM_CLANG_AST_ASTCONTEXT_H<br><br>+#include "clang/AST/ASTTypeTraits.h"<br>#include "clang/AST/CanonicalType.h"<br>#include "clang/AST/CommentCommandTraits.h"<br>
#include "clang/AST/Decl.h"<br>@@ -22,6 +23,7 @@<br>#include "clang/AST/NestedNameSpecifier.h"<br>#include "clang/AST/PrettyPrinter.h"<br>#include "clang/AST/RawCommentList.h"<br>+#include "clang/AST/RecursiveASTVisitor.h"<br>
#include "clang/AST/TemplateName.h"<br>#include "clang/AST/Type.h"<br>#include "clang/Basic/AddressSpaces.h"<br>@@ -382,6 +384,58 @@ public:<br>  OwningPtr<ExternalASTSource> ExternalSource;<br>
  ASTMutationListener *Listener;<br><br>+  /// \brief Contains parents of a node.<br>+  typedef llvm::SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;<br>+<br>+  /// \brief Maps from a node to its parents.<br>
+  typedef llvm::DenseMap<const void *, ParentVector> ParentMap;<br>+<br>+  /// \brief Returns the parents of the given node.<br>+  ///<br>+  /// Note that this will lazily compute the parents of all nodes<br>+  /// and store them for later retrieval. Thus, the first call is O(n)<br>
+  /// in the number of AST nodes.<br>+  ///<br>+  /// Caveats and FIXMEs:<br>+  /// Calculating the parent map over all AST nodes will need to load the<br>+  /// full AST. This can be undesirable in the case where the full AST is<br>
+  /// expensive to create (for example, when using precompiled header<br>+  /// preambles). Thus, there are good opportunities for optimization here.<br>+  /// One idea is to walk the given node downwards, looking for references<br>
+  /// to declaration contexts - once a declaration context is found, compute<br>+  /// the parent map for the declaration context; if that can satisfy the<br>+  /// request, loading the whole AST can be avoided. Note that this is made<br>
+  /// more complex by statements in templates having multiple parents - those<br>+  /// problems can be solved by building closure over the templated parts of<br>+  /// the AST, which also avoids touching large parts of the AST.<br>
+  /// Additionally, we will want to add an interface to already give a hint<br>+  /// where to search for the parents, for example when looking at a statement<br>+  /// inside a certain function.<br>+  ///<br>+  /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,<br>
+  /// NestedNameSpecifier or NestedNameSpecifierLoc.<br>+  template <typename NodeT><br>+  ParentVector getParents(const NodeT &Node) {<br>+    return getParents(ast_type_traits::DynTypedNode::create(Node));<br>
+  }<br>+<br>+  ParentVector getParents(const ast_type_traits::DynTypedNode &Node) {<br>+    assert(Node.getMemoizationData() &&<br>+           "Invariant broken: only nodes that support memoization may be "<br>
+           "used in the parent map.");<br>+    if (!AllParents) {<br>+      // We always need to run over the whole translation unit, as<br>+      // hasAncestor can escape any subtree.<br>+      AllParents.reset(<br>
+          ParentMapASTVisitor::buildMap(*getTranslationUnitDecl()));<br>+    }<br>+    ParentMap::const_iterator I = AllParents->find(Node.getMemoizationData());<br>+    if (I == AllParents->end()) {<br>+      return ParentVector();<br>
+    }<br>+    return I->second;<br>+  }<br>+<br>  const clang::PrintingPolicy &getPrintingPolicy() const {<br>    return PrintingPolicy;<br>  }<br>@@ -2136,8 +2190,81 @@ private:<br>  friend class DeclContext;<br>
  friend class DeclarationNameTable;<br>  void ReleaseDeclContextMaps();<br>+<br>+  /// \brief A \c RecursiveASTVisitor that builds a map from nodes to their<br>+  /// parents as defined by the \c RecursiveASTVisitor.<br>
+  ///<br>+  /// Note that the relationship described here is purely in terms of AST<br>+  /// traversal - there are other relationships (for example declaration context)<br>+  /// in the AST that are better modeled by special matchers.<br>
+  ///<br>+  /// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.<br>+  class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {<br>+  public:<br>+    /// \brief Builds and returns the translation unit's parent map.<br>
+    ///<br>+    ///  The caller takes ownership of the returned \c ParentMap.<br>+    static ParentMap *buildMap(TranslationUnitDecl &TU) {<br>+      ParentMapASTVisitor Visitor(new ParentMap);<br>+      Visitor.TraverseDecl(&TU);<br>
+      return Visitor.Parents;<br>+    }<br>+<br>+  private:<br>+    typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;<br>+<br>+    ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {<br>+    }<br>
+<br>+    bool shouldVisitTemplateInstantiations() const {<br>+      return true;<br>+    }<br>+    bool shouldVisitImplicitCode() const {<br>+      return true;<br>+    }<br>+    // Disables data recursion. We intercept Traverse* methods in the RAV, which<br>
+    // are not triggered during data recursion.<br>+    bool shouldUseDataRecursionFor(clang::Stmt *S) const {<br>+      return false;<br>+    }<br>+<br>+    template <typename T><br>+    bool TraverseNode(T *Node, bool(VisitorBase:: *traverse) (T *)) {<br>
+      if (Node == NULL)<br>+        return true;<br>+      if (ParentStack.size() > 0)<br>+        // FIXME: Currently we add the same parent multiple times, for example<br>+        // when we visit all subexpressions of template instantiations; this is<br>
+        // suboptimal, bug benign: the only way to visit those is with<br>+        // hasAncestor / hasParent, and those do not create new matches.<br>+        // The plan is to enable DynTypedNode to be storable in a map or hash<br>
+        // map. The main problem there is to implement hash functions /<br>+        // comparison operators for all types that DynTypedNode supports that<br>+        // do not have pointer identity.<br>+        (*Parents)[Node].push_back(ParentStack.back());<br>
+      ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));<br>+      bool Result = (this ->* traverse) (Node);<br>+      ParentStack.pop_back();<br>+      return Result;<br>+    }<br>+<br>+    bool TraverseDecl(Decl *DeclNode) {<br>
+      return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);<br>+    }<br>+<br>+    bool TraverseStmt(Stmt *StmtNode) {<br>+      return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);<br>+    }<br>+<br>+    ParentMap *Parents;<br>
+    llvm::SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;<br>+<br>+    friend class RecursiveASTVisitor<ParentMapASTVisitor>;<br>+  };<br>+<br>+  llvm::OwningPtr<ParentMap> AllParents;<br>};<br>
-  <br>+<br>/// \brief Utility function for constructing a nullary selector.<br>static inline Selector GetNullarySelector(StringRef name, ASTContext& Ctx) {<br>  IdentifierInfo* II = &Ctx.Idents.get(name);<br><br>
Copied: cfe/trunk/include/clang/AST/ASTTypeTraits.h (from r176245, cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h)<br>URL:<span> </span><a href="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" target="_blank">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</a><br>
==============================================================================<br>--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)<br>+++ cfe/trunk/include/clang/AST/ASTTypeTraits.h Thu Feb 28 07:21:39 2013<br>
@@ -1,4 +1,4 @@<br>-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//<br>+//===--- ASTTypeTraits.h ----------------------------------------*- C++ -*-===//<br>//<br>//                     The LLVM Compiler Infrastructure<br>
//<br>@@ -12,8 +12,8 @@<br>//<br>//===----------------------------------------------------------------------===//<br><br>-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>
+#ifndef LLVM_CLANG_AST_AST_TYPE_TRAITS_H<br>+#define LLVM_CLANG_AST_AST_TYPE_TRAITS_H<br><br>#include "clang/AST/Decl.h"<br>#include "clang/AST/Stmt.h"<br>@@ -88,8 +88,9 @@ private:<br>  /// guaranteed to be unique pointers pointing to dedicated storage in the<br>
  /// AST. \c QualTypes on the other hand do not have storage or unique<br>  /// pointers and thus need to be stored by value.<br>-  llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc><br>-    Storage;<br>
+  llvm::AlignedCharArrayUnion<Decl *, Stmt *, NestedNameSpecifier,<br>+                              NestedNameSpecifierLoc, QualType, Type,<br>+                              TypeLoc> Storage;<br>};<br><br>// FIXME: Pull out abstraction for the following.<br>
@@ -207,4 +208,4 @@ inline const void *DynTypedNode::getMemo<br>} // end namespace ast_type_traits<br>} // end namespace clang<br><br>-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>+#endif // LLVM_CLANG_AST_AST_TYPE_TRAITS_H<br>
<br>Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h<br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=176251&r1=176250&r2=176251&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=176251&r1=176250&r2=176251&view=diff</a><br>
==============================================================================<br>--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)<br>+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Feb 28 07:21:39 2013<br>
@@ -35,13 +35,13 @@<br>#ifndef LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H<br>#define LLVM_CLANG_AST_MATCHERS_AST_MATCHERS_INTERNAL_H<br><br>-#include "clang/AST/Decl.h"<br>+#include "clang/AST/ASTTypeTraits.h"<br>
#include "clang/AST/DeclCXX.h"<br>+#include "clang/AST/Decl.h"<br>#include "clang/AST/ExprCXX.h"<br>-#include "clang/AST/Stmt.h"<br>#include "clang/AST/StmtCXX.h"<br>+#include "clang/AST/Stmt.h"<br>
#include "clang/AST/Type.h"<br>-#include "clang/ASTMatchers/ASTTypeTraits.h"<br>#include "llvm/ADT/VariadicFunction.h"<br>#include "llvm/Support/type_traits.h"<br>#include <map><br>
<br>Removed: cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h<br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=176250&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h?rev=176250&view=auto</a><br>
==============================================================================<br>--- cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (original)<br>+++ cfe/trunk/include/clang/ASTMatchers/ASTTypeTraits.h (removed)<br>
@@ -1,210 +0,0 @@<br>-//===--- ASTMatchersTypeTraits.h --------------------------------*- C++ -*-===//<br>-//<br>-//                     The LLVM Compiler Infrastructure<br>-//<br>-// This file is distributed under the University of Illinois Open Source<br>
-// License. See LICENSE.TXT for details.<br>-//<br>-//===----------------------------------------------------------------------===//<br>-//<br>-//  Provides a dynamically typed node container that can be used to store<br>
-//  an AST base node at runtime in the same storage in a type safe way.<br>-//<br>-//===----------------------------------------------------------------------===//<br>-<br>-#ifndef LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>
-#define LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br>-<br>-#include "clang/AST/Decl.h"<br>-#include "clang/AST/Stmt.h"<br>-#include "clang/AST/TypeLoc.h"<br>-#include "llvm/Support/AlignOf.h"<br>
-<br>-namespace clang {<br>-namespace ast_type_traits {<br>-<br>-/// \brief A dynamically typed AST node container.<br>-///<br>-/// Stores an AST node in a type safe way. This allows writing code that<br>-/// works with different kinds of AST nodes, despite the fact that they don't<br>
-/// have a common base class.<br>-///<br>-/// Use \c create(Node) to create a \c DynTypedNode from an AST node,<br>-/// and \c get<T>() to retrieve the node as type T if the types match.<br>-///<br>-/// See \c NodeTypeTag for which node base types are currently supported;<br>
-/// You can create DynTypedNodes for all nodes in the inheritance hierarchy of<br>-/// the supported base types.<br>-class DynTypedNode {<br>-public:<br>-  /// \brief Creates a \c DynTypedNode from \c Node.<br>-  template <typename T><br>
-  static DynTypedNode create(const T &Node) {<br>-    return BaseConverter<T>::create(Node);<br>-  }<br>-<br>-  /// \brief Retrieve the stored node as type \c T.<br>-  ///<br>-  /// Returns NULL if the stored node does not have a type that is<br>
-  /// convertible to \c T.<br>-  ///<br>-  /// For types that have identity via their pointer in the AST<br>-  /// (like \c Stmt and \c Decl) the returned pointer points to the<br>-  /// referenced AST node.<br>-  /// For other types (like \c QualType) the value is stored directly<br>
-  /// in the \c DynTypedNode, and the returned pointer points at<br>-  /// the storage inside DynTypedNode. For those nodes, do not<br>-  /// use the pointer outside the scope of the DynTypedNode.<br>-  template <typename T><br>
-  const T *get() const {<br>-    return BaseConverter<T>::get(Tag, Storage.buffer);<br>-  }<br>-<br>-  /// \brief Returns a pointer that identifies the stored AST node.<br>-  ///<br>-  /// Note that this is not supported by all AST nodes. For AST nodes<br>
-  /// that don't have a pointer-defined identity inside the AST, this<br>-  /// method returns NULL.<br>-  const void *getMemoizationData() const;<br>-<br>-private:<br>-  /// \brief Takes care of converting from and to \c T.<br>
-  template <typename T, typename EnablerT = void> struct BaseConverter;<br>-<br>-  /// \brief Supported base node types.<br>-  enum NodeTypeTag {<br>-    NT_Decl,<br>-    NT_Stmt,<br>-    NT_NestedNameSpecifier,<br>
-    NT_NestedNameSpecifierLoc,<br>-    NT_QualType,<br>-    NT_Type,<br>-    NT_TypeLoc<br>-  } Tag;<br>-<br>-  /// \brief Stores the data of the node.<br>-  ///<br>-  /// Note that we can store \c Decls and \c Stmts by pointer as they are<br>
-  /// guaranteed to be unique pointers pointing to dedicated storage in the<br>-  /// AST. \c QualTypes on the other hand do not have storage or unique<br>-  /// pointers and thus need to be stored by value.<br>-  llvm::AlignedCharArrayUnion<Decl*, QualType, TypeLoc, NestedNameSpecifierLoc><br>
-    Storage;<br>-};<br>-<br>-// FIXME: Pull out abstraction for the following.<br>-template<typename T> struct DynTypedNode::BaseConverter<T,<br>-    typename llvm::enable_if<llvm::is_base_of<Decl, T> >::type> {<br>
-  static const T *get(NodeTypeTag Tag, const char Storage[]) {<br>-    if (Tag == NT_Decl)<br>-      return dyn_cast<T>(*reinterpret_cast<Decl*const*>(Storage));<br>-    return NULL;<br>-  }<br>-  static DynTypedNode create(const Decl &Node) {<br>
-    DynTypedNode Result;<br>-    Result.Tag = NT_Decl;<br>-    new (Result.Storage.buffer) const Decl*(&Node);<br>-    return Result;<br>-  }<br>-};<br>-template<typename T> struct DynTypedNode::BaseConverter<T,<br>
-    typename llvm::enable_if<llvm::is_base_of<Stmt, T> >::type> {<br>-  static const T *get(NodeTypeTag Tag, const char Storage[]) {<br>-    if (Tag == NT_Stmt)<br>-      return dyn_cast<T>(*reinterpret_cast<Stmt*const*>(Storage));<br>
-    return NULL;<br>-  }<br>-  static DynTypedNode create(const Stmt &Node) {<br>-    DynTypedNode Result;<br>-    Result.Tag = NT_Stmt;<br>-    new (Result.Storage.buffer) const Stmt*(&Node);<br>-    return Result;<br>
-  }<br>-};<br>-template<typename T> struct DynTypedNode::BaseConverter<T,<br>-    typename llvm::enable_if<llvm::is_base_of<Type, T> >::type> {<br>-  static const T *get(NodeTypeTag Tag, const char Storage[]) {<br>
-    if (Tag == NT_Type)<br>-      return dyn_cast<T>(*reinterpret_cast<Type*const*>(Storage));<br>-    return NULL;<br>-  }<br>-  static DynTypedNode create(const Type &Node) {<br>-    DynTypedNode Result;<br>
-    Result.Tag = NT_Type;<br>-    new (Result.Storage.buffer) const Type*(&Node);<br>-    return Result;<br>-  }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifier, void> {<br>-  static const NestedNameSpecifier *get(NodeTypeTag Tag, const char Storage[]) {<br>
-    if (Tag == NT_NestedNameSpecifier)<br>-      return *reinterpret_cast<NestedNameSpecifier*const*>(Storage);<br>-    return NULL;<br>-  }<br>-  static DynTypedNode create(const NestedNameSpecifier &Node) {<br>
-    DynTypedNode Result;<br>-    Result.Tag = NT_NestedNameSpecifier;<br>-    new (Result.Storage.buffer) const NestedNameSpecifier*(&Node);<br>-    return Result;<br>-  }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<NestedNameSpecifierLoc, void> {<br>
-  static const NestedNameSpecifierLoc *get(NodeTypeTag Tag,<br>-                                           const char Storage[]) {<br>-    if (Tag == NT_NestedNameSpecifierLoc)<br>-      return reinterpret_cast<const NestedNameSpecifierLoc*>(Storage);<br>
-    return NULL;<br>-  }<br>-  static DynTypedNode create(const NestedNameSpecifierLoc &Node) {<br>-    DynTypedNode Result;<br>-    Result.Tag = NT_NestedNameSpecifierLoc;<br>-    new (Result.Storage.buffer) NestedNameSpecifierLoc(Node);<br>
-    return Result;<br>-  }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<QualType, void> {<br>-  static const QualType *get(NodeTypeTag Tag, const char Storage[]) {<br>-    if (Tag == NT_QualType)<br>
-      return reinterpret_cast<const QualType*>(Storage);<br>-    return NULL;<br>-  }<br>-  static DynTypedNode create(const QualType &Node) {<br>-    DynTypedNode Result;<br>-    Result.Tag = NT_QualType;<br>-    new (Result.Storage.buffer) QualType(Node);<br>
-    return Result;<br>-  }<br>-};<br>-template<> struct DynTypedNode::BaseConverter<TypeLoc, void> {<br>-  static const TypeLoc *get(NodeTypeTag Tag, const char Storage[]) {<br>-    if (Tag == NT_TypeLoc)<br>
-      return reinterpret_cast<const TypeLoc*>(Storage);<br>-    return NULL;<br>-  }<br>-  static DynTypedNode create(const TypeLoc &Node) {<br>-    DynTypedNode Result;<br>-    Result.Tag = NT_TypeLoc;<br>-    new (Result.Storage.buffer) TypeLoc(Node);<br>
-    return Result;<br>-  }<br>-};<br>-// The only operation we allow on unsupported types is \c get.<br>-// This allows to conveniently use \c DynTypedNode when having an arbitrary<br>-// AST node that is not supported, but prevents misuse - a user cannot create<br>
-// a DynTypedNode from arbitrary types.<br>-template <typename T, typename EnablerT> struct DynTypedNode::BaseConverter {<br>-  static const T *get(NodeTypeTag Tag, const char Storage[]) { return NULL; }<br>-};<br>
-<br>-inline const void *DynTypedNode::getMemoizationData() const {<br>-  switch (Tag) {<br>-    case NT_Decl: return BaseConverter<Decl>::get(Tag, Storage.buffer);<br>-    case NT_Stmt: return BaseConverter<Stmt>::get(Tag, Storage.buffer);<br>
-    default: return NULL;<br>-  };<br>-}<br>-<br>-} // end namespace ast_type_traits<br>-} // end namespace clang<br>-<br>-#endif // LLVM_CLANG_AST_MATCHERS_AST_TYPE_TRAITS_H<br><br>Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp<br>
URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=176251&r1=176250&r2=176251&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=176251&r1=176250&r2=176251&view=diff</a><br>
==============================================================================<br>--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)<br>+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Feb 28 07:21:39 2013<br>
@@ -29,76 +29,6 @@ namespace {<br><br>typedef MatchFinder::MatchCallback MatchCallback;<br><br>-/// \brief A \c RecursiveASTVisitor that builds a map from nodes to their<br>-/// parents as defined by the \c RecursiveASTVisitor.<br>
-///<br>-/// Note that the relationship described here is purely in terms of AST<br>-/// traversal - there are other relationships (for example declaration context)<br>-/// in the AST that are better modeled by special matchers.<br>
-///<br>-/// FIXME: Currently only builds up the map using \c Stmt and \c Decl nodes.<br>-class ParentMapASTVisitor : public RecursiveASTVisitor<ParentMapASTVisitor> {<br>-public:<br>-  /// \brief Contains parents of a node.<br>
-  typedef SmallVector<ast_type_traits::DynTypedNode, 1> ParentVector;<br>-<br>-  /// \brief Maps from a node to its parents.<br>-  typedef llvm::DenseMap<const void *, ParentVector> ParentMap;<br>-<br>-  /// \brief Builds and returns the translation unit's parent map.<br>
-  ///<br>-  ///  The caller takes ownership of the returned \c ParentMap.<br>-  static ParentMap *buildMap(TranslationUnitDecl &TU) {<br>-    ParentMapASTVisitor Visitor(new ParentMap);<br>-    Visitor.TraverseDecl(&TU);<br>
-    return Visitor.Parents;<br>-  }<br>-<br>-private:<br>-  typedef RecursiveASTVisitor<ParentMapASTVisitor> VisitorBase;<br>-<br>-  ParentMapASTVisitor(ParentMap *Parents) : Parents(Parents) {}<br>-<br>-  bool shouldVisitTemplateInstantiations() const { return true; }<br>
-  bool shouldVisitImplicitCode() const { return true; }<br>-  // Disables data recursion. We intercept Traverse* methods in the RAV, which<br>-  // are not triggered during data recursion.<br>-  bool shouldUseDataRecursionFor(clang::Stmt *S) const { return false; }<br>
-<br>-  template <typename T><br>-  bool TraverseNode(T *Node, bool (VisitorBase::*traverse)(T*)) {<br>-    if (Node == NULL)<br>-      return true;<br>-    if (ParentStack.size() > 0)<br>-      // FIXME: Currently we add the same parent multiple times, for example<br>
-      // when we visit all subexpressions of template instantiations; this is<br>-      // suboptimal, bug benign: the only way to visit those is with<br>-      // hasAncestor / hasParent, and those do not create new matches.<br>
-      // The plan is to enable DynTypedNode to be storable in a map or hash<br>-      // map. The main problem there is to implement hash functions /<br>-      // comparison operators for all types that DynTypedNode supports that<br>
-      // do not have pointer identity.<br>-      (*Parents)[Node].push_back(ParentStack.back());<br>-    ParentStack.push_back(ast_type_traits::DynTypedNode::create(*Node));<br>-    bool Result = (this->*traverse)(Node);<br>
-    ParentStack.pop_back();<br>-    return Result;<br>-  }<br>-<br>-  bool TraverseDecl(Decl *DeclNode) {<br>-    return TraverseNode(DeclNode, &VisitorBase::TraverseDecl);<br>-  }<br>-<br>-  bool TraverseStmt(Stmt *StmtNode) {<br>
-    return TraverseNode(StmtNode, &VisitorBase::TraverseStmt);<br>-  }<br>-<br>-  ParentMap *Parents;<br>-  SmallVector<ast_type_traits::DynTypedNode, 16> ParentStack;<br>-<br>-  friend class RecursiveASTVisitor<ParentMapASTVisitor>;<br>
-};<br>-<br>// We use memoization to avoid running the same matcher on the same<br>// AST node twice.  This pair is the key for looking up match<br>// result.  It consists of an ID of the MatcherInterface (for<br>@@ -458,12 +388,6 @@ public:<br>
                                 const DynTypedMatcher &Matcher,<br>                                 BoundNodesTreeBuilder *Builder,<br>                                 AncestorMatchMode MatchMode) {<br>-    if (!Parents) {<br>
-      // We always need to run over the whole translation unit, as<br>-      // \c hasAncestor can escape any subtree.<br>-      Parents.reset(ParentMapASTVisitor::buildMap(<br>-        *ActiveASTContext->getTranslationUnitDecl()));<br>
-    }<br>    return matchesAncestorOfRecursively(Node, Matcher, Builder, MatchMode);<br>  }<br><br>@@ -506,22 +430,21 @@ private:<br>    assert(Node.getMemoizationData() &&<br>           "Invariant broken: only nodes that support memoization may be "<br>
           "used in the parent map.");<br>-    ParentMapASTVisitor::ParentMap::const_iterator I =<br>-        Parents->find(Node.getMemoizationData());<br>-    if (I == Parents->end()) {<br>+    ASTContext::ParentVector Parents = ActiveASTContext->getParents(Node);<br>
+    if (Parents.empty()) {<br>      assert(false && "Found node that is not in the parent map.");<br>      return false;<br>    }<br>-    for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =<br>
-             I->second.begin(), AncestorE = I->second.end();<br>+    for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),<br>+                                                  AncestorE = Parents.end();<br>
         AncestorI != AncestorE; ++AncestorI) {<br>      if (Matcher.matches(*AncestorI, this, Builder))<br>        return true;<br>    }<br>    if (MatchMode == ASTMatchFinder::AMM_ParentOnly)<br>      return false;<br>-    for (ParentMapASTVisitor::ParentVector::const_iterator AncestorI =<br>
-             I->second.begin(), AncestorE = I->second.end();<br>+    for (ASTContext::ParentVector::const_iterator AncestorI = Parents.begin(),<br>+                                                  AncestorE = Parents.end();<br>
         AncestorI != AncestorE; ++AncestorI) {<br>      if (matchesAncestorOfRecursively(*AncestorI, Matcher, Builder, MatchMode))<br>        return true;<br>@@ -574,8 +497,6 @@ private:<br>  // Maps (matcher, node) -> the match result for memoization.<br>
  typedef llvm::DenseMap<UntypedMatchInput, MemoizedMatchResult> MemoizationMap;<br>  MemoizationMap ResultCache;<br>-<br>-  OwningPtr<ParentMapASTVisitor::ParentMap> Parents;<br>};<br><br>// Returns true if the given class is directly or indirectly derived<br>
<br>Added: cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp<br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp?rev=176251&view=auto" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp?rev=176251&view=auto</a><br>
==============================================================================<br>--- cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp (added)<br>+++ cfe/trunk/unittests/AST/ASTContextParentMapTest.cpp Thu Feb 28 07:21:39 2013<br>
@@ -0,0 +1,71 @@<br>+//===- unittest/AST/ASTContextParentMapTest.cpp - AST parent map test -----===//<br>+//<br>+//                     The LLVM Compiler Infrastructure<br>+//<br>+// This file is distributed under the University of Illinois Open Source<br>
+// License. See LICENSE.TXT for details.<br>+//<br>+//===----------------------------------------------------------------------===//<br>+//<br>+// Tests for the getParents(...) methods of ASTContext.<br>+//<br>+//===----------------------------------------------------------------------===//<br>
+<br>+#include "clang/AST/ASTContext.h"<br>+#include "clang/ASTMatchers/ASTMatchFinder.h"<br>+#include "clang/ASTMatchers/ASTMatchers.h"<br>+#include "clang/Tooling/Tooling.h"<br>+#include "gtest/gtest.h"<br>
+#include "MatchVerifier.h"<br>+<br>+namespace clang {<br>+namespace ast_matchers {<br>+<br>+using clang::tooling::newFrontendActionFactory;<br>+using clang::tooling::runToolOnCodeWithArgs;<br>+using clang::tooling::FrontendActionFactory;<br>
+<br>+TEST(GetParents, ReturnsParentForDecl) {<br>+  MatchVerifier<Decl> Verifier;<br>+  EXPECT_TRUE(Verifier.match("class C { void f(); };",<br>+                             methodDecl(hasParent(recordDecl(hasName("C"))))));<br>
+}<br>+<br>+TEST(GetParents, ReturnsParentForStmt) {<br>+  MatchVerifier<Stmt> Verifier;<br>+  EXPECT_TRUE(Verifier.match("class C { void f() { if (true) {} } };",<br>+                             ifStmt(hasParent(compoundStmt()))));<br>
+}<br>+<br>+TEST(GetParents, ReturnsParentInsideTemplateInstantiations) {<br>+  MatchVerifier<Decl> DeclVerifier;<br>+  EXPECT_TRUE(DeclVerifier.match(<br>+      "template<typename T> struct C { void f() {} };"<br>
+      "void g() { C<int> c; c.f(); }",<br>+      methodDecl(hasName("f"),<br>+                 hasParent(recordDecl(isTemplateInstantiation())))));<br>+  EXPECT_TRUE(DeclVerifier.match(<br>+      "template<typename T> struct C { void f() {} };"<br>
+      "void g() { C<int> c; c.f(); }",<br>+      methodDecl(hasName("f"),<br>+                 hasParent(recordDecl(unless(isTemplateInstantiation()))))));<br>+  EXPECT_FALSE(DeclVerifier.match(<br>
+      "template<typename T> struct C { void f() {} };"<br>+      "void g() { C<int> c; c.f(); }",<br>+      methodDecl(hasName("f"),<br>+                 allOf(hasParent(recordDecl(unless(isTemplateInstantiation()))),<br>
+                       hasParent(recordDecl(isTemplateInstantiation()))))));<br>+}<br>+<br>+TEST(GetParents, ReturnsMultipleParentsInTemplateInstantiations) {<br>+  MatchVerifier<Stmt> TemplateVerifier;<br>+  EXPECT_TRUE(TemplateVerifier.match(<br>
+      "template<typename T> struct C { void f() {} };"<br>+      "void g() { C<int> c; c.f(); }",<br>+      compoundStmt(<br>+          allOf(hasAncestor(recordDecl(isTemplateInstantiation())),<br>
+                hasAncestor(recordDecl(unless(isTemplateInstantiation())))))));<br>+}<br>+<br>+} // end namespace ast_matchers<br>+} // end namespace clang<br><br>Modified: cfe/trunk/unittests/AST/CMakeLists.txt<br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=176251&r1=176250&r2=176251&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/CMakeLists.txt?rev=176251&r1=176250&r2=176251&view=diff</a><br>
==============================================================================<br>--- cfe/trunk/unittests/AST/CMakeLists.txt (original)<br>+++ cfe/trunk/unittests/AST/CMakeLists.txt Thu Feb 28 07:21:39 2013<br>@@ -1,4 +1,5 @@<br>
add_clang_unittest(ASTTests<br>+  ASTContextParentMapTest.cpp<br>  CommentLexer.cpp<br>  CommentParser.cpp<br>  DeclPrinterTest.cpp<br><br>Modified: cfe/trunk/unittests/AST/MatchVerifier.h<br>URL:<span> </span><a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/MatchVerifier.h?rev=176251&r1=176250&r2=176251&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/AST/MatchVerifier.h?rev=176251&r1=176250&r2=176251&view=diff</a><br>
==============================================================================<br>--- cfe/trunk/unittests/AST/MatchVerifier.h (original)<br>+++ cfe/trunk/unittests/AST/MatchVerifier.h Thu Feb 28 07:21:39 2013<br>@@ -44,7 +44,7 @@ public:<br>
protected:<br>  virtual void run(const MatchFinder::MatchResult &Result);<br>  virtual void verify(const MatchFinder::MatchResult &Result,<br>-                      const NodeType &Node) = 0;<br>+                      const NodeType &Node) {}<br>
<br>  void setFailure(const Twine &Result) {<br>    Verified = false;<br><br><br>_______________________________________________<br>cfe-commits mailing list<br><a href="mailto:cfe-commits@cs.uiuc.edu" target="_blank">cfe-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits</a></div></blockquote></div><br></div></div></div></div></blockquote></div><br></div>