| //===- ParentMapContext.h - Map of parents using DynTypedNode -------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Similar to ParentMap.h, but generalizes to non-Stmt nodes, which can have |
| // multiple parents. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_CLANG_AST_PARENTMAPCONTEXT_H |
| #define LLVM_CLANG_AST_PARENTMAPCONTEXT_H |
| |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTTypeTraits.h" |
| |
| namespace clang { |
| class DynTypedNodeList; |
| |
| class ParentMapContext { |
| public: |
| ParentMapContext(ASTContext &Ctx); |
| |
| ~ParentMapContext(); |
| |
| /// Returns the parents of the given node (within the traversal scope). |
| /// |
| /// 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> DynTypedNodeList getParents(const NodeT &Node); |
| |
| DynTypedNodeList getParents(const DynTypedNode &Node); |
| |
| /// Clear parent maps. |
| void clear(); |
| |
| TraversalKind getTraversalKind() const { return Traversal; } |
| void setTraversalKind(TraversalKind TK) { Traversal = TK; } |
| |
| const Expr *traverseIgnored(const Expr *E) const; |
| Expr *traverseIgnored(Expr *E) const; |
| DynTypedNode traverseIgnored(const DynTypedNode &N) const; |
| |
| class ParentMap; |
| |
| private: |
| ASTContext &ASTCtx; |
| TraversalKind Traversal = TK_AsIs; |
| std::unique_ptr<ParentMap> Parents; |
| }; |
| |
| class TraversalKindScope { |
| ParentMapContext &Ctx; |
| TraversalKind TK = TK_AsIs; |
| |
| public: |
| TraversalKindScope(ASTContext &ASTCtx, llvm::Optional<TraversalKind> ScopeTK) |
| : Ctx(ASTCtx.getParentMapContext()) { |
| TK = Ctx.getTraversalKind(); |
| if (ScopeTK) |
| Ctx.setTraversalKind(*ScopeTK); |
| } |
| |
| ~TraversalKindScope() { Ctx.setTraversalKind(TK); } |
| }; |
| |
| /// Container for either a single DynTypedNode or for an ArrayRef to |
| /// DynTypedNode. For use with ParentMap. |
| class DynTypedNodeList { |
| llvm::AlignedCharArrayUnion<DynTypedNode, ArrayRef<DynTypedNode>> Storage; |
| bool IsSingleNode; |
| |
| public: |
| DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) { |
| new (&Storage) DynTypedNode(N); |
| } |
| |
| DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) { |
| new (&Storage) ArrayRef<DynTypedNode>(A); |
| } |
| |
| const DynTypedNode *begin() const { |
| if (!IsSingleNode) |
| return reinterpret_cast<const ArrayRef<DynTypedNode> *>(&Storage) |
| ->begin(); |
| return reinterpret_cast<const DynTypedNode *>(&Storage); |
| } |
| |
| const DynTypedNode *end() const { |
| if (!IsSingleNode) |
| return reinterpret_cast<const ArrayRef<DynTypedNode> *>(&Storage)->end(); |
| return reinterpret_cast<const DynTypedNode *>(&Storage) + 1; |
| } |
| |
| size_t size() const { return end() - begin(); } |
| bool empty() const { return begin() == end(); } |
| |
| const DynTypedNode &operator[](size_t N) const { |
| assert(N < size() && "Out of bounds!"); |
| return *(begin() + N); |
| } |
| }; |
| |
| template <typename NodeT> |
| inline DynTypedNodeList ParentMapContext::getParents(const NodeT &Node) { |
| return getParents(DynTypedNode::create(Node)); |
| } |
| |
| template <typename NodeT> |
| inline DynTypedNodeList ASTContext::getParents(const NodeT &Node) { |
| return getParentMapContext().getParents(Node); |
| } |
| |
| template <> |
| inline DynTypedNodeList ASTContext::getParents(const DynTypedNode &Node) { |
| return getParentMapContext().getParents(Node); |
| } |
| |
| } // namespace clang |
| |
| #endif |