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