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