1 //===- SynthesisTest.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This file tests synthesis API for syntax trees.
11 //===----------------------------------------------------------------------===//
13 #include "TreeTestBase.h"
14 #include "clang/Tooling/Syntax/BuildTree.h"
15 #include "clang/Tooling/Syntax/Nodes.h"
16 #include "gtest/gtest.h"
18 using namespace clang
;
19 using namespace clang::syntax
;
23 class SynthesisTest
: public SyntaxTreeTest
{
25 ::testing::AssertionResult
treeDumpEqual(syntax::Node
*Root
, StringRef Dump
) {
27 return ::testing::AssertionFailure()
28 << "Root was not built successfully.";
30 auto Actual
= StringRef(Root
->dump(*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();
37 return ::testing::AssertionSuccess();
41 INSTANTIATE_TEST_SUITE_P(SynthesisTests
, SynthesisTest
,
42 ::testing::ValuesIn(allTestClangConfigs()) );
44 TEST_P(SynthesisTest
, Leaf_Punctuation
) {
45 buildTree("", GetParam());
47 auto *Leaf
= createLeaf(*Arena
, *TM
, tok::comma
);
49 EXPECT_TRUE(treeDumpEqual(Leaf
, R
"txt(
50 ',' Detached synthesized
54 TEST_P(SynthesisTest
, Leaf_Punctuation_CXX
) {
55 if (!GetParam().isCXX())
58 buildTree("", GetParam());
60 auto *Leaf
= createLeaf(*Arena
, *TM
, tok::coloncolon
);
62 EXPECT_TRUE(treeDumpEqual(Leaf
, R
"txt(
63 '::' Detached synthesized
67 TEST_P(SynthesisTest
, Leaf_Keyword
) {
68 buildTree("", GetParam());
70 auto *Leaf
= createLeaf(*Arena
, *TM
, tok::kw_if
);
72 EXPECT_TRUE(treeDumpEqual(Leaf
, R
"txt(
73 'if' Detached synthesized
77 TEST_P(SynthesisTest
, Leaf_Keyword_CXX11
) {
78 if (!GetParam().isCXX11OrLater())
81 buildTree("", GetParam());
83 auto *Leaf
= createLeaf(*Arena
, *TM
, tok::kw_nullptr
);
85 EXPECT_TRUE(treeDumpEqual(Leaf
, R
"txt(
86 'nullptr' Detached synthesized
90 TEST_P(SynthesisTest
, Leaf_Identifier
) {
91 buildTree("", GetParam());
93 auto *Leaf
= createLeaf(*Arena
, *TM
, tok::identifier
, "a");
95 EXPECT_TRUE(treeDumpEqual(Leaf
, R
"txt(
96 'a' Detached synthesized
100 TEST_P(SynthesisTest
, Leaf_Number
) {
101 buildTree("", GetParam());
103 auto *Leaf
= createLeaf(*Arena
, *TM
, tok::numeric_constant
, "1");
105 EXPECT_TRUE(treeDumpEqual(Leaf
, R
"txt(
106 '1' Detached synthesized
110 TEST_P(SynthesisTest
, Tree_Empty
) {
111 buildTree("", GetParam());
113 auto *Tree
= createTree(*Arena
, {}, NodeKind::UnknownExpression
);
115 EXPECT_TRUE(treeDumpEqual(Tree
, R
"txt(
116 UnknownExpression Detached synthesized
120 TEST_P(SynthesisTest
, Tree_Flat
) {
121 buildTree("", GetParam());
123 auto *LeafLParen
= createLeaf(*Arena
, *TM
, tok::l_paren
);
124 auto *LeafRParen
= createLeaf(*Arena
, *TM
, tok::r_paren
);
125 auto *TreeParen
= createTree(*Arena
,
126 {{LeafLParen
, NodeRole::LeftHandSide
},
127 {LeafRParen
, NodeRole::RightHandSide
}},
128 NodeKind::ParenExpression
);
130 EXPECT_TRUE(treeDumpEqual(TreeParen
, R
"txt(
131 ParenExpression Detached synthesized
132 |-'(' LeftHandSide synthesized
133 `-')' RightHandSide synthesized
137 TEST_P(SynthesisTest
, Tree_OfTree
) {
138 buildTree("", GetParam());
140 auto *Leaf1
= createLeaf(*Arena
, *TM
, tok::numeric_constant
, "1");
141 auto *Int1
= createTree(*Arena
, {{Leaf1
, NodeRole::LiteralToken
}},
142 NodeKind::IntegerLiteralExpression
);
144 auto *LeafPlus
= createLeaf(*Arena
, *TM
, tok::plus
);
146 auto *Leaf2
= createLeaf(*Arena
, *TM
, tok::numeric_constant
, "2");
147 auto *Int2
= createTree(*Arena
, {{Leaf2
, NodeRole::LiteralToken
}},
148 NodeKind::IntegerLiteralExpression
);
150 auto *TreeBinaryOperator
= createTree(*Arena
,
151 {{Int1
, NodeRole::LeftHandSide
},
152 {LeafPlus
, NodeRole::OperatorToken
},
153 {Int2
, NodeRole::RightHandSide
}},
154 NodeKind::BinaryOperatorExpression
);
156 EXPECT_TRUE(treeDumpEqual(TreeBinaryOperator
, R
"txt(
157 BinaryOperatorExpression Detached synthesized
158 |-IntegerLiteralExpression LeftHandSide synthesized
159 | `-'1' LiteralToken synthesized
160 |-'+' OperatorToken synthesized
161 `-IntegerLiteralExpression RightHandSide synthesized
162 `-'2' LiteralToken synthesized
166 TEST_P(SynthesisTest
, DeepCopy_Synthesized
) {
167 buildTree("", GetParam());
169 auto *LeafContinue
= createLeaf(*Arena
, *TM
, tok::kw_continue
);
170 auto *LeafSemiColon
= createLeaf(*Arena
, *TM
, tok::semi
);
171 auto *StatementContinue
= createTree(*Arena
,
172 {{LeafContinue
, NodeRole::LiteralToken
},
173 {LeafSemiColon
, NodeRole::Unknown
}},
174 NodeKind::ContinueStatement
);
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
182 TEST_P(SynthesisTest
, DeepCopy_Original
) {
183 auto *OriginalTree
= buildTree("int a;", GetParam());
185 auto *Copy
= deepCopyExpandingMacros(*Arena
, *TM
, OriginalTree
);
186 EXPECT_TRUE(treeDumpEqual(Copy
, R
"txt(
187 TranslationUnit Detached synthesized
188 `-SimpleDeclaration synthesized
190 |-DeclaratorList Declarators synthesized
191 | `-SimpleDeclarator ListElement synthesized
197 TEST_P(SynthesisTest
, DeepCopy_Child
) {
198 auto *OriginalTree
= buildTree("int a;", GetParam());
201 deepCopyExpandingMacros(*Arena
, *TM
, OriginalTree
->getFirstChild());
202 EXPECT_TRUE(treeDumpEqual(Copy
, R
"txt(
203 SimpleDeclaration Detached synthesized
205 |-DeclaratorList Declarators synthesized
206 | `-SimpleDeclarator ListElement synthesized
212 TEST_P(SynthesisTest
, DeepCopy_Macro
) {
213 auto *OriginalTree
= buildTree(R
"cpp(
214 #define HALF_IF if (1+
215 #define HALF_IF_2 1) {}
217 HALF_IF HALF_IF_2 else {}
221 auto *Copy
= deepCopyExpandingMacros(*Arena
, *TM
, OriginalTree
);
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(
227 TranslationUnit Detached synthesized
228 `-SimpleDeclaration 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
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
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
260 TEST_P(SynthesisTest
, Statement_EmptyStatement
) {
261 buildTree("", GetParam());
263 auto *S
= createEmptyStatement(*Arena
, *TM
);
264 EXPECT_TRUE(treeDumpEqual(S
, R
"txt(
265 EmptyStatement Detached synthesized