blob: 2edbc987850d23f0fd03cb7ddb32615fa3b9f80f [file] [log] [blame]
//===- 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