forked from OSchip/llvm-project
[SyntaxTree][Synthesis] Add support for simple Leafs and test based on tree dump
Differential Revision: https://reviews.llvm.org/D87495
This commit is contained in:
parent
c42f96cb23
commit
5d152127d4
|
@ -24,8 +24,17 @@ syntax::TranslationUnit *buildSyntaxTree(Arena &A,
|
|||
|
||||
// Create syntax trees from subtrees not backed by the source code.
|
||||
|
||||
clang::syntax::Leaf *createPunctuation(clang::syntax::Arena &A,
|
||||
clang::tok::TokenKind K);
|
||||
// Synthesis of Leafs
|
||||
/// Create `Leaf` from token with `Spelling` and assert it has the desired
|
||||
/// `TokenKind`.
|
||||
syntax::Leaf *createLeaf(syntax::Arena &A, tok::TokenKind K,
|
||||
StringRef Spelling);
|
||||
|
||||
/// Infer the token spelling from its `TokenKind`, then create `Leaf` from
|
||||
/// this token
|
||||
syntax::Leaf *createLeaf(syntax::Arena &A, tok::TokenKind K);
|
||||
|
||||
// Synthesis of Syntax Nodes
|
||||
clang::syntax::EmptyStatement *createEmptyStatement(clang::syntax::Arena &A);
|
||||
|
||||
} // namespace syntax
|
||||
|
|
|
@ -5,13 +5,14 @@
|
|||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include "clang/Basic/TokenKinds.h"
|
||||
#include "clang/Tooling/Syntax/BuildTree.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
/// Exposes private syntax tree APIs required to implement node synthesis.
|
||||
/// Should not be used for anything else.
|
||||
class syntax::FactoryImpl {
|
||||
class clang::syntax::FactoryImpl {
|
||||
public:
|
||||
static void setCanModify(syntax::Node *N) { N->CanModify = true; }
|
||||
|
||||
|
@ -21,24 +22,32 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
clang::syntax::Leaf *syntax::createPunctuation(clang::syntax::Arena &A,
|
||||
clang::tok::TokenKind K) {
|
||||
auto Tokens = A.lexBuffer(llvm::MemoryBuffer::getMemBuffer(
|
||||
clang::tok::getPunctuatorSpelling(K)))
|
||||
.second;
|
||||
syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K,
|
||||
StringRef Spelling) {
|
||||
auto Tokens = A.lexBuffer(llvm::MemoryBuffer::getMemBuffer(Spelling)).second;
|
||||
assert(Tokens.size() == 1);
|
||||
assert(Tokens.front().kind() == K);
|
||||
auto *L = new (A.getAllocator()) clang::syntax::Leaf(Tokens.begin());
|
||||
FactoryImpl::setCanModify(L);
|
||||
L->assertInvariants();
|
||||
return L;
|
||||
assert(Tokens.front().kind() == K &&
|
||||
"spelling is not lexed into the expected kind of token");
|
||||
|
||||
auto *Leaf = new (A.getAllocator()) syntax::Leaf(Tokens.begin());
|
||||
syntax::FactoryImpl::setCanModify(Leaf);
|
||||
Leaf->assertInvariants();
|
||||
return Leaf;
|
||||
}
|
||||
|
||||
clang::syntax::EmptyStatement *
|
||||
syntax::createEmptyStatement(clang::syntax::Arena &A) {
|
||||
auto *S = new (A.getAllocator()) clang::syntax::EmptyStatement;
|
||||
syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K) {
|
||||
const auto *Spelling = tok::getPunctuatorSpelling(K);
|
||||
if (!Spelling)
|
||||
Spelling = tok::getKeywordSpelling(K);
|
||||
assert(Spelling &&
|
||||
"Cannot infer the spelling of the token from its token kind.");
|
||||
return createLeaf(A, K, Spelling);
|
||||
}
|
||||
|
||||
syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) {
|
||||
auto *S = new (A.getAllocator()) syntax::EmptyStatement;
|
||||
FactoryImpl::setCanModify(S);
|
||||
FactoryImpl::prependChildLowLevel(S, createPunctuation(A, clang::tok::semi),
|
||||
FactoryImpl::prependChildLowLevel(S, createLeaf(A, tok::semi),
|
||||
NodeRole::Unknown);
|
||||
S->assertInvariants();
|
||||
return S;
|
||||
|
|
|
@ -12,33 +12,81 @@
|
|||
|
||||
#include "TreeTestBase.h"
|
||||
#include "clang/Tooling/Syntax/BuildTree.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::syntax;
|
||||
|
||||
namespace {
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, SyntaxTreeTest,
|
||||
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(SyntaxTreeTest, Leaf_Punctuation) {
|
||||
TEST_P(SynthesisTest, Leaf_Punctuation) {
|
||||
buildTree("", GetParam());
|
||||
|
||||
auto *C = syntax::createPunctuation(*Arena, tok::comma);
|
||||
ASSERT_NE(C, nullptr);
|
||||
EXPECT_EQ(C->getToken()->kind(), tok::comma);
|
||||
EXPECT_TRUE(C->canModify());
|
||||
EXPECT_FALSE(C->isOriginal());
|
||||
EXPECT_TRUE(C->isDetached());
|
||||
auto *Leaf = createLeaf(*Arena, tok::comma);
|
||||
|
||||
EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
|
||||
',' Detached synthesized
|
||||
)txt"));
|
||||
}
|
||||
|
||||
TEST_P(SyntaxTreeTest, Statement_Empty) {
|
||||
TEST_P(SynthesisTest, Leaf_Keyword) {
|
||||
buildTree("", GetParam());
|
||||
|
||||
auto *S = syntax::createEmptyStatement(*Arena);
|
||||
ASSERT_NE(S, nullptr);
|
||||
EXPECT_TRUE(S->canModify());
|
||||
EXPECT_FALSE(S->isOriginal());
|
||||
EXPECT_TRUE(S->isDetached());
|
||||
auto *Leaf = createLeaf(*Arena, tok::kw_if);
|
||||
|
||||
EXPECT_TRUE(treeDumpEqual(Leaf, R"txt(
|
||||
'if' 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, Statement_EmptyStatement) {
|
||||
buildTree("", GetParam());
|
||||
|
||||
auto *S = createEmptyStatement(*Arena);
|
||||
EXPECT_TRUE(treeDumpEqual(S, R"txt(
|
||||
EmptyStatement Detached synthesized
|
||||
`-';' synthesized
|
||||
)txt"));
|
||||
}
|
||||
} // namespace
|
||||
|
|
Loading…
Reference in New Issue