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(New->Parent == nullptr); 34 assert(New->NextSibling == nullptr); 35 assert(!New->isDetached()); 36 assert(Role != NodeRole::Detached); 37 38 New->setRole(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 71 private: 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 84 void 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