95 lines
3.0 KiB
C++
95 lines
3.0 KiB
C++
//===- Mutations.cpp ------------------------------------------*- C++ -*-=====//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "clang/Tooling/Syntax/Mutations.h"
|
|
#include "clang/Basic/LLVM.h"
|
|
#include "clang/Basic/SourceLocation.h"
|
|
#include "clang/Lex/Token.h"
|
|
#include "clang/Tooling/Core/Replacement.h"
|
|
#include "clang/Tooling/Syntax/BuildTree.h"
|
|
#include "clang/Tooling/Syntax/Nodes.h"
|
|
#include "clang/Tooling/Syntax/Tokens.h"
|
|
#include "clang/Tooling/Syntax/Tree.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include <cassert>
|
|
#include <string>
|
|
|
|
using namespace clang;
|
|
|
|
// This class has access to the internals of tree nodes. Its sole purpose is to
|
|
// define helpers that allow implementing the high-level mutation operations.
|
|
class syntax::MutationsImpl {
|
|
public:
|
|
/// Add a new node with a specified role.
|
|
static void addAfter(syntax::Node *Anchor, syntax::Node *New, NodeRole Role) {
|
|
assert(Anchor != nullptr);
|
|
assert(Anchor->Parent != nullptr);
|
|
assert(New->Parent == nullptr);
|
|
assert(New->NextSibling == nullptr);
|
|
assert(New->PreviousSibling == nullptr);
|
|
assert(New->isDetached());
|
|
assert(Role != NodeRole::Detached);
|
|
|
|
New->setRole(Role);
|
|
auto *P = Anchor->getParent();
|
|
P->replaceChildRangeLowLevel(Anchor->getNextSibling(),
|
|
Anchor->getNextSibling(), New);
|
|
|
|
P->assertInvariants();
|
|
}
|
|
|
|
/// Replace the node, keeping the role.
|
|
static void replace(syntax::Node *Old, syntax::Node *New) {
|
|
assert(Old != nullptr);
|
|
assert(Old->Parent != nullptr);
|
|
assert(Old->canModify());
|
|
assert(New->Parent == nullptr);
|
|
assert(New->NextSibling == nullptr);
|
|
assert(New->PreviousSibling == nullptr);
|
|
assert(New->isDetached());
|
|
|
|
New->Role = Old->Role;
|
|
auto *P = Old->getParent();
|
|
P->replaceChildRangeLowLevel(Old, Old->getNextSibling(), New);
|
|
|
|
P->assertInvariants();
|
|
}
|
|
|
|
/// Completely remove the node from its parent.
|
|
static void remove(syntax::Node *N) {
|
|
assert(N != nullptr);
|
|
assert(N->Parent != nullptr);
|
|
assert(N->canModify());
|
|
|
|
auto *P = N->getParent();
|
|
P->replaceChildRangeLowLevel(N, N->getNextSibling(),
|
|
/*New=*/nullptr);
|
|
|
|
P->assertInvariants();
|
|
N->assertInvariants();
|
|
}
|
|
};
|
|
|
|
void syntax::removeStatement(syntax::Arena &A, syntax::Statement *S) {
|
|
assert(S);
|
|
assert(S->canModify());
|
|
|
|
if (isa<CompoundStatement>(S->getParent())) {
|
|
// A child of CompoundStatement can just be safely removed.
|
|
MutationsImpl::remove(S);
|
|
return;
|
|
}
|
|
// For the rest, we have to replace with an empty statement.
|
|
if (isa<EmptyStatement>(S))
|
|
return; // already an empty statement, nothing to do.
|
|
|
|
MutationsImpl::replace(S, createEmptyStatement(A));
|
|
}
|