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