270 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			8.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- SynthesisTest.cpp --------------------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file tests synthesis API for syntax trees.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "TreeTestBase.h"
 | |
| #include "clang/Tooling/Syntax/BuildTree.h"
 | |
| #include "clang/Tooling/Syntax/Nodes.h"
 | |
| #include "gtest/gtest.h"
 | |
| 
 | |
| using namespace clang;
 | |
| using namespace clang::syntax;
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| class SynthesisTest : public SyntaxTreeTest {
 | |
| protected:
 | |
|   ::testing::AssertionResult treeDumpEqual(syntax::Node *Root, StringRef Dump) {
 | |
|     if (!Root)
 | |
|       return ::testing::AssertionFailure()
 | |
|              << "Root was not built successfully.";
 | |
| 
 | |
|     auto Actual = StringRef(Root->dump(Arena->getSourceManager())).trim().str();
 | |
|     auto Expected = Dump.trim().str();
 | |
|     // EXPECT_EQ shows the diff between the two strings if they are different.
 | |
|     EXPECT_EQ(Expected, Actual);
 | |
|     if (Actual != Expected) {
 | |
|       return ::testing::AssertionFailure();
 | |
|     }
 | |
|     return ::testing::AssertionSuccess();
 | |
|   }
 | |
| };
 | |
| 
 | |
| INSTANTIATE_TEST_CASE_P(SynthesisTests, SynthesisTest,
 | |
|                         ::testing::ValuesIn(allTestClangConfigs()), );
 | |
| 
 | |
| TEST_P(SynthesisTest, Leaf_Punctuation) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf = createLeaf(*Arena, tok::comma);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
 | |
| ',' Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Leaf_Punctuation_CXX) {
 | |
|   if (!GetParam().isCXX())
 | |
|     return;
 | |
| 
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf = createLeaf(*Arena, tok::coloncolon);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
 | |
| '::' Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Leaf_Keyword) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf = createLeaf(*Arena, tok::kw_if);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
 | |
| 'if' Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Leaf_Keyword_CXX11) {
 | |
|   if (!GetParam().isCXX11OrLater())
 | |
|     return;
 | |
| 
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf = createLeaf(*Arena, tok::kw_nullptr);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
 | |
| 'nullptr' Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Leaf_Identifier) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf = createLeaf(*Arena, tok::identifier, "a");
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
 | |
| 'a' Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Leaf_Number) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf = createLeaf(*Arena, tok::numeric_constant, "1");
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
 | |
| '1' Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Tree_Empty) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Tree = createTree(*Arena, {}, NodeKind::UnknownExpression);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(Tree, R"txt(
 | |
| UnknownExpression Detached synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Tree_Flat) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *LeafLParen = createLeaf(*Arena, tok::l_paren);
 | |
|   auto *LeafRParen = createLeaf(*Arena, tok::r_paren);
 | |
|   auto *TreeParen = createTree(*Arena,
 | |
|                                {{LeafLParen, NodeRole::LeftHandSide},
 | |
|                                 {LeafRParen, NodeRole::RightHandSide}},
 | |
|                                NodeKind::ParenExpression);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(TreeParen, R"txt(
 | |
| ParenExpression Detached synthesized
 | |
| |-'(' LeftHandSide synthesized
 | |
| `-')' RightHandSide synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Tree_OfTree) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *Leaf1 = createLeaf(*Arena, tok::numeric_constant, "1");
 | |
|   auto *Int1 = createTree(*Arena, {{Leaf1, NodeRole::LiteralToken}},
 | |
|                           NodeKind::IntegerLiteralExpression);
 | |
| 
 | |
|   auto *LeafPlus = createLeaf(*Arena, tok::plus);
 | |
| 
 | |
|   auto *Leaf2 = createLeaf(*Arena, tok::numeric_constant, "2");
 | |
|   auto *Int2 = createTree(*Arena, {{Leaf2, NodeRole::LiteralToken}},
 | |
|                           NodeKind::IntegerLiteralExpression);
 | |
| 
 | |
|   auto *TreeBinaryOperator = createTree(*Arena,
 | |
|                                         {{Int1, NodeRole::LeftHandSide},
 | |
|                                          {LeafPlus, NodeRole::OperatorToken},
 | |
|                                          {Int2, NodeRole::RightHandSide}},
 | |
|                                         NodeKind::BinaryOperatorExpression);
 | |
| 
 | |
|   EXPECT_TRUE(treeDumpEqual(TreeBinaryOperator, R"txt(
 | |
| BinaryOperatorExpression Detached synthesized
 | |
| |-IntegerLiteralExpression LeftHandSide synthesized
 | |
| | `-'1' LiteralToken synthesized
 | |
| |-'+' OperatorToken synthesized
 | |
| `-IntegerLiteralExpression RightHandSide synthesized
 | |
|   `-'2' LiteralToken synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, DeepCopy_Synthesized) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *LeafContinue = createLeaf(*Arena, tok::kw_continue);
 | |
|   auto *LeafSemiColon = createLeaf(*Arena, tok::semi);
 | |
|   auto *StatementContinue = createTree(*Arena,
 | |
|                                        {{LeafContinue, NodeRole::LiteralToken},
 | |
|                                         {LeafSemiColon, NodeRole::Unknown}},
 | |
|                                        NodeKind::ContinueStatement);
 | |
| 
 | |
|   auto *Copy = deepCopyExpandingMacros(*Arena, StatementContinue);
 | |
|   EXPECT_TRUE(
 | |
|       treeDumpEqual(Copy, StatementContinue->dump(Arena->getSourceManager())));
 | |
|   // FIXME: Test that copy is independent of original, once the Mutations API is
 | |
|   // more developed.
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, DeepCopy_Original) {
 | |
|   auto *OriginalTree = buildTree("int a;", GetParam());
 | |
| 
 | |
|   auto *Copy = deepCopyExpandingMacros(*Arena, OriginalTree);
 | |
|   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
 | |
| TranslationUnit Detached synthesized
 | |
| `-SimpleDeclaration synthesized
 | |
|   |-'int' synthesized
 | |
|   |-DeclaratorList Declarators synthesized
 | |
|   | `-SimpleDeclarator ListElement synthesized
 | |
|   |   `-'a' synthesized
 | |
|   `-';' synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, DeepCopy_Child) {
 | |
|   auto *OriginalTree = buildTree("int a;", GetParam());
 | |
| 
 | |
|   auto *Copy = deepCopyExpandingMacros(*Arena, OriginalTree->getFirstChild());
 | |
|   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
 | |
| SimpleDeclaration Detached synthesized
 | |
| |-'int' synthesized
 | |
| |-DeclaratorList Declarators synthesized
 | |
| | `-SimpleDeclarator ListElement synthesized
 | |
| |   `-'a' synthesized
 | |
| `-';' synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, DeepCopy_Macro) {
 | |
|   auto *OriginalTree = buildTree(R"cpp(
 | |
| #define HALF_IF if (1+
 | |
| #define HALF_IF_2 1) {}
 | |
| void test() {
 | |
|   HALF_IF HALF_IF_2 else {}
 | |
| })cpp",
 | |
|                                  GetParam());
 | |
| 
 | |
|   auto *Copy = deepCopyExpandingMacros(*Arena, OriginalTree);
 | |
| 
 | |
|   // The syntax tree stores already expanded Tokens, we can only see whether the
 | |
|   // macro was expanded when computing replacements. The dump does show that
 | |
|   // nodes in the copy are `modifiable`.
 | |
|   EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
 | |
| TranslationUnit Detached synthesized
 | |
| `-SimpleDeclaration synthesized
 | |
|   |-'void' synthesized
 | |
|   |-DeclaratorList Declarators synthesized
 | |
|   | `-SimpleDeclarator ListElement synthesized
 | |
|   |   |-'test' synthesized
 | |
|   |   `-ParametersAndQualifiers synthesized
 | |
|   |     |-'(' OpenParen synthesized
 | |
|   |     `-')' CloseParen synthesized
 | |
|   `-CompoundStatement synthesized
 | |
|     |-'{' OpenParen synthesized
 | |
|     |-IfStatement Statement synthesized
 | |
|     | |-'if' IntroducerKeyword synthesized
 | |
|     | |-'(' synthesized
 | |
|     | |-ExpressionStatement Condition synthesized
 | |
|     | | `-BinaryOperatorExpression Expression synthesized
 | |
|     | |   |-IntegerLiteralExpression LeftHandSide synthesized
 | |
|     | |   | `-'1' LiteralToken synthesized
 | |
|     | |   |-'+' OperatorToken synthesized
 | |
|     | |   `-IntegerLiteralExpression RightHandSide synthesized
 | |
|     | |     `-'1' LiteralToken synthesized
 | |
|     | |-')' synthesized
 | |
|     | |-CompoundStatement ThenStatement synthesized
 | |
|     | | |-'{' OpenParen synthesized
 | |
|     | | `-'}' CloseParen synthesized
 | |
|     | |-'else' ElseKeyword synthesized
 | |
|     | `-CompoundStatement ElseStatement synthesized
 | |
|     |   |-'{' OpenParen synthesized
 | |
|     |   `-'}' CloseParen synthesized
 | |
|     `-'}' CloseParen synthesized
 | |
|   )txt"));
 | |
| }
 | |
| 
 | |
| TEST_P(SynthesisTest, Statement_EmptyStatement) {
 | |
|   buildTree("", GetParam());
 | |
| 
 | |
|   auto *S = createEmptyStatement(*Arena);
 | |
|   EXPECT_TRUE(treeDumpEqual(S, R"txt(
 | |
| EmptyStatement Detached synthesized
 | |
| `-';' synthesized
 | |
|   )txt"));
 | |
| }
 | |
| } // namespace
 |