1*d17437d2SEduardo Caldas //===- MutationsTest.cpp --------------------------------------------------===// 2*d17437d2SEduardo Caldas // 3*d17437d2SEduardo Caldas // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*d17437d2SEduardo Caldas // See https://llvm.org/LICENSE.txt for license information. 5*d17437d2SEduardo Caldas // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*d17437d2SEduardo Caldas // 7*d17437d2SEduardo Caldas //===----------------------------------------------------------------------===// 8*d17437d2SEduardo Caldas // 9*d17437d2SEduardo Caldas // This file tests mutation API for syntax trees. 10*d17437d2SEduardo Caldas // 11*d17437d2SEduardo Caldas //===----------------------------------------------------------------------===// 12*d17437d2SEduardo Caldas 13*d17437d2SEduardo Caldas #include "TreeTestBase.h" 14*d17437d2SEduardo Caldas 15*d17437d2SEduardo Caldas namespace clang { 16*d17437d2SEduardo Caldas namespace syntax { 17*d17437d2SEduardo Caldas namespace { 18*d17437d2SEduardo Caldas 19*d17437d2SEduardo Caldas TEST_P(SyntaxTreeTest, Mutations) { 20*d17437d2SEduardo Caldas if (!GetParam().isCXX11OrLater()) { 21*d17437d2SEduardo Caldas return; 22*d17437d2SEduardo Caldas } 23*d17437d2SEduardo Caldas 24*d17437d2SEduardo Caldas using Transformation = std::function<void( 25*d17437d2SEduardo Caldas const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>; 26*d17437d2SEduardo Caldas auto CheckTransformation = [this](std::string Input, std::string Expected, 27*d17437d2SEduardo Caldas Transformation Transform) -> void { 28*d17437d2SEduardo Caldas llvm::Annotations Source(Input); 29*d17437d2SEduardo Caldas auto *Root = buildTree(Source.code(), GetParam()); 30*d17437d2SEduardo Caldas 31*d17437d2SEduardo Caldas Transform(Source, Root); 32*d17437d2SEduardo Caldas 33*d17437d2SEduardo Caldas auto Replacements = syntax::computeReplacements(*Arena, *Root); 34*d17437d2SEduardo Caldas auto Output = tooling::applyAllReplacements(Source.code(), Replacements); 35*d17437d2SEduardo Caldas if (!Output) { 36*d17437d2SEduardo Caldas ADD_FAILURE() << "could not apply replacements: " 37*d17437d2SEduardo Caldas << llvm::toString(Output.takeError()); 38*d17437d2SEduardo Caldas return; 39*d17437d2SEduardo Caldas } 40*d17437d2SEduardo Caldas 41*d17437d2SEduardo Caldas EXPECT_EQ(Expected, *Output) << "input is:\n" << Input; 42*d17437d2SEduardo Caldas }; 43*d17437d2SEduardo Caldas 44*d17437d2SEduardo Caldas // Removes the selected statement. Input should have exactly one selected 45*d17437d2SEduardo Caldas // range and it should correspond to a single statement. 46*d17437d2SEduardo Caldas auto RemoveStatement = [this](const llvm::Annotations &Input, 47*d17437d2SEduardo Caldas syntax::TranslationUnit *TU) { 48*d17437d2SEduardo Caldas auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU)); 49*d17437d2SEduardo Caldas ASSERT_TRUE(S->canModify()) << "cannot remove a statement"; 50*d17437d2SEduardo Caldas syntax::removeStatement(*Arena, S); 51*d17437d2SEduardo Caldas EXPECT_TRUE(S->isDetached()); 52*d17437d2SEduardo Caldas EXPECT_FALSE(S->isOriginal()) 53*d17437d2SEduardo Caldas << "node removed from tree cannot be marked as original"; 54*d17437d2SEduardo Caldas }; 55*d17437d2SEduardo Caldas 56*d17437d2SEduardo Caldas std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>> 57*d17437d2SEduardo Caldas Cases = { 58*d17437d2SEduardo Caldas {"void test() { [[100+100;]] test(); }", "void test() { test(); }"}, 59*d17437d2SEduardo Caldas {"void test() { if (true) [[{}]] else {} }", 60*d17437d2SEduardo Caldas "void test() { if (true) ; else {} }"}, 61*d17437d2SEduardo Caldas {"void test() { [[;]] }", "void test() { }"}}; 62*d17437d2SEduardo Caldas for (const auto &C : Cases) 63*d17437d2SEduardo Caldas CheckTransformation(C.first, C.second, RemoveStatement); 64*d17437d2SEduardo Caldas } 65*d17437d2SEduardo Caldas 66*d17437d2SEduardo Caldas TEST_P(SyntaxTreeTest, SynthesizedNodes) { 67*d17437d2SEduardo Caldas buildTree("", GetParam()); 68*d17437d2SEduardo Caldas 69*d17437d2SEduardo Caldas auto *C = syntax::createPunctuation(*Arena, tok::comma); 70*d17437d2SEduardo Caldas ASSERT_NE(C, nullptr); 71*d17437d2SEduardo Caldas EXPECT_EQ(C->token()->kind(), tok::comma); 72*d17437d2SEduardo Caldas EXPECT_TRUE(C->canModify()); 73*d17437d2SEduardo Caldas EXPECT_FALSE(C->isOriginal()); 74*d17437d2SEduardo Caldas EXPECT_TRUE(C->isDetached()); 75*d17437d2SEduardo Caldas 76*d17437d2SEduardo Caldas auto *S = syntax::createEmptyStatement(*Arena); 77*d17437d2SEduardo Caldas ASSERT_NE(S, nullptr); 78*d17437d2SEduardo Caldas EXPECT_TRUE(S->canModify()); 79*d17437d2SEduardo Caldas EXPECT_FALSE(S->isOriginal()); 80*d17437d2SEduardo Caldas EXPECT_TRUE(S->isDetached()); 81*d17437d2SEduardo Caldas } 82*d17437d2SEduardo Caldas } // namespace 83*d17437d2SEduardo Caldas } // namespace syntax 84*d17437d2SEduardo Caldas } // namespace clang 85