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