1 | //===- Mutations.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/Mutations.h" |
9 | #include "clang/Basic/LLVM.h" |
10 | #include "clang/Tooling/Syntax/BuildTree.h" |
11 | #include "clang/Tooling/Syntax/Nodes.h" |
12 | #include "clang/Tooling/Syntax/Tree.h" |
13 | #include <cassert> |
14 | |
15 | using namespace clang; |
16 | |
17 | // This class has access to the internals of tree nodes. Its sole purpose is to |
18 | // define helpers that allow implementing the high-level mutation operations. |
19 | class syntax::MutationsImpl { |
20 | public: |
21 | /// Add a new node with a specified role. |
22 | static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) { |
23 | assert(Anchor != nullptr); |
24 | assert(Anchor->Parent != nullptr); |
25 | assert(New->Parent == nullptr); |
26 | assert(New->NextSibling == nullptr); |
27 | assert(New->PreviousSibling == nullptr); |
28 | assert(New->isDetached()); |
29 | assert(Role != NodeRole::Detached); |
30 | |
31 | New->setRole(Role); |
32 | auto *P = Anchor->getParent(); |
33 | P->replaceChildRangeLowLevel(Begin: Anchor->getNextSibling(), |
34 | End: Anchor->getNextSibling(), New); |
35 | |
36 | P->assertInvariants(); |
37 | } |
38 | |
39 | /// Replace the node, keeping the role. |
40 | static void replace(syntax::Node *Old, syntax::Node *New) { |
41 | assert(Old != nullptr); |
42 | assert(Old->Parent != nullptr); |
43 | assert(Old->canModify()); |
44 | assert(New->Parent == nullptr); |
45 | assert(New->NextSibling == nullptr); |
46 | assert(New->PreviousSibling == nullptr); |
47 | assert(New->isDetached()); |
48 | |
49 | New->Role = Old->Role; |
50 | auto *P = Old->getParent(); |
51 | P->replaceChildRangeLowLevel(Begin: Old, End: Old->getNextSibling(), New); |
52 | |
53 | P->assertInvariants(); |
54 | } |
55 | |
56 | /// Completely remove the node from its parent. |
57 | static void remove(syntax::Node *N) { |
58 | assert(N != nullptr); |
59 | assert(N->Parent != nullptr); |
60 | assert(N->canModify()); |
61 | |
62 | auto *P = N->getParent(); |
63 | P->replaceChildRangeLowLevel(Begin: N, End: N->getNextSibling(), |
64 | /*New=*/nullptr); |
65 | |
66 | P->assertInvariants(); |
67 | N->assertInvariants(); |
68 | } |
69 | }; |
70 | |
71 | void syntax::removeStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM, |
72 | syntax::Statement *S) { |
73 | assert(S); |
74 | assert(S->canModify()); |
75 | |
76 | if (isa<CompoundStatement>(Val: S->getParent())) { |
77 | // A child of CompoundStatement can just be safely removed. |
78 | MutationsImpl::remove(N: S); |
79 | return; |
80 | } |
81 | // For the rest, we have to replace with an empty statement. |
82 | if (isa<EmptyStatement>(Val: S)) |
83 | return; // already an empty statement, nothing to do. |
84 | |
85 | MutationsImpl::replace(Old: S, New: createEmptyStatement(A, TBTM)); |
86 | } |
87 | |