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