eduucaldas updated this revision to Diff 297395.
eduucaldas added a comment.
Add role sanity-check. Introduce `GetBegin()`.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D89147/new/
https://reviews.llvm.org/D89147
Files:
clang/include/clang/Tooling/Syntax/Tree.h
clang/lib/Tooling/Syntax/Mutations.cpp
clang/lib/Tooling/Syntax/Tree.cpp
Index: clang/lib/Tooling/Syntax/Tree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Tree.cpp
+++ clang/lib/Tooling/Syntax/Tree.cpp
@@ -92,50 +92,84 @@
this->FirstChild = Child;
}
-void syntax::Tree::replaceChildRangeLowLevel(Node *BeforeBegin, Node *End,
- Node *New) {
- assert(!BeforeBegin || BeforeBegin->Parent == this);
+std::vector<std::pair<syntax::Node *, syntax::NodeRole>>
+syntax::Tree::replaceChildRangeLowLevel(
+ Node *BeforeBegin, Node *End,
+ ArrayRef<std::pair<syntax::Node *, syntax::NodeRole>> NewRange) {
+ assert(!BeforeBegin || BeforeBegin->Parent == this &&
+ "`BeforeBegin` is not a child of `this`");
+ assert(!End || End->Parent == this && "`End` is not a child of `this`");
#ifndef NDEBUG
- for (auto *N = New; N; N = N->getNextSibling()) {
+ for (const auto &NodeAndRole : NewRange) {
+ auto *N = NodeAndRole.first;
assert(N->Parent == nullptr);
- assert(N->getRole() != NodeRole::Detached && "Roles must be set");
- // FIXME: sanity-check the role.
+ assert(N->getRole() == NodeRole::Detached && "Roles must not be set");
+
+ auto Role = NodeAndRole.second;
+ assert(Role != NodeRole::Detached);
}
+
+ auto Reachable = [](Node *From, Node *N) {
+ if (!N)
+ return true;
+ for (auto *It = From; It; It = It->NextSibling)
+ if (It == N)
+ return true;
+ return false;
+ };
+ assert(Reachable(FirstChild, BeforeBegin) &&
+ "`BeforeBegin` is not reachable");
+ assert(Reachable(BeforeBegin ? BeforeBegin->NextSibling : FirstChild, End) &&
+ "`End` is not after `BeforeBegin`");
+
#endif
- // Detach old nodes.
- for (auto *N = !BeforeBegin ? FirstChild : BeforeBegin->getNextSibling();
- N != End;) {
+ auto GetBegin = [&BeforeBegin, &FirstChild = this->FirstChild]() -> Node *& {
+ return BeforeBegin ? BeforeBegin->NextSibling : FirstChild;
+ };
+
+ // Extract old nodes.
+ std::vector<std::pair<syntax::Node *, syntax::NodeRole>> ExtractedChildren;
+ for (auto *N = GetBegin(); N != End;) {
auto *Next = N->NextSibling;
+ ExtractedChildren.push_back({N, N->getRole()});
N->setRole(NodeRole::Detached);
N->Parent = nullptr;
N->NextSibling = nullptr;
if (N->Original)
- traverse(N, [&](Node *C) { C->Original = false; });
+ traverse(N, [](Node *C) { C->Original = false; });
N = Next;
}
- // Attach new nodes.
- if (BeforeBegin)
- BeforeBegin->NextSibling = New ? New : End;
- else
- FirstChild = New ? New : End;
+ // If any modification occurred mark this and its ancestors as modified.
+ if (!ExtractedChildren.empty() || !NewRange.empty())
+ for (auto *T = this; T && T->Original; T = T->Parent)
+ T->Original = false;
- if (New) {
- auto *Last = New;
- for (auto *N = New; N != nullptr; N = N->getNextSibling()) {
- Last = N;
- N->Parent = this;
- }
- Last->NextSibling = End;
+ // Attach new children to the replaced range.
+ if (NewRange.empty()) {
+ GetBegin() = End;
+ return ExtractedChildren;
+ }
+ GetBegin() = NewRange.front().first;
+ NewRange.back().first->NextSibling = End;
+
+ for (const auto &NodeAndRole : NewRange) {
+ NodeAndRole.first->setRole(NodeAndRole.second);
+ NodeAndRole.first->Parent = this;
+ }
+
+ for (const auto *It = NewRange.begin(); It != std::prev(NewRange.end());
+ ++It) {
+ auto *Node = It->first;
+ auto *Next = std::next(It)->first;
+ Node->NextSibling = Next;
}
- // Mark the node as modified.
- for (auto *T = this; T && T->Original; T = T->Parent)
- T->Original = false;
+ return ExtractedChildren;
}
namespace {
Index: clang/lib/Tooling/Syntax/Mutations.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Mutations.cpp
+++ clang/lib/Tooling/Syntax/Mutations.cpp
@@ -23,6 +23,17 @@
using namespace clang;
+static syntax::Node *findPrevious(syntax::Node *N) {
+ if (N->getParent()->getFirstChild() == N)
+ return nullptr;
+ for (syntax::Node *C = N->getParent()->getFirstChild(); C != nullptr;
+ C = C->getNextSibling()) {
+ if (C->getNextSibling() == N)
+ return C;
+ }
+ llvm_unreachable("could not find a child node");
+}
+
// This class has access to the internals of tree nodes. Its sole purpose is to
// define helpers that allow implementing the high-level mutation operations.
class syntax::MutationsImpl {
@@ -30,14 +41,15 @@
/// Add a new node with a specified role.
static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
assert(Anchor != nullptr);
+ assert(Anchor->Parent != nullptr);
assert(New->Parent == nullptr);
assert(New->NextSibling == nullptr);
- assert(!New->isDetached());
+ assert(New->isDetached());
assert(Role != NodeRole::Detached);
- New->setRole(Role);
auto *P = Anchor->getParent();
- P->replaceChildRangeLowLevel(Anchor, Anchor, New);
+ P->replaceChildRangeLowLevel(Anchor, Anchor->getNextSibling(),
+ {{New, Role}});
P->assertInvariants();
}
@@ -51,9 +63,9 @@
assert(New->NextSibling == nullptr);
assert(New->isDetached());
- New->Role = Old->Role;
auto *P = Old->getParent();
- P->replaceChildRangeLowLevel(findPrevious(Old), Old->getNextSibling(), New);
+ P->replaceChildRangeLowLevel(findPrevious(Old), Old->getNextSibling(),
+ {{New, Old->getRole()}});
P->assertInvariants();
}
@@ -62,23 +74,11 @@
static void remove(syntax::Node *N) {
auto *P = N->getParent();
P->replaceChildRangeLowLevel(findPrevious(N), N->getNextSibling(),
- /*New=*/nullptr);
+ /*NewRange=*/{});
P->assertInvariants();
N->assertInvariants();
}
-
-private:
- static syntax::Node *findPrevious(syntax::Node *N) {
- if (N->getParent()->getFirstChild() == N)
- return nullptr;
- for (syntax::Node *C = N->getParent()->getFirstChild(); C != nullptr;
- C = C->getNextSibling()) {
- if (C->getNextSibling() == N)
- return C;
- }
- llvm_unreachable("could not find a child node");
- }
};
void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
Index: clang/include/clang/Tooling/Syntax/Tree.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tree.h
+++ clang/include/clang/Tooling/Syntax/Tree.h
@@ -185,11 +185,14 @@
friend class TreeBuilder;
friend class FactoryImpl;
- /// Replace a range of children [BeforeBegin->NextSibling, End) with a list of
- /// new nodes starting at \p New.
- /// Only used by MutationsImpl to implement higher-level mutation operations.
- /// (!) \p New can be null to model removal of the child range.
- void replaceChildRangeLowLevel(Node *BeforeBegin, Node *End, Node *New);
+ /// Replace a range of children between \p BeforeBegin and \p End with a list
+ /// of new nodes and their corresponding `NodeRole`s \p NewRange. Only used by
+ /// MutationsImpl to implement higher-level mutation operations.
+ /// (!) `BeforeBegin` == nullptr => Replace everything before `End`.
+ /// (!) `End` == nullptr => Replace everything after `BeforeBegin`.
+ std::vector<std::pair<Node *, NodeRole>> replaceChildRangeLowLevel(
+ Node *BeforeBegin, Node *End,
+ ArrayRef<std::pair<syntax::Node *, NodeRole>> NewRange);
friend class MutationsImpl;
Node *FirstChild = nullptr;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits