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 // This class has access to the internals of tree nodes. Its sole purpose is to
27 // define helpers that allow implementing the high-level mutation operations.
28 class syntax::MutationsImpl {
29 public:
30   /// Add a new node with a specified role.
31   static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
32     assert(New->Parent == nullptr);
33     assert(New->NextSibling == nullptr);
34     assert(!New->isDetached());
35     assert(Role != NodeRole::Detached);
36 
37     New->Role = static_cast<unsigned>(Role);
38     Anchor->parent()->replaceChildRangeLowLevel(Anchor, Anchor, New);
39   }
40 
41   /// Replace the node, keeping the role.
42   static void replace(syntax::Node *Old, syntax::Node *New) {
43     assert(New->Parent == nullptr);
44     assert(New->NextSibling == nullptr);
45     assert(New->isDetached());
46 
47     New->Role = Old->Role;
48     Old->parent()->replaceChildRangeLowLevel(findPrevious(Old),
49                                              Old->nextSibling(), New);
50   }
51 
52   /// Completely remove the node from its parent.
53   static void remove(syntax::Node *N) {
54     N->parent()->replaceChildRangeLowLevel(findPrevious(N), N->nextSibling(),
55                                            /*New=*/nullptr);
56   }
57 
58 private:
59   static syntax::Node *findPrevious(syntax::Node *N) {
60     if (N->parent()->firstChild() == N)
61       return nullptr;
62     for (syntax::Node *C = N->parent()->firstChild(); C != nullptr;
63          C = C->nextSibling()) {
64       if (C->nextSibling() == N)
65         return C;
66     }
67     llvm_unreachable("could not find a child node");
68   }
69 };
70 
71 void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
72   assert(S->canModify());
73 
74   if (isa<CompoundStatement>(S->parent())) {
75     // A child of CompoundStatement can just be safely removed.
76     MutationsImpl::remove(S);
77     return;
78   }
79   // For the rest, we have to replace with an empty statement.
80   if (isa<EmptyStatement>(S))
81     return; // already an empty statement, nothing to do.
82 
83   MutationsImpl::replace(S, createEmptyStatement(A));
84 }
85