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/Basic/SourceLocation.h"
11 #include "clang/Lex/Token.h"
12 #include "clang/Tooling/Core/Replacement.h"
13 #include "clang/Tooling/Syntax/BuildTree.h"
14 #include "clang/Tooling/Syntax/Nodes.h"
15 #include "clang/Tooling/Syntax/Tokens.h"
16 #include "clang/Tooling/Syntax/Tree.h"
17 #include "llvm/ADT/ArrayRef.h"
18 #include "llvm/ADT/Optional.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/Support/Casting.h"
21 #include <cassert>
22 #include <string>
23 
24 using namespace clang;
25 
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 
39 // This class has access to the internals of tree nodes. Its sole purpose is to
40 // define helpers that allow implementing the high-level mutation operations.
41 class syntax::MutationsImpl {
42 public:
43   /// Add a new node with a specified role.
44   static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
45     assert(Anchor != nullptr);
46     assert(Anchor->Parent != nullptr);
47     assert(New->Parent == nullptr);
48     assert(New->NextSibling == nullptr);
49     assert(New->isDetached());
50     assert(Role != NodeRole::Detached);
51 
52     New->setRole(Role);
53     auto *P = Anchor->getParent();
54     P->replaceChildRangeLowLevel(Anchor, Anchor->getNextSibling(), New);
55 
56     P->assertInvariants();
57   }
58 
59   /// Replace the node, keeping the role.
60   static void replace(syntax::Node *Old, syntax::Node *New) {
61     assert(Old != nullptr);
62     assert(Old->Parent != nullptr);
63     assert(Old->canModify());
64     assert(New->Parent == nullptr);
65     assert(New->NextSibling == nullptr);
66     assert(New->isDetached());
67 
68     New->Role = Old->Role;
69     auto *P = Old->getParent();
70     P->replaceChildRangeLowLevel(findPrevious(Old), Old->getNextSibling(), New);
71 
72     P->assertInvariants();
73   }
74 
75   /// Completely remove the node from its parent.
76   static void remove(syntax::Node *N) {
77     assert(N != nullptr);
78     assert(N->Parent != nullptr);
79     assert(N->canModify());
80 
81     auto *P = N->getParent();
82     P->replaceChildRangeLowLevel(findPrevious(N), N->getNextSibling(),
83                                  /*New=*/nullptr);
84 
85     P->assertInvariants();
86     N->assertInvariants();
87   }
88 };
89 
90 void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
91   assert(S);
92   assert(S->canModify());
93 
94   if (isa<CompoundStatement>(S->getParent())) {
95     // A child of CompoundStatement can just be safely removed.
96     MutationsImpl::remove(S);
97     return;
98   }
99   // For the rest, we have to replace with an empty statement.
100   if (isa<EmptyStatement>(S))
101     return; // already an empty statement, nothing to do.
102 
103   MutationsImpl::replace(S, createEmptyStatement(A));
104 }
105