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