Tree.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. //===- Tree.cpp -----------------------------------------------*- C++ -*-=====//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/Tooling/Syntax/Tree.h"
  9. #include "clang/Basic/TokenKinds.h"
  10. #include "clang/Tooling/Syntax/Nodes.h"
  11. #include "llvm/ADT/ArrayRef.h"
  12. #include "llvm/ADT/STLExtras.h"
  13. #include "llvm/Support/Casting.h"
  14. using namespace clang;
  15. syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
  16. TokenBuffer Tokens)
  17. : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {}
  18. const clang::syntax::TokenBuffer &syntax::Arena::tokenBuffer() const {
  19. return Tokens;
  20. }
  21. std::pair<FileID, llvm::ArrayRef<syntax::Token>>
  22. syntax::Arena::lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Input) {
  23. auto FID = SourceMgr.createFileID(std::move(Input));
  24. auto It = ExtraTokens.try_emplace(FID, tokenize(FID, SourceMgr, LangOpts));
  25. assert(It.second && "duplicate FileID");
  26. return {FID, It.first->second};
  27. }
  28. syntax::Leaf::Leaf(const syntax::Token *Tok) : Node(NodeKind::Leaf), Tok(Tok) {
  29. assert(Tok != nullptr);
  30. }
  31. bool syntax::Leaf::classof(const Node *N) {
  32. return N->kind() == NodeKind::Leaf;
  33. }
  34. syntax::Node::Node(NodeKind Kind)
  35. : Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
  36. Role(static_cast<unsigned>(NodeRole::Detached)) {}
  37. bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; }
  38. void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
  39. assert(Child->Parent == nullptr);
  40. assert(Child->NextSibling == nullptr);
  41. assert(Child->role() == NodeRole::Detached);
  42. assert(Role != NodeRole::Detached);
  43. Child->Parent = this;
  44. Child->NextSibling = this->FirstChild;
  45. Child->Role = static_cast<unsigned>(Role);
  46. this->FirstChild = Child;
  47. }
  48. namespace {
  49. static void traverse(const syntax::Node *N,
  50. llvm::function_ref<void(const syntax::Node *)> Visit) {
  51. if (auto *T = dyn_cast<syntax::Tree>(N)) {
  52. for (auto *C = T->firstChild(); C; C = C->nextSibling())
  53. traverse(C, Visit);
  54. }
  55. Visit(N);
  56. }
  57. static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens,
  58. const SourceManager &SM) {
  59. assert(!Tokens.empty());
  60. bool First = true;
  61. for (const auto &T : Tokens) {
  62. if (!First)
  63. OS << " ";
  64. else
  65. First = false;
  66. // Handle 'eof' separately, calling text() on it produces an empty string.
  67. if (T.kind() == tok::eof) {
  68. OS << "<eof>";
  69. continue;
  70. }
  71. OS << T.text(SM);
  72. }
  73. }
  74. static void dumpTree(llvm::raw_ostream &OS, const syntax::Node *N,
  75. const syntax::Arena &A, std::vector<bool> IndentMask) {
  76. if (N->role() != syntax::NodeRole::Unknown) {
  77. // FIXME: print the symbolic name of a role.
  78. if (N->role() == syntax::NodeRole::Detached)
  79. OS << "*: ";
  80. else
  81. OS << static_cast<int>(N->role()) << ": ";
  82. }
  83. if (auto *L = llvm::dyn_cast<syntax::Leaf>(N)) {
  84. dumpTokens(OS, *L->token(), A.sourceManager());
  85. OS << "\n";
  86. return;
  87. }
  88. auto *T = llvm::cast<syntax::Tree>(N);
  89. OS << T->kind() << "\n";
  90. for (auto It = T->firstChild(); It != nullptr; It = It->nextSibling()) {
  91. for (bool Filled : IndentMask) {
  92. if (Filled)
  93. OS << "| ";
  94. else
  95. OS << " ";
  96. }
  97. if (!It->nextSibling()) {
  98. OS << "`-";
  99. IndentMask.push_back(false);
  100. } else {
  101. OS << "|-";
  102. IndentMask.push_back(true);
  103. }
  104. dumpTree(OS, It, A, IndentMask);
  105. IndentMask.pop_back();
  106. }
  107. }
  108. } // namespace
  109. std::string syntax::Node::dump(const Arena &A) const {
  110. std::string Str;
  111. llvm::raw_string_ostream OS(Str);
  112. dumpTree(OS, this, A, /*IndentMask=*/{});
  113. return std::move(OS.str());
  114. }
  115. std::string syntax::Node::dumpTokens(const Arena &A) const {
  116. std::string Storage;
  117. llvm::raw_string_ostream OS(Storage);
  118. traverse(this, [&](const syntax::Node *N) {
  119. auto *L = llvm::dyn_cast<syntax::Leaf>(N);
  120. if (!L)
  121. return;
  122. ::dumpTokens(OS, *L->token(), A.sourceManager());
  123. });
  124. return OS.str();
  125. }
  126. syntax::Node *syntax::Tree::findChild(NodeRole R) {
  127. for (auto *C = FirstChild; C; C = C->nextSibling()) {
  128. if (C->role() == R)
  129. return C;
  130. }
  131. return nullptr;
  132. }