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.
addAfter(syntax::Node * Anchor,syntax::Node * New,NodeRole Role)31 static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
32 assert(Anchor != nullptr);
33 assert(Anchor->Parent != nullptr);
34 assert(New->Parent == nullptr);
35 assert(New->NextSibling == nullptr);
36 assert(New->PreviousSibling == nullptr);
37 assert(New->isDetached());
38 assert(Role != NodeRole::Detached);
39
40 New->setRole(Role);
41 auto *P = Anchor->getParent();
42 P->replaceChildRangeLowLevel(Anchor->getNextSibling(),
43 Anchor->getNextSibling(), New);
44
45 P->assertInvariants();
46 }
47
48 /// Replace the node, keeping the role.
replace(syntax::Node * Old,syntax::Node * New)49 static void replace(syntax::Node *Old, syntax::Node *New) {
50 assert(Old != nullptr);
51 assert(Old->Parent != nullptr);
52 assert(Old->canModify());
53 assert(New->Parent == nullptr);
54 assert(New->NextSibling == nullptr);
55 assert(New->PreviousSibling == nullptr);
56 assert(New->isDetached());
57
58 New->Role = Old->Role;
59 auto *P = Old->getParent();
60 P->replaceChildRangeLowLevel(Old, Old->getNextSibling(), New);
61
62 P->assertInvariants();
63 }
64
65 /// Completely remove the node from its parent.
remove(syntax::Node * N)66 static void remove(syntax::Node *N) {
67 assert(N != nullptr);
68 assert(N->Parent != nullptr);
69 assert(N->canModify());
70
71 auto *P = N->getParent();
72 P->replaceChildRangeLowLevel(N, N->getNextSibling(),
73 /*New=*/nullptr);
74
75 P->assertInvariants();
76 N->assertInvariants();
77 }
78 };
79
removeStatement(syntax::Arena & A,syntax::Statement * S)80 void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
81 assert(S);
82 assert(S->canModify());
83
84 if (isa<CompoundStatement>(S->getParent())) {
85 // A child of CompoundStatement can just be safely removed.
86 MutationsImpl::remove(S);
87 return;
88 }
89 // For the rest, we have to replace with an empty statement.
90 if (isa<EmptyStatement>(S))
91 return; // already an empty statement, nothing to do.
92
93 MutationsImpl::replace(S, createEmptyStatement(A));
94 }
95