ParentMapContext.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- ParentMapContext.h - Map of parents using DynTypedNode -------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // Similar to ParentMap.h, but generalizes to non-Stmt nodes, which can have
  15. // multiple parents.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_CLANG_AST_PARENTMAPCONTEXT_H
  19. #define LLVM_CLANG_AST_PARENTMAPCONTEXT_H
  20. #include "clang/AST/ASTContext.h"
  21. #include "clang/AST/ASTTypeTraits.h"
  22. namespace clang {
  23. class DynTypedNodeList;
  24. class ParentMapContext {
  25. public:
  26. ParentMapContext(ASTContext &Ctx);
  27. ~ParentMapContext();
  28. /// Returns the parents of the given node (within the traversal scope).
  29. ///
  30. /// Note that this will lazily compute the parents of all nodes
  31. /// and store them for later retrieval. Thus, the first call is O(n)
  32. /// in the number of AST nodes.
  33. ///
  34. /// Caveats and FIXMEs:
  35. /// Calculating the parent map over all AST nodes will need to load the
  36. /// full AST. This can be undesirable in the case where the full AST is
  37. /// expensive to create (for example, when using precompiled header
  38. /// preambles). Thus, there are good opportunities for optimization here.
  39. /// One idea is to walk the given node downwards, looking for references
  40. /// to declaration contexts - once a declaration context is found, compute
  41. /// the parent map for the declaration context; if that can satisfy the
  42. /// request, loading the whole AST can be avoided. Note that this is made
  43. /// more complex by statements in templates having multiple parents - those
  44. /// problems can be solved by building closure over the templated parts of
  45. /// the AST, which also avoids touching large parts of the AST.
  46. /// Additionally, we will want to add an interface to already give a hint
  47. /// where to search for the parents, for example when looking at a statement
  48. /// inside a certain function.
  49. ///
  50. /// 'NodeT' can be one of Decl, Stmt, Type, TypeLoc,
  51. /// NestedNameSpecifier or NestedNameSpecifierLoc.
  52. template <typename NodeT> DynTypedNodeList getParents(const NodeT &Node);
  53. DynTypedNodeList getParents(const DynTypedNode &Node);
  54. /// Clear parent maps.
  55. void clear();
  56. TraversalKind getTraversalKind() const { return Traversal; }
  57. void setTraversalKind(TraversalKind TK) { Traversal = TK; }
  58. const Expr *traverseIgnored(const Expr *E) const;
  59. Expr *traverseIgnored(Expr *E) const;
  60. DynTypedNode traverseIgnored(const DynTypedNode &N) const;
  61. class ParentMap;
  62. private:
  63. ASTContext &ASTCtx;
  64. TraversalKind Traversal = TK_AsIs;
  65. std::unique_ptr<ParentMap> Parents;
  66. };
  67. class TraversalKindScope {
  68. ParentMapContext &Ctx;
  69. TraversalKind TK = TK_AsIs;
  70. public:
  71. TraversalKindScope(ASTContext &ASTCtx, std::optional<TraversalKind> ScopeTK)
  72. : Ctx(ASTCtx.getParentMapContext()) {
  73. TK = Ctx.getTraversalKind();
  74. if (ScopeTK)
  75. Ctx.setTraversalKind(*ScopeTK);
  76. }
  77. ~TraversalKindScope() { Ctx.setTraversalKind(TK); }
  78. };
  79. /// Container for either a single DynTypedNode or for an ArrayRef to
  80. /// DynTypedNode. For use with ParentMap.
  81. class DynTypedNodeList {
  82. union {
  83. DynTypedNode SingleNode;
  84. ArrayRef<DynTypedNode> Nodes;
  85. };
  86. bool IsSingleNode;
  87. public:
  88. DynTypedNodeList(const DynTypedNode &N) : IsSingleNode(true) {
  89. new (&SingleNode) DynTypedNode(N);
  90. }
  91. DynTypedNodeList(ArrayRef<DynTypedNode> A) : IsSingleNode(false) {
  92. new (&Nodes) ArrayRef<DynTypedNode>(A);
  93. }
  94. const DynTypedNode *begin() const {
  95. return !IsSingleNode ? Nodes.begin() : &SingleNode;
  96. }
  97. const DynTypedNode *end() const {
  98. return !IsSingleNode ? Nodes.end() : &SingleNode + 1;
  99. }
  100. size_t size() const { return end() - begin(); }
  101. bool empty() const { return begin() == end(); }
  102. const DynTypedNode &operator[](size_t N) const {
  103. assert(N < size() && "Out of bounds!");
  104. return *(begin() + N);
  105. }
  106. };
  107. template <typename NodeT>
  108. inline DynTypedNodeList ParentMapContext::getParents(const NodeT &Node) {
  109. return getParents(DynTypedNode::create(Node));
  110. }
  111. template <typename NodeT>
  112. inline DynTypedNodeList ASTContext::getParents(const NodeT &Node) {
  113. return getParentMapContext().getParents(Node);
  114. }
  115. template <>
  116. inline DynTypedNodeList ASTContext::getParents(const DynTypedNode &Node) {
  117. return getParentMapContext().getParents(Node);
  118. }
  119. } // namespace clang
  120. #endif
  121. #ifdef __GNUC__
  122. #pragma GCC diagnostic pop
  123. #endif