1//===- SynthesisTest.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 synthesis API for syntax trees.
10//
11//===----------------------------------------------------------------------===//
12
13#include "TreeTestBase.h"
14#include "clang/Tooling/Syntax/BuildTree.h"
15#include "clang/Tooling/Syntax/Nodes.h"
16#include "gtest/gtest.h"
17
18using namespace clang;
19using namespace clang::syntax;
20
21namespace {
22
23class SynthesisTest : public SyntaxTreeTest {
24protected:
25 ::testing::AssertionResult treeDumpEqual(syntax::Node *Root, StringRef Dump) {
26 if (!Root)
27 return ::testing::AssertionFailure()
28 << "Root was not built successfully.";
29
30 auto Actual = StringRef(Root->dump(SM: *TM)).trim().str();
31 auto Expected = Dump.trim().str();
32 // EXPECT_EQ shows the diff between the two strings if they are different.
33 EXPECT_EQ(Expected, Actual);
34 if (Actual != Expected) {
35 return ::testing::AssertionFailure();
36 }
37 return ::testing::AssertionSuccess();
38 }
39};
40
41INSTANTIATE_TEST_SUITE_P(SynthesisTests, SynthesisTest,
42 ::testing::ValuesIn(allTestClangConfigs()) );
43
44TEST_P(SynthesisTest, Leaf_Punctuation) {
45 buildTree("", GetParam());
46
47 auto *Leaf = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::comma);
48
49 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
50',' Detached synthesized
51 )txt"));
52}
53
54TEST_P(SynthesisTest, Leaf_Punctuation_CXX) {
55 if (!GetParam().isCXX())
56 return;
57
58 buildTree("", GetParam());
59
60 auto *Leaf = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::coloncolon);
61
62 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
63'::' Detached synthesized
64 )txt"));
65}
66
67TEST_P(SynthesisTest, Leaf_Keyword) {
68 buildTree("", GetParam());
69
70 auto *Leaf = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::kw_if);
71
72 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
73'if' Detached synthesized
74 )txt"));
75}
76
77TEST_P(SynthesisTest, Leaf_Keyword_CXX11) {
78 if (!GetParam().isCXX11OrLater())
79 return;
80
81 buildTree("", GetParam());
82
83 auto *Leaf = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::kw_nullptr);
84
85 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
86'nullptr' Detached synthesized
87 )txt"));
88}
89
90TEST_P(SynthesisTest, Leaf_Identifier) {
91 buildTree("", GetParam());
92
93 auto *Leaf = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::identifier, Spelling: "a");
94
95 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
96'a' Detached synthesized
97 )txt"));
98}
99
100TEST_P(SynthesisTest, Leaf_Number) {
101 buildTree("", GetParam());
102
103 auto *Leaf = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::numeric_constant, Spelling: "1");
104
105 EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
106'1' Detached synthesized
107 )txt"));
108}
109
110TEST_P(SynthesisTest, Tree_Empty) {
111 buildTree("", GetParam());
112
113 auto *Tree = createTree(*Arena, {}, NodeKind::UnknownExpression);
114
115 EXPECT_TRUE(treeDumpEqual(Tree, R"txt(
116UnknownExpression Detached synthesized
117 )txt"));
118}
119
120TEST_P(SynthesisTest, Tree_Flat) {
121 buildTree("", GetParam());
122
123 auto *LeafLParen = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::l_paren);
124 auto *LeafRParen = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::r_paren);
125 auto *TreeParen = createTree(*Arena,
126 {{LeafLParen, NodeRole::LeftHandSide},
127 {LeafRParen, NodeRole::RightHandSide}},
128 NodeKind::ParenExpression);
129
130 EXPECT_TRUE(treeDumpEqual(TreeParen, R"txt(
131ParenExpression Detached synthesized
132|-'(' LeftHandSide synthesized
133`-')' RightHandSide synthesized
134 )txt"));
135}
136
137TEST_P(SynthesisTest, Tree_OfTree) {
138 buildTree("", GetParam());
139
140 auto *Leaf1 = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::numeric_constant, Spelling: "1");
141 auto *Int1 = createTree(*Arena, {{Leaf1, NodeRole::LiteralToken}},
142 NodeKind::IntegerLiteralExpression);
143
144 auto *LeafPlus = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::plus);
145
146 auto *Leaf2 = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::numeric_constant, Spelling: "2");
147 auto *Int2 = createTree(*Arena, {{Leaf2, NodeRole::LiteralToken}},
148 NodeKind::IntegerLiteralExpression);
149
150 auto *TreeBinaryOperator = createTree(*Arena,
151 {{Int1, NodeRole::LeftHandSide},
152 {LeafPlus, NodeRole::OperatorToken},
153 {Int2, NodeRole::RightHandSide}},
154 NodeKind::BinaryOperatorExpression);
155
156 EXPECT_TRUE(treeDumpEqual(TreeBinaryOperator, R"txt(
157BinaryOperatorExpression Detached synthesized
158|-IntegerLiteralExpression LeftHandSide synthesized
159| `-'1' LiteralToken synthesized
160|-'+' OperatorToken synthesized
161`-IntegerLiteralExpression RightHandSide synthesized
162 `-'2' LiteralToken synthesized
163 )txt"));
164}
165
166TEST_P(SynthesisTest, DeepCopy_Synthesized) {
167 buildTree("", GetParam());
168
169 auto *LeafContinue = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::kw_continue);
170 auto *LeafSemiColon = createLeaf(A&: *Arena, TBTM&: *TM, K: tok::semi);
171 auto *StatementContinue = createTree(*Arena,
172 {{LeafContinue, NodeRole::LiteralToken},
173 {LeafSemiColon, NodeRole::Unknown}},
174 NodeKind::ContinueStatement);
175
176 auto *Copy = deepCopyExpandingMacros(*Arena, *TM, StatementContinue);
177 EXPECT_TRUE(treeDumpEqual(Copy, StatementContinue->dump(*TM)));
178 // FIXME: Test that copy is independent of original, once the Mutations API is
179 // more developed.
180}
181
182TEST_P(SynthesisTest, DeepCopy_Original) {
183 auto *OriginalTree = buildTree("int a;", GetParam());
184
185 auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);
186 EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
187TranslationUnit Detached synthesized
188`-SimpleDeclaration synthesized
189 |-'int' synthesized
190 |-DeclaratorList Declarators synthesized
191 | `-SimpleDeclarator ListElement synthesized
192 | `-'a' synthesized
193 `-';' synthesized
194 )txt"));
195}
196
197TEST_P(SynthesisTest, DeepCopy_Child) {
198 auto *OriginalTree = buildTree("int a;", GetParam());
199
200 auto *Copy =
201 deepCopyExpandingMacros(*Arena, *TM, OriginalTree->getFirstChild());
202 EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
203SimpleDeclaration Detached synthesized
204|-'int' synthesized
205|-DeclaratorList Declarators synthesized
206| `-SimpleDeclarator ListElement synthesized
207| `-'a' synthesized
208`-';' synthesized
209 )txt"));
210}
211
212TEST_P(SynthesisTest, DeepCopy_Macro) {
213 auto *OriginalTree = buildTree(R"cpp(
214#define HALF_IF if (1+
215#define HALF_IF_2 1) {}
216void test() {
217 HALF_IF HALF_IF_2 else {}
218})cpp",
219 GetParam());
220
221 auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);
222
223 // The syntax tree stores already expanded Tokens, we can only see whether the
224 // macro was expanded when computing replacements. The dump does show that
225 // nodes in the copy are `modifiable`.
226 EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
227TranslationUnit Detached synthesized
228`-SimpleDeclaration synthesized
229 |-'void' synthesized
230 |-DeclaratorList Declarators synthesized
231 | `-SimpleDeclarator ListElement synthesized
232 | |-'test' synthesized
233 | `-ParametersAndQualifiers synthesized
234 | |-'(' OpenParen synthesized
235 | `-')' CloseParen synthesized
236 `-CompoundStatement synthesized
237 |-'{' OpenParen synthesized
238 |-IfStatement Statement synthesized
239 | |-'if' IntroducerKeyword synthesized
240 | |-'(' synthesized
241 | |-ExpressionStatement Condition synthesized
242 | | `-BinaryOperatorExpression Expression synthesized
243 | | |-IntegerLiteralExpression LeftHandSide synthesized
244 | | | `-'1' LiteralToken synthesized
245 | | |-'+' OperatorToken synthesized
246 | | `-IntegerLiteralExpression RightHandSide synthesized
247 | | `-'1' LiteralToken synthesized
248 | |-')' synthesized
249 | |-CompoundStatement ThenStatement synthesized
250 | | |-'{' OpenParen synthesized
251 | | `-'}' CloseParen synthesized
252 | |-'else' ElseKeyword synthesized
253 | `-CompoundStatement ElseStatement synthesized
254 | |-'{' OpenParen synthesized
255 | `-'}' CloseParen synthesized
256 `-'}' CloseParen synthesized
257 )txt"));
258}
259
260TEST_P(SynthesisTest, Statement_EmptyStatement) {
261 buildTree("", GetParam());
262
263 auto *S = createEmptyStatement(A&: *Arena, TBTM&: *TM);
264 EXPECT_TRUE(treeDumpEqual(S, R"txt(
265EmptyStatement Detached synthesized
266`-';' synthesized
267 )txt"));
268}
269} // namespace
270

source code of clang/unittests/Tooling/Syntax/SynthesisTest.cpp