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