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

Anna Zaks ganna at apple.com
Thu Feb 28 09:55:53 PST 2013


Manuel,

This commit has caused breakage on our internal MSVC buildbot:

279>.\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1715) : error C2872: 'clang' : ambiguous symbol
279>        could be 'clang'
279>        or       'clang::ento::clang'
279>        .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1688) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseFunctionHelper(clang::FunctionDecl *)'
279>        with
279>        [
279>            Derived=clang::ASTContext::ParentMapASTVisitor
279>        ]
279>        .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(1840) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseGCCAsmStmt(clang::GCCAsmStmt *)'
279>        with
279>        [
279>            Derived=clang::ASTContext::ParentMapASTVisitor
279>        ]
279>        .\llvm\tools\clang\include\clang/AST/RecursiveASTVisitor.h(522) : while compiling class template member function 'bool clang::RecursiveASTVisitor<Derived>::TraverseStmt(clang::Stmt *)'
279>        with
279>        [
279>            Derived=clang::ASTContext::ParentMapASTVisitor
279>        ]
279>        .\llvm\tools\clang\include\clang/AST/ASTContext.h(2202) : see reference to class template instantiation 'clang::RecursiveASTVisitor<Derived>' being compiled
279>        with
279>        [
279>            Derived=clang::ASTContext::ParentMapASTVisitor
279>        ]
275>   Creating library .\llvm\build\lib\Debug\clang-check.lib and object .\llvm\build\lib\Debug\clang-check.exp
2
On Feb 28, 2013, at 5:21 AM, Manuel Klimek <klimek at google.com> wrote:

> 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;
> 
> 
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130228/a4e12d53/attachment.html>


More information about the cfe-commits mailing list