1 //===- Tree.cpp -----------------------------------------------*- C++ -*-=====//
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
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"
15 using namespace clang;
17 syntax::Arena::Arena(SourceManager &SourceMgr, const LangOptions &LangOpts,
19 : SourceMgr(SourceMgr), LangOpts(LangOpts), Tokens(std::move(Tokens)) {}
21 const clang::syntax::TokenBuffer &syntax::Arena::tokenBuffer() const {
25 std::pair<FileID, llvm::ArrayRef<syntax::Token>>
26 syntax::Arena::lexBuffer(std::unique_ptr<llvm::MemoryBuffer> Input) {
27 auto FID = SourceMgr.createFileID(std::move(Input));
28 auto It = ExtraTokens.try_emplace(FID, tokenize(FID, SourceMgr, LangOpts));
29 assert(It.second && "duplicate FileID");
30 return {FID, It.first->second};
33 syntax::Leaf::Leaf(const syntax::Token *Tok) : Node(NodeKind::Leaf), Tok(Tok) {
34 assert(Tok != nullptr);
37 bool syntax::Leaf::classof(const Node *N) {
38 return N->kind() == NodeKind::Leaf;
41 syntax::Node::Node(NodeKind Kind)
42 : Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
43 Role(static_cast<unsigned>(NodeRole::Detached)) {}
45 bool syntax::Tree::classof(const Node *N) { return N->kind() > NodeKind::Leaf; }
47 void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
48 assert(Child->Parent == nullptr);
49 assert(Child->NextSibling == nullptr);
50 assert(Child->role() == NodeRole::Detached);
51 assert(Role != NodeRole::Detached);
54 Child->NextSibling = this->FirstChild;
55 Child->Role = static_cast<unsigned>(Role);
56 this->FirstChild = Child;
60 static void traverse(const syntax::Node *N,
61 llvm::function_ref<void(const syntax::Node *)> Visit) {
62 if (auto *T = dyn_cast<syntax::Tree>(N)) {
63 for (auto *C = T->firstChild(); C; C = C->nextSibling())
68 static void dumpTokens(llvm::raw_ostream &OS, ArrayRef<syntax::Token> Tokens,
69 const SourceManager &SM) {
70 assert(!Tokens.empty());
72 for (const auto &T : Tokens) {
77 // Handle 'eof' separately, calling text() on it produces an empty string.
78 if (T.kind() == tok::eof) {
86 static void dumpTree(llvm::raw_ostream &OS, const syntax::Node *N,
87 const syntax::Arena &A, std::vector<bool> IndentMask) {
88 if (N->role() != syntax::NodeRole::Unknown) {
89 // FIXME: print the symbolic name of a role.
90 if (N->role() == syntax::NodeRole::Detached)
93 OS << static_cast<int>(N->role()) << ": ";
95 if (auto *L = llvm::dyn_cast<syntax::Leaf>(N)) {
96 dumpTokens(OS, *L->token(), A.sourceManager());
101 auto *T = llvm::cast<syntax::Tree>(N);
102 OS << T->kind() << "\n";
104 for (auto It = T->firstChild(); It != nullptr; It = It->nextSibling()) {
105 for (bool Filled : IndentMask) {
111 if (!It->nextSibling()) {
113 IndentMask.push_back(false);
116 IndentMask.push_back(true);
118 dumpTree(OS, It, A, IndentMask);
119 IndentMask.pop_back();
124 std::string syntax::Node::dump(const Arena &A) const {
126 llvm::raw_string_ostream OS(Str);
127 dumpTree(OS, this, A, /*IndentMask=*/{});
128 return std::move(OS.str());
131 std::string syntax::Node::dumpTokens(const Arena &A) const {
133 llvm::raw_string_ostream OS(Storage);
134 traverse(this, [&](const syntax::Node *N) {
135 auto *L = llvm::dyn_cast<syntax::Leaf>(N);
138 ::dumpTokens(OS, *L->token(), A.sourceManager());
143 syntax::Node *syntax::Tree::findChild(NodeRole R) {
144 for (auto *C = FirstChild; C; C = C->nextSibling()) {