xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp (revision 82d4dc0621c92e3c05a86013eec35afbdec057a5)
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(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.
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  
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