Path: blob/main/contrib/llvm-project/clang/lib/Tooling/Syntax/Tree.cpp
35271 views
//===- Tree.cpp -----------------------------------------------*- C++ -*-=====//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7#include "clang/Tooling/Syntax/Tree.h"8#include "clang/Basic/TokenKinds.h"9#include "clang/Tooling/Syntax/Nodes.h"10#include "llvm/ADT/BitVector.h"11#include "llvm/Support/raw_ostream.h"12#include "llvm/Support/Casting.h"13#include <cassert>1415using namespace clang;1617namespace {18static void traverse(const syntax::Node *N,19llvm::function_ref<void(const syntax::Node *)> Visit) {20if (auto *T = dyn_cast<syntax::Tree>(N)) {21for (const syntax::Node &C : T->getChildren())22traverse(&C, Visit);23}24Visit(N);25}26static void traverse(syntax::Node *N,27llvm::function_ref<void(syntax::Node *)> Visit) {28traverse(static_cast<const syntax::Node *>(N), [&](const syntax::Node *N) {29Visit(const_cast<syntax::Node *>(N));30});31}32} // namespace3334syntax::Leaf::Leaf(syntax::TokenManager::Key K) : Node(NodeKind::Leaf), K(K) {}3536syntax::Node::Node(NodeKind Kind)37: Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),38Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),39CanModify(false) {40this->setRole(NodeRole::Detached);41}4243bool syntax::Node::isDetached() const {44return getRole() == NodeRole::Detached;45}4647void syntax::Node::setRole(NodeRole NR) {48this->Role = static_cast<unsigned>(NR);49}5051void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {52assert(Child->getRole() == NodeRole::Detached);53assert(Role != NodeRole::Detached);5455Child->setRole(Role);56appendChildLowLevel(Child);57}5859void syntax::Tree::appendChildLowLevel(Node *Child) {60assert(Child->Parent == nullptr);61assert(Child->NextSibling == nullptr);62assert(Child->PreviousSibling == nullptr);63assert(Child->getRole() != NodeRole::Detached);6465Child->Parent = this;66if (this->LastChild) {67Child->PreviousSibling = this->LastChild;68this->LastChild->NextSibling = Child;69} else70this->FirstChild = Child;7172this->LastChild = Child;73}7475void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {76assert(Child->getRole() == NodeRole::Detached);77assert(Role != NodeRole::Detached);7879Child->setRole(Role);80prependChildLowLevel(Child);81}8283void syntax::Tree::prependChildLowLevel(Node *Child) {84assert(Child->Parent == nullptr);85assert(Child->NextSibling == nullptr);86assert(Child->PreviousSibling == nullptr);87assert(Child->getRole() != NodeRole::Detached);8889Child->Parent = this;90if (this->FirstChild) {91Child->NextSibling = this->FirstChild;92this->FirstChild->PreviousSibling = Child;93} else94this->LastChild = Child;9596this->FirstChild = Child;97}9899void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,100Node *New) {101assert((!Begin || Begin->Parent == this) &&102"`Begin` is not a child of `this`.");103assert((!End || End->Parent == this) && "`End` is not a child of `this`.");104assert(canModify() && "Cannot modify `this`.");105106#ifndef NDEBUG107for (auto *N = New; N; N = N->NextSibling) {108assert(N->Parent == nullptr);109assert(N->getRole() != NodeRole::Detached && "Roles must be set");110// FIXME: validate the role.111}112113auto Reachable = [](Node *From, Node *N) {114if (!N)115return true;116for (auto *It = From; It; It = It->NextSibling)117if (It == N)118return true;119return false;120};121assert(Reachable(FirstChild, Begin) && "`Begin` is not reachable.");122assert(Reachable(Begin, End) && "`End` is not after `Begin`.");123#endif124125if (!New && Begin == End)126return;127128// Mark modification.129for (auto *T = this; T && T->Original; T = T->Parent)130T->Original = false;131132// Save the node before the range to be removed. Later we insert the `New`133// range after this node.134auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;135136// Detach old nodes.137for (auto *N = Begin; N != End;) {138auto *Next = N->NextSibling;139140N->setRole(NodeRole::Detached);141N->Parent = nullptr;142N->NextSibling = nullptr;143N->PreviousSibling = nullptr;144if (N->Original)145traverse(N, [](Node *C) { C->Original = false; });146147N = Next;148}149150// Attach new range.151auto *&NewFirst = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;152auto *&NewLast = End ? End->PreviousSibling : LastChild;153154if (!New) {155NewFirst = End;156NewLast = BeforeBegin;157return;158}159160New->PreviousSibling = BeforeBegin;161NewFirst = New;162163Node *LastInNew;164for (auto *N = New; N != nullptr; N = N->NextSibling) {165LastInNew = N;166N->Parent = this;167}168LastInNew->NextSibling = End;169NewLast = LastInNew;170}171172namespace {173static void dumpNode(raw_ostream &OS, const syntax::Node *N,174const syntax::TokenManager &TM, llvm::BitVector IndentMask) {175auto DumpExtraInfo = [&OS](const syntax::Node *N) {176if (N->getRole() != syntax::NodeRole::Unknown)177OS << " " << N->getRole();178if (!N->isOriginal())179OS << " synthesized";180if (!N->canModify())181OS << " unmodifiable";182};183184assert(N);185if (const auto *L = dyn_cast<syntax::Leaf>(N)) {186OS << "'";187OS << TM.getText(L->getTokenKey());188OS << "'";189DumpExtraInfo(N);190OS << "\n";191return;192}193194const auto *T = cast<syntax::Tree>(N);195OS << T->getKind();196DumpExtraInfo(N);197OS << "\n";198199for (const syntax::Node &It : T->getChildren()) {200for (unsigned Idx = 0; Idx < IndentMask.size(); ++Idx) {201if (IndentMask[Idx])202OS << "| ";203else204OS << " ";205}206if (!It.getNextSibling()) {207OS << "`-";208IndentMask.push_back(false);209} else {210OS << "|-";211IndentMask.push_back(true);212}213dumpNode(OS, &It, TM, IndentMask);214IndentMask.pop_back();215}216}217} // namespace218219std::string syntax::Node::dump(const TokenManager &TM) const {220std::string Str;221llvm::raw_string_ostream OS(Str);222dumpNode(OS, this, TM, /*IndentMask=*/{});223return std::move(OS.str());224}225226std::string syntax::Node::dumpTokens(const TokenManager &TM) const {227std::string Storage;228llvm::raw_string_ostream OS(Storage);229traverse(this, [&](const syntax::Node *N) {230if (const auto *L = dyn_cast<syntax::Leaf>(N)) {231OS << TM.getText(L->getTokenKey());232OS << " ";233}234});235return Storage;236}237238void syntax::Node::assertInvariants() const {239#ifndef NDEBUG240if (isDetached())241assert(getParent() == nullptr);242else243assert(getParent() != nullptr);244245const auto *T = dyn_cast<Tree>(this);246if (!T)247return;248for (const Node &C : T->getChildren()) {249if (T->isOriginal())250assert(C.isOriginal());251assert(!C.isDetached());252assert(C.getParent() == T);253const auto *Next = C.getNextSibling();254assert(!Next || &C == Next->getPreviousSibling());255if (!C.getNextSibling())256assert(&C == T->getLastChild() &&257"Last child is reachable by advancing from the first child.");258}259260const auto *L = dyn_cast<List>(T);261if (!L)262return;263for (const Node &C : T->getChildren()) {264assert(C.getRole() == NodeRole::ListElement ||265C.getRole() == NodeRole::ListDelimiter);266if (C.getRole() == NodeRole::ListDelimiter) {267assert(isa<Leaf>(C));268// FIXME: re-enable it when there is way to retrieve token kind in Leaf.269// assert(cast<Leaf>(C).getToken()->kind() == L->getDelimiterTokenKind());270}271}272273#endif274}275276void syntax::Node::assertInvariantsRecursive() const {277#ifndef NDEBUG278traverse(this, [&](const syntax::Node *N) { N->assertInvariants(); });279#endif280}281282const syntax::Leaf *syntax::Tree::findFirstLeaf() const {283for (const Node &C : getChildren()) {284if (const auto *L = dyn_cast<syntax::Leaf>(&C))285return L;286if (const auto *L = cast<syntax::Tree>(C).findFirstLeaf())287return L;288}289return nullptr;290}291292const syntax::Leaf *syntax::Tree::findLastLeaf() const {293for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {294if (const auto *L = dyn_cast<syntax::Leaf>(C))295return L;296if (const auto *L = cast<syntax::Tree>(C)->findLastLeaf())297return L;298}299return nullptr;300}301302const syntax::Node *syntax::Tree::findChild(NodeRole R) const {303for (const Node &C : getChildren()) {304if (C.getRole() == R)305return &C;306}307return nullptr;308}309310std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>311syntax::List::getElementsAsNodesAndDelimiters() {312if (!getFirstChild())313return {};314315std::vector<syntax::List::ElementAndDelimiter<Node>> Children;316syntax::Node *ElementWithoutDelimiter = nullptr;317for (Node &C : getChildren()) {318switch (C.getRole()) {319case syntax::NodeRole::ListElement: {320if (ElementWithoutDelimiter) {321Children.push_back({ElementWithoutDelimiter, nullptr});322}323ElementWithoutDelimiter = &C;324break;325}326case syntax::NodeRole::ListDelimiter: {327Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(&C)});328ElementWithoutDelimiter = nullptr;329break;330}331default:332llvm_unreachable(333"A list can have only elements and delimiters as children.");334}335}336337switch (getTerminationKind()) {338case syntax::List::TerminationKind::Separated: {339Children.push_back({ElementWithoutDelimiter, nullptr});340break;341}342case syntax::List::TerminationKind::Terminated:343case syntax::List::TerminationKind::MaybeTerminated: {344if (ElementWithoutDelimiter) {345Children.push_back({ElementWithoutDelimiter, nullptr});346}347break;348}349}350351return Children;352}353354// Almost the same implementation of `getElementsAsNodesAndDelimiters` but355// ignoring delimiters356std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {357if (!getFirstChild())358return {};359360std::vector<syntax::Node *> Children;361syntax::Node *ElementWithoutDelimiter = nullptr;362for (Node &C : getChildren()) {363switch (C.getRole()) {364case syntax::NodeRole::ListElement: {365if (ElementWithoutDelimiter) {366Children.push_back(ElementWithoutDelimiter);367}368ElementWithoutDelimiter = &C;369break;370}371case syntax::NodeRole::ListDelimiter: {372Children.push_back(ElementWithoutDelimiter);373ElementWithoutDelimiter = nullptr;374break;375}376default:377llvm_unreachable("A list has only elements or delimiters.");378}379}380381switch (getTerminationKind()) {382case syntax::List::TerminationKind::Separated: {383Children.push_back(ElementWithoutDelimiter);384break;385}386case syntax::List::TerminationKind::Terminated:387case syntax::List::TerminationKind::MaybeTerminated: {388if (ElementWithoutDelimiter) {389Children.push_back(ElementWithoutDelimiter);390}391break;392}393}394395return Children;396}397398clang::tok::TokenKind syntax::List::getDelimiterTokenKind() const {399switch (this->getKind()) {400case NodeKind::NestedNameSpecifier:401return clang::tok::coloncolon;402case NodeKind::CallArguments:403case NodeKind::ParameterDeclarationList:404case NodeKind::DeclaratorList:405return clang::tok::comma;406default:407llvm_unreachable("This is not a subclass of List, thus "408"getDelimiterTokenKind() cannot be called");409}410}411412syntax::List::TerminationKind syntax::List::getTerminationKind() const {413switch (this->getKind()) {414case NodeKind::NestedNameSpecifier:415return TerminationKind::Terminated;416case NodeKind::CallArguments:417case NodeKind::ParameterDeclarationList:418case NodeKind::DeclaratorList:419return TerminationKind::Separated;420default:421llvm_unreachable("This is not a subclass of List, thus "422"getTerminationKind() cannot be called");423}424}425426bool syntax::List::canBeEmpty() const {427switch (this->getKind()) {428case NodeKind::NestedNameSpecifier:429return false;430case NodeKind::CallArguments:431return true;432case NodeKind::ParameterDeclarationList:433return true;434case NodeKind::DeclaratorList:435return true;436default:437llvm_unreachable("This is not a subclass of List, thus canBeEmpty() "438"cannot be called");439}440}441442443