1276789Sdim//===- Mutations.cpp ------------------------------------------*- C++ -*-=====//
2276789Sdim//
3276789Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4276789Sdim// See https://llvm.org/LICENSE.txt for license information.
5276789Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6276789Sdim//
7276789Sdim//===----------------------------------------------------------------------===//
8276789Sdim#include "clang/Tooling/Syntax/Mutations.h"
9276789Sdim#include "clang/Basic/LLVM.h"
10276789Sdim#include "clang/Basic/SourceLocation.h"
11276789Sdim#include "clang/Lex/Token.h"
12276789Sdim#include "clang/Tooling/Core/Replacement.h"
13276789Sdim#include "clang/Tooling/Syntax/BuildTree.h"
14276789Sdim#include "clang/Tooling/Syntax/Nodes.h"
15276789Sdim#include "clang/Tooling/Syntax/Tokens.h"
16276789Sdim#include "clang/Tooling/Syntax/Tree.h"
17276789Sdim#include "llvm/ADT/ArrayRef.h"
18276789Sdim#include "llvm/ADT/Optional.h"
19276789Sdim#include "llvm/ADT/STLExtras.h"
20276789Sdim#include "llvm/Support/Casting.h"
21276789Sdim#include <cassert>
22276789Sdim#include <string>
23276789Sdim
24276789Sdimusing namespace clang;
25276789Sdim
26276789Sdim// This class has access to the internals of tree nodes. Its sole purpose is to
27276789Sdim// define helpers that allow implementing the high-level mutation operations.
28276789Sdimclass syntax::MutationsImpl {
29276789Sdimpublic:
30276789Sdim  /// Add a new node with a specified role.
31276789Sdim  static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
32276789Sdim    assert(Anchor != nullptr);
33276789Sdim    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.
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.
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
80void 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