Skip to content

Commit 23657d9

Browse files
author
Eduardo Caldas
committed
[SyntaxTree] Add reverse links to syntax Nodes.
Rationale: Children of a syntax tree had forward links only, because there was no need for reverse links. This need appeared when we started mutating the syntax tree. On a forward list, to remove a target node in O(1) we need a pointer to the node before the target. If we don't have this "before" pointer, we have to find it, and that requires O(n). So in order to remove a syntax node from a tree, we would similarly need to find the node before to then remove. This is both not ergonomic nor does it have a good complexity. Differential Revision: https://reviews.llvm.org/D90240
1 parent b715fa3 commit 23657d9

File tree

5 files changed

+100
-50
lines changed

5 files changed

+100
-50
lines changed

clang/include/clang/Tooling/Syntax/Tree.h

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ class Node {
118118

119119
const Node *getNextSibling() const { return NextSibling; }
120120
Node *getNextSibling() { return NextSibling; }
121+
const Node *getPreviousSibling() const { return PreviousSibling; }
122+
Node *getPreviousSibling() { return PreviousSibling; }
121123

122124
/// Dumps the structure of a subtree. For debugging and testing purposes.
123125
std::string dump(const SourceManager &SM) const;
@@ -144,6 +146,7 @@ class Node {
144146

145147
Tree *Parent;
146148
Node *NextSibling;
149+
Node *PreviousSibling;
147150
unsigned Kind : 16;
148151
unsigned Role : 8;
149152
unsigned Original : 1;
@@ -197,6 +200,8 @@ class Tree : public Node {
197200

198201
Node *getFirstChild() { return FirstChild; }
199202
const Node *getFirstChild() const { return FirstChild; }
203+
Node *getLastChild() { return LastChild; }
204+
const Node *getLastChild() const { return LastChild; }
200205

201206
const Leaf *findFirstLeaf() const;
202207
Leaf *findFirstLeaf() {
@@ -236,25 +241,32 @@ class Tree : public Node {
236241
using Node::Node;
237242

238243
private:
239-
/// Prepend \p Child to the list of children and and sets the parent pointer.
244+
/// Append \p Child to the list of children and sets the parent pointer.
240245
/// A very low-level operation that does not check any invariants, only used
241246
/// by TreeBuilder and FactoryImpl.
242247
/// EXPECTS: Role != Detached.
248+
void appendChildLowLevel(Node *Child, NodeRole Role);
249+
/// Similar but prepends.
243250
void prependChildLowLevel(Node *Child, NodeRole Role);
244-
/// Like the previous overload, but does not set role for \p Child.
251+
252+
/// Like the previous overloads, but does not set role for \p Child.
245253
/// EXPECTS: Child->Role != Detached
254+
void appendChildLowLevel(Node *Child);
246255
void prependChildLowLevel(Node *Child);
247256
friend class TreeBuilder;
248257
friend class FactoryImpl;
249258

250-
/// Replace a range of children [BeforeBegin->NextSibling, End) with a list of
259+
/// Replace a range of children [Begin, End) with a list of
251260
/// new nodes starting at \p New.
252261
/// Only used by MutationsImpl to implement higher-level mutation operations.
253262
/// (!) \p New can be null to model removal of the child range.
254-
void replaceChildRangeLowLevel(Node *BeforeBegin, Node *End, Node *New);
263+
/// (!) \p End can be null to model one past the end.
264+
/// (!) \p Begin can be null to model an append.
265+
void replaceChildRangeLowLevel(Node *Begin, Node *End, Node *New);
255266
friend class MutationsImpl;
256267

257268
Node *FirstChild = nullptr;
269+
Node *LastChild = nullptr;
258270
};
259271

260272
// Provide missing non_const == const overload.

clang/lib/Tooling/Syntax/BuildTree.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -636,12 +636,11 @@ class syntax::TreeBuilder {
636636
(EndChildren == Trees.end() || EndChildren->first == Tokens.end()) &&
637637
"fold crosses boundaries of existing subtrees");
638638

639-
// We need to go in reverse order, because we can only prepend.
640-
for (auto It = EndChildren; It != BeginChildren; --It) {
641-
auto *C = std::prev(It)->second;
639+
for (auto It = BeginChildren; It != EndChildren; ++It) {
640+
auto *C = It->second;
642641
if (C->getRole() == NodeRole::Detached)
643642
C->setRole(NodeRole::Unknown);
644-
Node->prependChildLowLevel(C);
643+
Node->appendChildLowLevel(C);
645644
}
646645

647646
// Mark that this node came from the AST and is backed by the source code.

clang/lib/Tooling/Syntax/Mutations.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,6 @@
2323

2424
using namespace clang;
2525

26-
static syntax::Node *findPrevious(syntax::Node *N) {
27-
assert(N);
28-
assert(N->getParent());
29-
if (N->getParent()->getFirstChild() == N)
30-
return nullptr;
31-
for (syntax::Node *C = N->getParent()->getFirstChild(); C != nullptr;
32-
C = C->getNextSibling()) {
33-
if (C->getNextSibling() == N)
34-
return C;
35-
}
36-
llvm_unreachable("could not find a child node");
37-
}
38-
3926
// This class has access to the internals of tree nodes. Its sole purpose is to
4027
// define helpers that allow implementing the high-level mutation operations.
4128
class syntax::MutationsImpl {
@@ -46,12 +33,14 @@ class syntax::MutationsImpl {
4633
assert(Anchor->Parent != nullptr);
4734
assert(New->Parent == nullptr);
4835
assert(New->NextSibling == nullptr);
36+
assert(New->PreviousSibling == nullptr);
4937
assert(New->isDetached());
5038
assert(Role != NodeRole::Detached);
5139

5240
New->setRole(Role);
5341
auto *P = Anchor->getParent();
54-
P->replaceChildRangeLowLevel(Anchor, Anchor->getNextSibling(), New);
42+
P->replaceChildRangeLowLevel(Anchor->getNextSibling(),
43+
Anchor->getNextSibling(), New);
5544

5645
P->assertInvariants();
5746
}
@@ -63,11 +52,12 @@ class syntax::MutationsImpl {
6352
assert(Old->canModify());
6453
assert(New->Parent == nullptr);
6554
assert(New->NextSibling == nullptr);
55+
assert(New->PreviousSibling == nullptr);
6656
assert(New->isDetached());
6757

6858
New->Role = Old->Role;
6959
auto *P = Old->getParent();
70-
P->replaceChildRangeLowLevel(findPrevious(Old), Old->getNextSibling(), New);
60+
P->replaceChildRangeLowLevel(Old, Old->getNextSibling(), New);
7161

7262
P->assertInvariants();
7363
}
@@ -79,7 +69,7 @@ class syntax::MutationsImpl {
7969
assert(N->canModify());
8070

8171
auto *P = N->getParent();
82-
P->replaceChildRangeLowLevel(findPrevious(N), N->getNextSibling(),
72+
P->replaceChildRangeLowLevel(N, N->getNextSibling(),
8373
/*New=*/nullptr);
8474

8575
P->assertInvariants();

clang/lib/Tooling/Syntax/Synthesis.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ class clang::syntax::FactoryImpl {
2121
syntax::NodeRole R) {
2222
T->prependChildLowLevel(Child, R);
2323
}
24+
static void appendChildLowLevel(syntax::Tree *T, syntax::Node *Child,
25+
syntax::NodeRole R) {
26+
T->appendChildLowLevel(Child, R);
27+
}
2428

2529
static std::pair<FileID, ArrayRef<Token>>
2630
lexBuffer(syntax::Arena &A, std::unique_ptr<llvm::MemoryBuffer> Buffer) {
@@ -196,8 +200,8 @@ syntax::Tree *clang::syntax::createTree(
196200
syntax::NodeKind K) {
197201
auto *T = allocateTree(A, K);
198202
FactoryImpl::setCanModify(T);
199-
for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend(); ++ChildIt)
200-
FactoryImpl::prependChildLowLevel(T, ChildIt->first, ChildIt->second);
203+
for (const auto &Child : Children)
204+
FactoryImpl::appendChildLowLevel(T, Child.first, Child.second);
201205

202206
T->assertInvariants();
203207
return T;

clang/lib/Tooling/Syntax/Tree.cpp

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,9 @@ bool syntax::Leaf::classof(const Node *N) {
5757
}
5858

5959
syntax::Node::Node(NodeKind Kind)
60-
: Parent(nullptr), NextSibling(nullptr), Kind(static_cast<unsigned>(Kind)),
61-
Role(0), Original(false), CanModify(false) {
60+
: Parent(nullptr), NextSibling(nullptr), PreviousSibling(nullptr),
61+
Kind(static_cast<unsigned>(Kind)), Role(0), Original(false),
62+
CanModify(false) {
6263
this->setRole(NodeRole::Detached);
6364
}
6465

@@ -74,6 +75,30 @@ bool syntax::Tree::classof(const Node *N) {
7475
return N->getKind() > NodeKind::Leaf;
7576
}
7677

78+
void syntax::Tree::appendChildLowLevel(Node *Child, NodeRole Role) {
79+
assert(Child->getRole() == NodeRole::Detached);
80+
assert(Role != NodeRole::Detached);
81+
82+
Child->setRole(Role);
83+
appendChildLowLevel(Child);
84+
}
85+
86+
void syntax::Tree::appendChildLowLevel(Node *Child) {
87+
assert(Child->Parent == nullptr);
88+
assert(Child->NextSibling == nullptr);
89+
assert(Child->PreviousSibling == nullptr);
90+
assert(Child->getRole() != NodeRole::Detached);
91+
92+
Child->Parent = this;
93+
if (this->LastChild) {
94+
Child->PreviousSibling = this->LastChild;
95+
this->LastChild->NextSibling = Child;
96+
} else
97+
this->FirstChild = Child;
98+
99+
this->LastChild = Child;
100+
}
101+
77102
void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
78103
assert(Child->getRole() == NodeRole::Detached);
79104
assert(Role != NodeRole::Detached);
@@ -85,22 +110,26 @@ void syntax::Tree::prependChildLowLevel(Node *Child, NodeRole Role) {
85110
void syntax::Tree::prependChildLowLevel(Node *Child) {
86111
assert(Child->Parent == nullptr);
87112
assert(Child->NextSibling == nullptr);
113+
assert(Child->PreviousSibling == nullptr);
88114
assert(Child->getRole() != NodeRole::Detached);
89115

90116
Child->Parent = this;
91-
Child->NextSibling = this->FirstChild;
117+
if (this->FirstChild) {
118+
Child->NextSibling = this->FirstChild;
119+
this->FirstChild->PreviousSibling = Child;
120+
} else
121+
this->LastChild = Child;
122+
92123
this->FirstChild = Child;
93124
}
94125

95-
void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
126+
void syntax::Tree::replaceChildRangeLowLevel(Node *Begin, Node *End,
96127
Node *New) {
97-
assert((!BeforeBegin || BeforeBegin->Parent == this) &&
98-
"`BeforeBegin` is not a child of `this`.");
128+
assert((!Begin || Begin->Parent == this) &&
129+
"`Begin` is not a child of `this`.");
99130
assert((!End || End->Parent == this) && "`End` is not a child of `this`.");
100131
assert(canModify() && "Cannot modify `this`.");
101132

102-
Node *&Begin = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
103-
104133
#ifndef NDEBUG
105134
for (auto *N = New; N; N = N->NextSibling) {
106135
assert(N->Parent == nullptr);
@@ -116,9 +145,8 @@ void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
116145
return true;
117146
return false;
118147
};
119-
assert(Reachable(FirstChild, BeforeBegin) &&
120-
"`BeforeBegin` is not reachable.");
121-
assert(Reachable(Begin, End) && "`End` is not after `BeforeBegin`.");
148+
assert(Reachable(FirstChild, Begin) && "`Begin` is not reachable.");
149+
assert(Reachable(Begin, End) && "`End` is not after `Begin`.");
122150
#endif
123151

124152
if (!New && Begin == End)
@@ -128,31 +156,44 @@ void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
128156
for (auto *T = this; T && T->Original; T = T->Parent)
129157
T->Original = false;
130158

159+
// Save the node before the range to be removed. Later we insert the `New`
160+
// range after this node.
161+
auto *BeforeBegin = Begin ? Begin->PreviousSibling : LastChild;
162+
131163
// Detach old nodes.
132164
for (auto *N = Begin; N != End;) {
133165
auto *Next = N->NextSibling;
134166

135167
N->setRole(NodeRole::Detached);
136168
N->Parent = nullptr;
137169
N->NextSibling = nullptr;
170+
N->PreviousSibling = nullptr;
138171
if (N->Original)
139172
traverse(N, [](Node *C) { C->Original = false; });
140173

141174
N = Next;
142175
}
143176

177+
// Attach new range.
178+
auto *&NewFirst = BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
179+
auto *&NewLast = End ? End->PreviousSibling : LastChild;
180+
144181
if (!New) {
145-
Begin = End;
182+
NewFirst = End;
183+
NewLast = BeforeBegin;
146184
return;
147185
}
148-
// Attach new nodes.
149-
Begin = New;
150-
auto *Last = New;
186+
187+
New->PreviousSibling = BeforeBegin;
188+
NewFirst = New;
189+
190+
Node *LastInNew;
151191
for (auto *N = New; N != nullptr; N = N->NextSibling) {
152-
Last = N;
192+
LastInNew = N;
153193
N->Parent = this;
154194
}
155-
Last->NextSibling = End;
195+
LastInNew->NextSibling = End;
196+
NewLast = LastInNew;
156197
}
157198

158199
namespace {
@@ -248,6 +289,11 @@ void syntax::Node::assertInvariants() const {
248289
assert(C.isOriginal());
249290
assert(!C.isDetached());
250291
assert(C.getParent() == T);
292+
const auto *Next = C.getNextSibling();
293+
assert(!Next || &C == Next->getPreviousSibling());
294+
if (!C.getNextSibling())
295+
assert(&C == T->getLastChild() &&
296+
"Last child is reachable by advancing from the first child.");
251297
}
252298

253299
const auto *L = dyn_cast<List>(T);
@@ -282,14 +328,13 @@ const syntax::Leaf *syntax::Tree::findFirstLeaf() const {
282328
}
283329

284330
const syntax::Leaf *syntax::Tree::findLastLeaf() const {
285-
const syntax::Leaf *Last = nullptr;
286-
for (const Node &C : getChildren()) {
287-
if (const auto *L = dyn_cast<syntax::Leaf>(&C))
288-
Last = L;
289-
else if (const auto *L = cast<syntax::Tree>(C).findLastLeaf())
290-
Last = L;
331+
for (const auto *C = getLastChild(); C; C = C->getPreviousSibling()) {
332+
if (const auto *L = dyn_cast<syntax::Leaf>(C))
333+
return L;
334+
if (const auto *L = cast<syntax::Tree>(C)->findLastLeaf())
335+
return L;
291336
}
292-
return Last;
337+
return nullptr;
293338
}
294339

295340
const syntax::Node *syntax::Tree::findChild(NodeRole R) const {

0 commit comments

Comments
 (0)