xref: /freebsd/contrib/llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp (revision f5f40dd63bc7acbb5312b26ac1ea1103c12352a6)
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 
23 using 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.
27 class syntax::MutationsImpl {
28 public:
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(Anchor->getNextSibling(),
42                                  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(Old, 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(N, N->getNextSibling(),
72                                  /*New=*/nullptr);
73 
74     P->assertInvariants();
75     N->assertInvariants();
76   }
77 };
78 
79 void syntax::removeStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM,
80                              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, TBTM));
94 }
95