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