//===- 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, std::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 {
 
  union {
 
    DynTypedNode SingleNode;
 
    ArrayRef<DynTypedNode> Nodes;
 
  };
 
  bool IsSingleNode;
 
 
 
public:
 
  DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) {
 
    new (&SingleNode) DynTypedNode(N);
 
  }
 
 
 
  DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) {
 
    new (&Nodes) ArrayRef<DynTypedNode>(A);
 
  }
 
 
 
  const DynTypedNode *begin() const {
 
    return !IsSingleNode ? Nodes.begin() : &SingleNode;
 
  }
 
 
 
  const DynTypedNode *end() const {
 
    return !IsSingleNode ? Nodes.end() : &SingleNode + 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