269 lines
8.1 KiB
C++
269 lines
8.1 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
|
|
| |-BinaryOperatorExpression 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
|