xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
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(Anchor->getNextSibling(),
34                                  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(Old, 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(N, 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>(S->getParent())) {
77     // A child of CompoundStatement can just be safely removed.
78     MutationsImpl::remove(S);
79     return;
80   }
81   // For the rest, we have to replace with an empty statement.
82   if (isa<EmptyStatement>(S))
83     return; // already an empty statement, nothing to do.
84 
85   MutationsImpl::replace(S, createEmptyStatement(A, TBTM));
86 }
87