xref: /llvm-project/clang/lib/Tooling/Syntax/Mutations.cpp (revision a996cc217cefb9071888de38c6f05e5742d0106f)
11ad15046SIlya Biryukov //===- Mutations.cpp ------------------------------------------*- C++ -*-=====//
21ad15046SIlya Biryukov //
31ad15046SIlya Biryukov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41ad15046SIlya Biryukov // See https://llvm.org/LICENSE.txt for license information.
51ad15046SIlya Biryukov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61ad15046SIlya Biryukov //
71ad15046SIlya Biryukov //===----------------------------------------------------------------------===//
81ad15046SIlya Biryukov #include "clang/Tooling/Syntax/Mutations.h"
91ad15046SIlya Biryukov #include "clang/Basic/LLVM.h"
101ad15046SIlya Biryukov #include "clang/Basic/SourceLocation.h"
111ad15046SIlya Biryukov #include "clang/Lex/Token.h"
121ad15046SIlya Biryukov #include "clang/Tooling/Core/Replacement.h"
131ad15046SIlya Biryukov #include "clang/Tooling/Syntax/BuildTree.h"
141ad15046SIlya Biryukov #include "clang/Tooling/Syntax/Nodes.h"
151ad15046SIlya Biryukov #include "clang/Tooling/Syntax/Tokens.h"
161ad15046SIlya Biryukov #include "clang/Tooling/Syntax/Tree.h"
171ad15046SIlya Biryukov #include "llvm/ADT/ArrayRef.h"
181ad15046SIlya Biryukov #include "llvm/ADT/STLExtras.h"
191ad15046SIlya Biryukov #include "llvm/Support/Casting.h"
201ad15046SIlya Biryukov #include <cassert>
211ad15046SIlya Biryukov #include <string>
221ad15046SIlya Biryukov 
231ad15046SIlya Biryukov using namespace clang;
241ad15046SIlya Biryukov 
251ad15046SIlya Biryukov // This class has access to the internals of tree nodes. Its sole purpose is to
261ad15046SIlya Biryukov // define helpers that allow implementing the high-level mutation operations.
271ad15046SIlya Biryukov class syntax::MutationsImpl {
281ad15046SIlya Biryukov public:
291ad15046SIlya Biryukov   /// Add a new node with a specified role.
addAfter(syntax::Node * Anchor,syntax::Node * New,NodeRole Role)301ad15046SIlya Biryukov   static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
313b929fe7SIlya Biryukov     assert(Anchor != nullptr);
3272732acaSEduardo Caldas     assert(Anchor->Parent != nullptr);
331ad15046SIlya Biryukov     assert(New->Parent == nullptr);
341ad15046SIlya Biryukov     assert(New->NextSibling == nullptr);
3523657d9cSEduardo Caldas     assert(New->PreviousSibling == nullptr);
3672732acaSEduardo Caldas     assert(New->isDetached());
371ad15046SIlya Biryukov     assert(Role != NodeRole::Detached);
381ad15046SIlya Biryukov 
39a711a3a4SMarcel Hlopko     New->setRole(Role);
404c14ee61SEduardo Caldas     auto *P = Anchor->getParent();
4123657d9cSEduardo Caldas     P->replaceChildRangeLowLevel(Anchor->getNextSibling(),
4223657d9cSEduardo Caldas                                  Anchor->getNextSibling(), New);
433b929fe7SIlya Biryukov 
443b929fe7SIlya Biryukov     P->assertInvariants();
451ad15046SIlya Biryukov   }
461ad15046SIlya Biryukov 
471ad15046SIlya Biryukov   /// Replace the node, keeping the role.
replace(syntax::Node * Old,syntax::Node * New)481ad15046SIlya Biryukov   static void replace(syntax::Node *Old, syntax::Node *New) {
493b929fe7SIlya Biryukov     assert(Old != nullptr);
503b929fe7SIlya Biryukov     assert(Old->Parent != nullptr);
513b929fe7SIlya Biryukov     assert(Old->canModify());
521ad15046SIlya Biryukov     assert(New->Parent == nullptr);
531ad15046SIlya Biryukov     assert(New->NextSibling == nullptr);
5423657d9cSEduardo Caldas     assert(New->PreviousSibling == nullptr);
551ad15046SIlya Biryukov     assert(New->isDetached());
561ad15046SIlya Biryukov 
571ad15046SIlya Biryukov     New->Role = Old->Role;
584c14ee61SEduardo Caldas     auto *P = Old->getParent();
5923657d9cSEduardo Caldas     P->replaceChildRangeLowLevel(Old, Old->getNextSibling(), New);
603b929fe7SIlya Biryukov 
613b929fe7SIlya Biryukov     P->assertInvariants();
621ad15046SIlya Biryukov   }
631ad15046SIlya Biryukov 
641ad15046SIlya Biryukov   /// Completely remove the node from its parent.
remove(syntax::Node * N)651ad15046SIlya Biryukov   static void remove(syntax::Node *N) {
6672732acaSEduardo Caldas     assert(N != nullptr);
6772732acaSEduardo Caldas     assert(N->Parent != nullptr);
6872732acaSEduardo Caldas     assert(N->canModify());
6972732acaSEduardo Caldas 
704c14ee61SEduardo Caldas     auto *P = N->getParent();
7123657d9cSEduardo Caldas     P->replaceChildRangeLowLevel(N, N->getNextSibling(),
721ad15046SIlya Biryukov                                  /*New=*/nullptr);
733b929fe7SIlya Biryukov 
743b929fe7SIlya Biryukov     P->assertInvariants();
753b929fe7SIlya Biryukov     N->assertInvariants();
761ad15046SIlya Biryukov   }
771ad15046SIlya Biryukov };
781ad15046SIlya Biryukov 
removeStatement(syntax::Arena & A,TokenBufferTokenManager & TBTM,syntax::Statement * S)79*263dcf45SHaojian Wu void syntax::removeStatement(syntax::Arena &A, TokenBufferTokenManager &TBTM,
80*263dcf45SHaojian Wu                              syntax::Statement *S) {
813b929fe7SIlya Biryukov   assert(S);
821ad15046SIlya Biryukov   assert(S->canModify());
831ad15046SIlya Biryukov 
844c14ee61SEduardo Caldas   if (isa<CompoundStatement>(S->getParent())) {
851ad15046SIlya Biryukov     // A child of CompoundStatement can just be safely removed.
861ad15046SIlya Biryukov     MutationsImpl::remove(S);
871ad15046SIlya Biryukov     return;
881ad15046SIlya Biryukov   }
891ad15046SIlya Biryukov   // For the rest, we have to replace with an empty statement.
901ad15046SIlya Biryukov   if (isa<EmptyStatement>(S))
911ad15046SIlya Biryukov     return; // already an empty statement, nothing to do.
921ad15046SIlya Biryukov 
93*263dcf45SHaojian Wu   MutationsImpl::replace(S, createEmptyStatement(A, TBTM));
941ad15046SIlya Biryukov }
95