xref: /llvm-project/clang/unittests/Tooling/Syntax/SynthesisTest.cpp (revision 7dfdca1961aadc75ca397818bfb9bd32f1879248)
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:
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 
30263dcf45SHaojian 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 
41*7dfdca19SJulian Schmidt INSTANTIATE_TEST_SUITE_P(
42*7dfdca19SJulian Schmidt     SynthesisTests, SynthesisTest, ::testing::ValuesIn(allTestClangConfigs()),
43*7dfdca19SJulian Schmidt     [](const testing::TestParamInfo<TestClangConfig> &Info) {
44*7dfdca19SJulian Schmidt       return Info.param.toShortString();
45*7dfdca19SJulian Schmidt     });
46c01d28dcSEduardo Caldas 
475d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Punctuation) {
48c01d28dcSEduardo Caldas   buildTree("", GetParam());
49c01d28dcSEduardo Caldas 
50263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::comma);
515d152127SEduardo Caldas 
525d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
535d152127SEduardo Caldas ',' Detached synthesized
545d152127SEduardo Caldas   )txt"));
55c01d28dcSEduardo Caldas }
56c01d28dcSEduardo Caldas 
57bb5b28f1SEduardo Caldas TEST_P(SynthesisTest, Leaf_Punctuation_CXX) {
58bb5b28f1SEduardo Caldas   if (!GetParam().isCXX())
59bb5b28f1SEduardo Caldas     return;
60bb5b28f1SEduardo Caldas 
61bb5b28f1SEduardo Caldas   buildTree("", GetParam());
62bb5b28f1SEduardo Caldas 
63263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::coloncolon);
64bb5b28f1SEduardo Caldas 
65bb5b28f1SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
66bb5b28f1SEduardo Caldas '::' Detached synthesized
67bb5b28f1SEduardo Caldas   )txt"));
68bb5b28f1SEduardo Caldas }
69bb5b28f1SEduardo Caldas 
705d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Keyword) {
71c01d28dcSEduardo Caldas   buildTree("", GetParam());
72c01d28dcSEduardo Caldas 
73263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::kw_if);
745d152127SEduardo Caldas 
755d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
765d152127SEduardo Caldas 'if' Detached synthesized
775d152127SEduardo Caldas   )txt"));
785d152127SEduardo Caldas }
795d152127SEduardo Caldas 
80bb5b28f1SEduardo Caldas TEST_P(SynthesisTest, Leaf_Keyword_CXX11) {
81bb5b28f1SEduardo Caldas   if (!GetParam().isCXX11OrLater())
82bb5b28f1SEduardo Caldas     return;
83bb5b28f1SEduardo Caldas 
84bb5b28f1SEduardo Caldas   buildTree("", GetParam());
85bb5b28f1SEduardo Caldas 
86263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::kw_nullptr);
87bb5b28f1SEduardo Caldas 
88bb5b28f1SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
89bb5b28f1SEduardo Caldas 'nullptr' Detached synthesized
90bb5b28f1SEduardo Caldas   )txt"));
91bb5b28f1SEduardo Caldas }
92bb5b28f1SEduardo Caldas 
935d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Identifier) {
945d152127SEduardo Caldas   buildTree("", GetParam());
955d152127SEduardo Caldas 
96263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::identifier, "a");
975d152127SEduardo Caldas 
985d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
995d152127SEduardo Caldas 'a' Detached synthesized
1005d152127SEduardo Caldas   )txt"));
1015d152127SEduardo Caldas }
1025d152127SEduardo Caldas 
1035d152127SEduardo Caldas TEST_P(SynthesisTest, Leaf_Number) {
1045d152127SEduardo Caldas   buildTree("", GetParam());
1055d152127SEduardo Caldas 
106263dcf45SHaojian Wu   auto *Leaf = createLeaf(*Arena, *TM, tok::numeric_constant, "1");
1075d152127SEduardo Caldas 
1085d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
1095d152127SEduardo Caldas '1' Detached synthesized
1105d152127SEduardo Caldas   )txt"));
1115d152127SEduardo Caldas }
1125d152127SEduardo Caldas 
1137c37b82fSEduardo Caldas TEST_P(SynthesisTest, Tree_Empty) {
1147c37b82fSEduardo Caldas   buildTree("", GetParam());
1157c37b82fSEduardo Caldas 
1167c37b82fSEduardo Caldas   auto *Tree = createTree(*Arena, {}, NodeKind::UnknownExpression);
1177c37b82fSEduardo Caldas 
1187c37b82fSEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Tree, R"txt(
1197c37b82fSEduardo Caldas UnknownExpression Detached synthesized
1207c37b82fSEduardo Caldas   )txt"));
1217c37b82fSEduardo Caldas }
1227c37b82fSEduardo Caldas 
1237c37b82fSEduardo Caldas TEST_P(SynthesisTest, Tree_Flat) {
1247c37b82fSEduardo Caldas   buildTree("", GetParam());
1257c37b82fSEduardo Caldas 
126263dcf45SHaojian Wu   auto *LeafLParen = createLeaf(*Arena, *TM, tok::l_paren);
127263dcf45SHaojian Wu   auto *LeafRParen = createLeaf(*Arena, *TM, tok::r_paren);
1287c37b82fSEduardo Caldas   auto *TreeParen = createTree(*Arena,
1297c37b82fSEduardo Caldas                                {{LeafLParen, NodeRole::LeftHandSide},
1307c37b82fSEduardo Caldas                                 {LeafRParen, NodeRole::RightHandSide}},
1317c37b82fSEduardo Caldas                                NodeKind::ParenExpression);
1327c37b82fSEduardo Caldas 
1337c37b82fSEduardo Caldas   EXPECT_TRUE(treeDumpEqual(TreeParen, R"txt(
1347c37b82fSEduardo Caldas ParenExpression Detached synthesized
1357c37b82fSEduardo Caldas |-'(' LeftHandSide synthesized
1367c37b82fSEduardo Caldas `-')' RightHandSide synthesized
1377c37b82fSEduardo Caldas   )txt"));
1387c37b82fSEduardo Caldas }
1397c37b82fSEduardo Caldas 
1407c37b82fSEduardo Caldas TEST_P(SynthesisTest, Tree_OfTree) {
1417c37b82fSEduardo Caldas   buildTree("", GetParam());
1427c37b82fSEduardo Caldas 
143263dcf45SHaojian Wu   auto *Leaf1 = createLeaf(*Arena, *TM, tok::numeric_constant, "1");
1447c37b82fSEduardo Caldas   auto *Int1 = createTree(*Arena, {{Leaf1, NodeRole::LiteralToken}},
1457c37b82fSEduardo Caldas                           NodeKind::IntegerLiteralExpression);
1467c37b82fSEduardo Caldas 
147263dcf45SHaojian Wu   auto *LeafPlus = createLeaf(*Arena, *TM, tok::plus);
1487c37b82fSEduardo Caldas 
149263dcf45SHaojian Wu   auto *Leaf2 = createLeaf(*Arena, *TM, tok::numeric_constant, "2");
1507c37b82fSEduardo Caldas   auto *Int2 = createTree(*Arena, {{Leaf2, NodeRole::LiteralToken}},
1517c37b82fSEduardo Caldas                           NodeKind::IntegerLiteralExpression);
1527c37b82fSEduardo Caldas 
1537c37b82fSEduardo Caldas   auto *TreeBinaryOperator = createTree(*Arena,
1547c37b82fSEduardo Caldas                                         {{Int1, NodeRole::LeftHandSide},
1557c37b82fSEduardo Caldas                                          {LeafPlus, NodeRole::OperatorToken},
1567c37b82fSEduardo Caldas                                          {Int2, NodeRole::RightHandSide}},
1577c37b82fSEduardo Caldas                                         NodeKind::BinaryOperatorExpression);
1587c37b82fSEduardo Caldas 
1597c37b82fSEduardo Caldas   EXPECT_TRUE(treeDumpEqual(TreeBinaryOperator, R"txt(
1607c37b82fSEduardo Caldas BinaryOperatorExpression Detached synthesized
1617c37b82fSEduardo Caldas |-IntegerLiteralExpression LeftHandSide synthesized
1627c37b82fSEduardo Caldas | `-'1' LiteralToken synthesized
1637c37b82fSEduardo Caldas |-'+' OperatorToken synthesized
1647c37b82fSEduardo Caldas `-IntegerLiteralExpression RightHandSide synthesized
1657c37b82fSEduardo Caldas   `-'2' LiteralToken synthesized
1667c37b82fSEduardo Caldas   )txt"));
1677c37b82fSEduardo Caldas }
1687c37b82fSEduardo Caldas 
1694a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Synthesized) {
1704a5cc389SEduardo Caldas   buildTree("", GetParam());
1714a5cc389SEduardo Caldas 
172263dcf45SHaojian Wu   auto *LeafContinue = createLeaf(*Arena, *TM, tok::kw_continue);
173263dcf45SHaojian Wu   auto *LeafSemiColon = createLeaf(*Arena, *TM, tok::semi);
1744a5cc389SEduardo Caldas   auto *StatementContinue = createTree(*Arena,
1754a5cc389SEduardo Caldas                                        {{LeafContinue, NodeRole::LiteralToken},
1764a5cc389SEduardo Caldas                                         {LeafSemiColon, NodeRole::Unknown}},
1774a5cc389SEduardo Caldas                                        NodeKind::ContinueStatement);
1784a5cc389SEduardo Caldas 
179263dcf45SHaojian Wu   auto *Copy = deepCopyExpandingMacros(*Arena, *TM, StatementContinue);
180263dcf45SHaojian Wu   EXPECT_TRUE(treeDumpEqual(Copy, StatementContinue->dump(*TM)));
1814a5cc389SEduardo Caldas   // FIXME: Test that copy is independent of original, once the Mutations API is
1824a5cc389SEduardo Caldas   // more developed.
1834a5cc389SEduardo Caldas }
1844a5cc389SEduardo Caldas 
1854a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Original) {
1864a5cc389SEduardo Caldas   auto *OriginalTree = buildTree("int a;", GetParam());
1874a5cc389SEduardo Caldas 
188263dcf45SHaojian Wu   auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);
1894a5cc389SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
1904a5cc389SEduardo Caldas TranslationUnit Detached synthesized
1914a5cc389SEduardo Caldas `-SimpleDeclaration synthesized
1924a5cc389SEduardo Caldas   |-'int' synthesized
1935011d431SEduardo Caldas   |-DeclaratorList Declarators synthesized
1945011d431SEduardo Caldas   | `-SimpleDeclarator ListElement synthesized
1954a5cc389SEduardo Caldas   |   `-'a' synthesized
1964a5cc389SEduardo Caldas   `-';' synthesized
1974a5cc389SEduardo Caldas   )txt"));
1984a5cc389SEduardo Caldas }
1994a5cc389SEduardo Caldas 
2004a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Child) {
2014a5cc389SEduardo Caldas   auto *OriginalTree = buildTree("int a;", GetParam());
2024a5cc389SEduardo Caldas 
203263dcf45SHaojian Wu   auto *Copy =
204263dcf45SHaojian Wu       deepCopyExpandingMacros(*Arena, *TM, OriginalTree->getFirstChild());
2054a5cc389SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
2064a5cc389SEduardo Caldas SimpleDeclaration Detached synthesized
2074a5cc389SEduardo Caldas |-'int' synthesized
2085011d431SEduardo Caldas |-DeclaratorList Declarators synthesized
2095011d431SEduardo Caldas | `-SimpleDeclarator ListElement synthesized
2104a5cc389SEduardo Caldas |   `-'a' synthesized
2114a5cc389SEduardo Caldas `-';' synthesized
2124a5cc389SEduardo Caldas   )txt"));
2134a5cc389SEduardo Caldas }
2144a5cc389SEduardo Caldas 
2154a5cc389SEduardo Caldas TEST_P(SynthesisTest, DeepCopy_Macro) {
2164a5cc389SEduardo Caldas   auto *OriginalTree = buildTree(R"cpp(
2174a5cc389SEduardo Caldas #define HALF_IF if (1+
2184a5cc389SEduardo Caldas #define HALF_IF_2 1) {}
2194a5cc389SEduardo Caldas void test() {
2204a5cc389SEduardo Caldas   HALF_IF HALF_IF_2 else {}
2214a5cc389SEduardo Caldas })cpp",
2224a5cc389SEduardo Caldas                                  GetParam());
2234a5cc389SEduardo Caldas 
224263dcf45SHaojian Wu   auto *Copy = deepCopyExpandingMacros(*Arena, *TM, OriginalTree);
22566bcb143SEduardo Caldas 
22666bcb143SEduardo Caldas   // The syntax tree stores already expanded Tokens, we can only see whether the
22766bcb143SEduardo Caldas   // macro was expanded when computing replacements. The dump does show that
22866bcb143SEduardo Caldas   // nodes in the copy are `modifiable`.
22966bcb143SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
23066bcb143SEduardo Caldas TranslationUnit Detached synthesized
23166bcb143SEduardo Caldas `-SimpleDeclaration synthesized
23266bcb143SEduardo Caldas   |-'void' synthesized
2335011d431SEduardo Caldas   |-DeclaratorList Declarators synthesized
2345011d431SEduardo Caldas   | `-SimpleDeclarator ListElement synthesized
23566bcb143SEduardo Caldas   |   |-'test' synthesized
23666bcb143SEduardo Caldas   |   `-ParametersAndQualifiers synthesized
23766bcb143SEduardo Caldas   |     |-'(' OpenParen synthesized
23866bcb143SEduardo Caldas   |     `-')' CloseParen synthesized
23966bcb143SEduardo Caldas   `-CompoundStatement synthesized
24066bcb143SEduardo Caldas     |-'{' OpenParen synthesized
24166bcb143SEduardo Caldas     |-IfStatement Statement synthesized
24266bcb143SEduardo Caldas     | |-'if' IntroducerKeyword synthesized
24366bcb143SEduardo Caldas     | |-'(' synthesized
2446c1a2330SHaojian Wu     | |-ExpressionStatement Condition synthesized
2456c1a2330SHaojian Wu     | | `-BinaryOperatorExpression Expression synthesized
24666bcb143SEduardo Caldas     | |   |-IntegerLiteralExpression LeftHandSide synthesized
24766bcb143SEduardo Caldas     | |   | `-'1' LiteralToken synthesized
24866bcb143SEduardo Caldas     | |   |-'+' OperatorToken synthesized
24966bcb143SEduardo Caldas     | |   `-IntegerLiteralExpression RightHandSide synthesized
25066bcb143SEduardo Caldas     | |     `-'1' LiteralToken synthesized
25166bcb143SEduardo Caldas     | |-')' synthesized
25266bcb143SEduardo Caldas     | |-CompoundStatement ThenStatement synthesized
25366bcb143SEduardo Caldas     | | |-'{' OpenParen synthesized
25466bcb143SEduardo Caldas     | | `-'}' CloseParen synthesized
25566bcb143SEduardo Caldas     | |-'else' ElseKeyword synthesized
25666bcb143SEduardo Caldas     | `-CompoundStatement ElseStatement synthesized
25766bcb143SEduardo Caldas     |   |-'{' OpenParen synthesized
25866bcb143SEduardo Caldas     |   `-'}' CloseParen synthesized
25966bcb143SEduardo Caldas     `-'}' CloseParen synthesized
26066bcb143SEduardo Caldas   )txt"));
2614a5cc389SEduardo Caldas }
2624a5cc389SEduardo Caldas 
2635d152127SEduardo Caldas TEST_P(SynthesisTest, Statement_EmptyStatement) {
2645d152127SEduardo Caldas   buildTree("", GetParam());
2655d152127SEduardo Caldas 
266263dcf45SHaojian Wu   auto *S = createEmptyStatement(*Arena, *TM);
2675d152127SEduardo Caldas   EXPECT_TRUE(treeDumpEqual(S, R"txt(
2685d152127SEduardo Caldas EmptyStatement Detached synthesized
2695d152127SEduardo Caldas `-';' synthesized
2705d152127SEduardo Caldas   )txt"));
271c01d28dcSEduardo Caldas }
272c01d28dcSEduardo Caldas } // namespace
273