1c01d28dcSEduardo Caldas //===- SynthesisTest.cpp --------------------------------------------------===//
2c01d28dcSEduardo Caldas //
3c01d28dcSEduardo Caldas // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c01d28dcSEduardo Caldas // See https://llvm.org/LICENSE.txt for license information.
5c01d28dcSEduardo Caldas // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6c01d28dcSEduardo Caldas //
7c01d28dcSEduardo Caldas //===----------------------------------------------------------------------===//
8c01d28dcSEduardo Caldas //
9c01d28dcSEduardo Caldas // This file tests synthesis API for syntax trees.
10c01d28dcSEduardo Caldas //
11c01d28dcSEduardo Caldas //===----------------------------------------------------------------------===//
12c01d28dcSEduardo Caldas 
13c01d28dcSEduardo Caldas #include "TreeTestBase.h"
14c01d28dcSEduardo Caldas #include "clang/Tooling/Syntax/BuildTree.h"
157c37b82fSEduardo Caldas #include "clang/Tooling/Syntax/Nodes.h"
165d152127SEduardo Caldas #include "gtest/gtest.h"
17c01d28dcSEduardo Caldas 
18c01d28dcSEduardo Caldas using namespace clang;
19c01d28dcSEduardo Caldas using namespace clang::syntax;
20c01d28dcSEduardo Caldas 
21c01d28dcSEduardo Caldas namespace {
22c01d28dcSEduardo Caldas 
235d152127SEduardo Caldas class SynthesisTest : public SyntaxTreeTest {
245d152127SEduardo Caldas protected:
treeDumpEqual(syntax::Node * Root,StringRef Dump)255d152127SEduardo Caldas   ::testing::AssertionResult treeDumpEqual(syntax::Node *Root, StringRef Dump) {
265d152127SEduardo Caldas     if (!Root)
275d152127SEduardo Caldas       return ::testing::AssertionFailure()
285d152127SEduardo Caldas              << "Root was not built successfully.";
295d152127SEduardo Caldas 
30*263dcf45SHaojian Wu     auto Actual = StringRef(Root->dump(*TM)).trim().str();
315d152127SEduardo Caldas     auto Expected = Dump.trim().str();
325d152127SEduardo Caldas     // EXPECT_EQ shows the diff between the two strings if they are different.
335d152127SEduardo Caldas     EXPECT_EQ(Expected, Actual);
345d152127SEduardo Caldas     if (Actual != Expected) {
355d152127SEduardo Caldas       return ::testing::AssertionFailure();
365d152127SEduardo Caldas     }
375d152127SEduardo Caldas     return ::testing::AssertionSuccess();
385d152127SEduardo Caldas   }
395d152127SEduardo Caldas };
405d152127SEduardo Caldas 
41d4d80a29SBenjamin Kramer INSTANTIATE_TEST_SUITE_P(SynthesisTests, SynthesisTest,
42d4d80a29SBenjamin Kramer                         ::testing::ValuesIn(allTestClangConfigs()) );
43c01d28dcSEduardo Caldas 
TEST_P(SynthesisTest,Leaf_Punctuation)445d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Punctuation) {
45c01d28dcSEduardo Caldas   buildTree("", GetParam());
46c01d28dcSEduardo Caldas 
47*263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::comma);
485d152127SEduardo Caldas 
495d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
505d152127SEduardo Caldas ',' Detached synthesized
515d152127SEduardo Caldas   )txt"));
52c01d28dcSEduardo Caldas }
53c01d28dcSEduardo Caldas 
TEST_P(SynthesisTest,Leaf_Punctuation_CXX)54bb5b28f1SEduardo Caldas TEST_P(SynthesisTest, Leaf_Punctuation_CXX) {
55bb5b28f1SEduardo Caldas   if (!GetParam().isCXX())
56bb5b28f1SEduardo Caldas     return;
57bb5b28f1SEduardo Caldas 
58bb5b28f1SEduardo Caldas   buildTree("", GetParam());
59bb5b28f1SEduardo Caldas 
60*263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::coloncolon);
61bb5b28f1SEduardo Caldas 
62bb5b28f1SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
63bb5b28f1SEduardo Caldas '::' Detached synthesized
64bb5b28f1SEduardo Caldas   )txt"));
65bb5b28f1SEduardo Caldas }
66bb5b28f1SEduardo Caldas 
TEST_P(SynthesisTest,Leaf_Keyword)675d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Keyword) {
68c01d28dcSEduardo Caldas   buildTree("", GetParam());
69c01d28dcSEduardo Caldas 
70*263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::kw_if);
715d152127SEduardo Caldas 
725d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
735d152127SEduardo Caldas 'if' Detached synthesized
745d152127SEduardo Caldas   )txt"));
755d152127SEduardo Caldas }
765d152127SEduardo Caldas 
TEST_P(SynthesisTest,Leaf_Keyword_CXX11)77bb5b28f1SEduardo Caldas TEST_P(SynthesisTest, Leaf_Keyword_CXX11) {
78bb5b28f1SEduardo Caldas   if (!GetParam().isCXX11OrLater())
79bb5b28f1SEduardo Caldas     return;
80bb5b28f1SEduardo Caldas 
81bb5b28f1SEduardo Caldas   buildTree("", GetParam());
82bb5b28f1SEduardo Caldas 
83*263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::kw_nullptr);
84bb5b28f1SEduardo Caldas 
85bb5b28f1SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
86bb5b28f1SEduardo Caldas 'nullptr' Detached synthesized
87bb5b28f1SEduardo Caldas   )txt"));
88bb5b28f1SEduardo Caldas }
89bb5b28f1SEduardo Caldas 
TEST_P(SynthesisTest,Leaf_Identifier)905d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Identifier) {
915d152127SEduardo Caldas   buildTree("", GetParam());
925d152127SEduardo Caldas 
93*263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::identifier, "a");
945d152127SEduardo Caldas 
955d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
965d152127SEduardo Caldas 'a' Detached synthesized
975d152127SEduardo Caldas   )txt"));
985d152127SEduardo Caldas }
995d152127SEduardo Caldas 
TEST_P(SynthesisTest,Leaf_Number)1005d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Number) {
1015d152127SEduardo Caldas   buildTree("", GetParam());
1025d152127SEduardo Caldas 
103*263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::numeric_constant, "1");
1045d152127SEduardo Caldas 
1055d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
1065d152127SEduardo Caldas '1' Detached synthesized
1075d152127SEduardo Caldas   )txt"));
1085d152127SEduardo Caldas }
1095d152127SEduardo Caldas 
TEST_P(SynthesisTest,Tree_Empty)1107c37b82fSEduardo Caldas TEST_P(SynthesisTest, Tree_Empty) {
1117c37b82fSEduardo Caldas   buildTree("", GetParam());
1127c37b82fSEduardo Caldas 
1137c37b82fSEduardo Caldas   auto *Tree = createTree(*Arena, {}, NodeKind::UnknownExpression);
1147c37b82fSEduardo Caldas 
1157c37b82fSEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Tree, R"txt(
1167c37b82fSEduardo Caldas UnknownExpression Detached synthesized
1177c37b82fSEduardo Caldas   )txt"));
1187c37b82fSEduardo Caldas }
1197c37b82fSEduardo Caldas 
TEST_P(SynthesisTest,Tree_Flat)1207c37b82fSEduardo Caldas TEST_P(SynthesisTest, Tree_Flat) {
1217c37b82fSEduardo Caldas   buildTree("", GetParam());
1227c37b82fSEduardo Caldas 
123*263dcf45SHaojian Wu   auto *LeafLParen = createLeaf(*Arena, *TM, tok::l_paren);
124*263dcf45SHaojian Wu   auto *LeafRParen = createLeaf(*Arena, *TM, tok::r_paren);
1257c37b82fSEduardo Caldas   auto *TreeParen = createTree(*Arena,
1267c37b82fSEduardo Caldas                                {{LeafLParen, NodeRole::LeftHandSide},
1277c37b82fSEduardo Caldas                                 {LeafRParen, NodeRole::RightHandSide}},
1287c37b82fSEduardo Caldas                                NodeKind::ParenExpression);
1297c37b82fSEduardo Caldas 
1307c37b82fSEduardo Caldas   EXPECT_TRUE(treeDumpEqual(TreeParen, R"txt(
1317c37b82fSEduardo Caldas ParenExpression Detached synthesized
1327c37b82fSEduardo Caldas |-'(' LeftHandSide synthesized
1337c37b82fSEduardo Caldas `-')' RightHandSide synthesized
1347c37b82fSEduardo Caldas   )txt"));
1357c37b82fSEduardo Caldas }
1367c37b82fSEduardo Caldas 
TEST_P(SynthesisTest,Tree_OfTree)1377c37b82fSEduardo Caldas TEST_P(SynthesisTest, Tree_OfTree) {
1387c37b82fSEduardo Caldas   buildTree("", GetParam());
1397c37b82fSEduardo Caldas 
140*263dcf45SHaojian Wu   auto *Leaf1 = createLeaf(*Arena, *TM, tok::numeric_constant, "1");
1417c37b82fSEduardo Caldas   auto *Int1 = createTree(*Arena, {{Leaf1, NodeRole::LiteralToken}},
1427c37b82fSEduardo Caldas                           NodeKind::IntegerLiteralExpression);
1437c37b82fSEduardo Caldas 
144*263dcf45SHaojian Wu   auto *LeafPlus = createLeaf(*Arena, *TM, tok::plus);
1457c37b82fSEduardo Caldas 
146*263dcf45SHaojian Wu   auto *Leaf2 = createLeaf(*Arena, *TM, tok::numeric_constant, "2");
1477c37b82fSEduardo Caldas   auto *Int2 = createTree(*Arena, {{Leaf2, NodeRole::LiteralToken}},
1487c37b82fSEduardo Caldas                           NodeKind::IntegerLiteralExpression);
1497c37b82fSEduardo Caldas 
1507c37b82fSEduardo Caldas   auto *TreeBinaryOperator = createTree(*Arena,
1517c37b82fSEduardo Caldas                                         {{Int1, NodeRole::LeftHandSide},
1527c37b82fSEduardo Caldas                                          {LeafPlus, NodeRole::OperatorToken},
1537c37b82fSEduardo Caldas                                          {Int2, NodeRole::RightHandSide}},
1547c37b82fSEduardo Caldas                                         NodeKind::BinaryOperatorExpression);
1557c37b82fSEduardo Caldas 
1567c37b82fSEduardo Caldas   EXPECT_TRUE(treeDumpEqual(TreeBinaryOperator, R"txt(
1577c37b82fSEduardo Caldas BinaryOperatorExpression Detached synthesized
1587c37b82fSEduardo Caldas |-IntegerLiteralExpression LeftHandSide synthesized
1597c37b82fSEduardo Caldas | `-'1' LiteralToken synthesized
1607c37b82fSEduardo Caldas |-'+' OperatorToken synthesized
1617c37b82fSEduardo Caldas `-IntegerLiteralExpression RightHandSide synthesized
1627c37b82fSEduardo Caldas   `-'2' LiteralToken synthesized
1637c37b82fSEduardo Caldas   )txt"));
1647c37b82fSEduardo Caldas }
1657c37b82fSEduardo Caldas 
TEST_P(SynthesisTest,DeepCopy_Synthesized)1664a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Synthesized) {
1674a5cc389SEduardo Caldas   buildTree("", GetParam());
1684a5cc389SEduardo Caldas 
169*263dcf45SHaojian Wu   auto *LeafContinue = createLeaf(*Arena, *TM, tok::kw_continue);
170*263dcf45SHaojian Wu   auto *LeafSemiColon = createLeaf(*Arena, *TM, tok::semi);
1714a5cc389SEduardo Caldas   auto *StatementContinue = createTree(*Arena,
1724a5cc389SEduardo Caldas                                        {{LeafContinue, NodeRole::LiteralToken},
1734a5cc389SEduardo Caldas                                         {LeafSemiColon, NodeRole::Unknown}},
1744a5cc389SEduardo Caldas                                        NodeKind::ContinueStatement);
1754a5cc389SEduardo Caldas 
176*263dcf45SHaojian Wu   auto *Copy = deepCopyExpandingMacros(*Arena, *TM, StatementContinue);
177*263dcf45SHaojian Wu   EXPECT_TRUE(treeDumpEqual(Copy, StatementContinue->dump(*TM)));
1784a5cc389SEduardo Caldas   // FIXME: Test that copy is independent of original, once the Mutations API is
1794a5cc389SEduardo Caldas   // more developed.
1804a5cc389SEduardo Caldas }
1814a5cc389SEduardo Caldas 
TEST_P(SynthesisTest,DeepCopy_Original)1824a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Original) {
1834a5cc389SEduardo Caldas   auto *OriginalTree = buildTree("int a;", GetParam());
1844a5cc389SEduardo Caldas 
185*263dcf45SHaojian Wu   auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);
1864a5cc389SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
1874a5cc389SEduardo Caldas TranslationUnit Detached synthesized
1884a5cc389SEduardo Caldas `-SimpleDeclaration synthesized
1894a5cc389SEduardo Caldas   |-'int' synthesized
1905011d431SEduardo Caldas   |-DeclaratorList Declarators synthesized
1915011d431SEduardo Caldas   | `-SimpleDeclarator ListElement synthesized
1924a5cc389SEduardo Caldas   |   `-'a' synthesized
1934a5cc389SEduardo Caldas   `-';' synthesized
1944a5cc389SEduardo Caldas   )txt"));
1954a5cc389SEduardo Caldas }
1964a5cc389SEduardo Caldas 
TEST_P(SynthesisTest,DeepCopy_Child)1974a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Child) {
1984a5cc389SEduardo Caldas   auto *OriginalTree = buildTree("int a;", GetParam());
1994a5cc389SEduardo Caldas 
200*263dcf45SHaojian Wu   auto *Copy =
201*263dcf45SHaojian Wu       deepCopyExpandingMacros(*Arena, *TM, OriginalTree->getFirstChild());
2024a5cc389SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
2034a5cc389SEduardo Caldas SimpleDeclaration Detached synthesized
2044a5cc389SEduardo Caldas |-'int' synthesized
2055011d431SEduardo Caldas |-DeclaratorList Declarators synthesized
2065011d431SEduardo Caldas | `-SimpleDeclarator ListElement synthesized
2074a5cc389SEduardo Caldas |   `-'a' synthesized
2084a5cc389SEduardo Caldas `-';' synthesized
2094a5cc389SEduardo Caldas   )txt"));
2104a5cc389SEduardo Caldas }
2114a5cc389SEduardo Caldas 
TEST_P(SynthesisTest,DeepCopy_Macro)2124a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Macro) {
2134a5cc389SEduardo Caldas   auto *OriginalTree = buildTree(R"cpp(
2144a5cc389SEduardo Caldas #define HALF_IF if (1+
2154a5cc389SEduardo Caldas #define HALF_IF_2 1) {}
2164a5cc389SEduardo Caldas void test() {
2174a5cc389SEduardo Caldas   HALF_IF HALF_IF_2 else {}
2184a5cc389SEduardo Caldas })cpp",
2194a5cc389SEduardo Caldas                                  GetParam());
2204a5cc389SEduardo Caldas 
221*263dcf45SHaojian Wu   auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);
22266bcb143SEduardo Caldas 
22366bcb143SEduardo Caldas   // The syntax tree stores already expanded Tokens, we can only see whether the
22466bcb143SEduardo Caldas   // macro was expanded when computing replacements. The dump does show that
22566bcb143SEduardo Caldas   // nodes in the copy are `modifiable`.
22666bcb143SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
22766bcb143SEduardo Caldas TranslationUnit Detached synthesized
22866bcb143SEduardo Caldas `-SimpleDeclaration synthesized
22966bcb143SEduardo Caldas   |-'void' synthesized
2305011d431SEduardo Caldas   |-DeclaratorList Declarators synthesized
2315011d431SEduardo Caldas   | `-SimpleDeclarator ListElement synthesized
23266bcb143SEduardo Caldas   |   |-'test' synthesized
23366bcb143SEduardo Caldas   |   `-ParametersAndQualifiers synthesized
23466bcb143SEduardo Caldas   |     |-'(' OpenParen synthesized
23566bcb143SEduardo Caldas   |     `-')' CloseParen synthesized
23666bcb143SEduardo Caldas   `-CompoundStatement synthesized
23766bcb143SEduardo Caldas     |-'{' OpenParen synthesized
23866bcb143SEduardo Caldas     |-IfStatement Statement synthesized
23966bcb143SEduardo Caldas     | |-'if' IntroducerKeyword synthesized
24066bcb143SEduardo Caldas     | |-'(' synthesized
2416c1a2330SHaojian Wu     | |-ExpressionStatement Condition synthesized
2426c1a2330SHaojian Wu     | | `-BinaryOperatorExpression Expression synthesized
24366bcb143SEduardo Caldas     | |   |-IntegerLiteralExpression LeftHandSide synthesized
24466bcb143SEduardo Caldas     | |   | `-'1' LiteralToken synthesized
24566bcb143SEduardo Caldas     | |   |-'+' OperatorToken synthesized
24666bcb143SEduardo Caldas     | |   `-IntegerLiteralExpression RightHandSide synthesized
24766bcb143SEduardo Caldas     | |     `-'1' LiteralToken synthesized
24866bcb143SEduardo Caldas     | |-')' synthesized
24966bcb143SEduardo Caldas     | |-CompoundStatement ThenStatement synthesized
25066bcb143SEduardo Caldas     | | |-'{' OpenParen synthesized
25166bcb143SEduardo Caldas     | | `-'}' CloseParen synthesized
25266bcb143SEduardo Caldas     | |-'else' ElseKeyword synthesized
25366bcb143SEduardo Caldas     | `-CompoundStatement ElseStatement synthesized
25466bcb143SEduardo Caldas     |   |-'{' OpenParen synthesized
25566bcb143SEduardo Caldas     |   `-'}' CloseParen synthesized
25666bcb143SEduardo Caldas     `-'}' CloseParen synthesized
25766bcb143SEduardo Caldas   )txt"));
2584a5cc389SEduardo Caldas }
2594a5cc389SEduardo Caldas 
TEST_P(SynthesisTest,Statement_EmptyStatement)2605d152127SEduardo Caldas TEST_P(SynthesisTest, Statement_EmptyStatement) {
2615d152127SEduardo Caldas   buildTree("", GetParam());
2625d152127SEduardo Caldas 
263*263dcf45SHaojian Wu   auto *S = createEmptyStatement(*Arena, *TM);
2645d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(S, R"txt(
2655d152127SEduardo Caldas EmptyStatement Detached synthesized
2665d152127SEduardo Caldas `-';' synthesized
2675d152127SEduardo Caldas   )txt"));
268c01d28dcSEduardo Caldas }
269c01d28dcSEduardo Caldas } // namespace
270