forked from OSchip/llvm-project
[SyntaxTree] Specialize `TreeTestBase` for `BuildTreeTest`, `MutationsTest` and `SynthesisTest`
Differential Revision: https://reviews.llvm.org/D87374
This commit is contained in:
parent
f42f733af9
commit
c01d28dc51
File diff suppressed because it is too large
Load Diff
|
@ -6,6 +6,7 @@ add_clang_unittest(SyntaxTests
|
|||
TreeTestBase.cpp
|
||||
BuildTreeTest.cpp
|
||||
MutationsTest.cpp
|
||||
SynthesisTest.cpp
|
||||
TokensTest.cpp
|
||||
)
|
||||
|
||||
|
|
|
@ -19,15 +19,12 @@ using namespace clang::syntax;
|
|||
|
||||
namespace {
|
||||
|
||||
TEST_P(SyntaxTreeTest, Mutations) {
|
||||
if (!GetParam().isCXX11OrLater()) {
|
||||
return;
|
||||
}
|
||||
|
||||
using Transformation = std::function<void(
|
||||
const llvm::Annotations & /*Input*/, syntax::TranslationUnit * /*Root*/)>;
|
||||
auto CheckTransformation = [this](std::string Input, std::string Expected,
|
||||
Transformation Transform) -> void {
|
||||
class MutationTest : public SyntaxTreeTest {
|
||||
protected:
|
||||
using Transformation = std::function<void(const llvm::Annotations & /*Input*/,
|
||||
TranslationUnit * /*Root*/)>;
|
||||
void CheckTransformation(Transformation Transform, std::string Input,
|
||||
std::string Expected) {
|
||||
llvm::Annotations Source(Input);
|
||||
auto *Root = buildTree(Source.code(), GetParam());
|
||||
|
||||
|
@ -46,40 +43,32 @@ TEST_P(SyntaxTreeTest, Mutations) {
|
|||
|
||||
// Removes the selected statement. Input should have exactly one selected
|
||||
// range and it should correspond to a single statement.
|
||||
auto RemoveStatement = [this](const llvm::Annotations &Input,
|
||||
syntax::TranslationUnit *TU) {
|
||||
auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), TU));
|
||||
Transformation RemoveStatement = [this](const llvm::Annotations &Input,
|
||||
TranslationUnit *Root) {
|
||||
auto *S = cast<syntax::Statement>(nodeByRange(Input.range(), Root));
|
||||
ASSERT_TRUE(S->canModify()) << "cannot remove a statement";
|
||||
syntax::removeStatement(*Arena, S);
|
||||
EXPECT_TRUE(S->isDetached());
|
||||
EXPECT_FALSE(S->isOriginal())
|
||||
<< "node removed from tree cannot be marked as original";
|
||||
};
|
||||
};
|
||||
|
||||
std::vector<std::pair<std::string /*Input*/, std::string /*Expected*/>>
|
||||
Cases = {
|
||||
{"void test() { [[100+100;]] test(); }", "void test() { test(); }"},
|
||||
{"void test() { if (true) [[{}]] else {} }",
|
||||
"void test() { if (true) ; else {} }"},
|
||||
{"void test() { [[;]] }", "void test() { }"}};
|
||||
for (const auto &C : Cases)
|
||||
CheckTransformation(C.first, C.second, RemoveStatement);
|
||||
INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, MutationTest,
|
||||
::testing::ValuesIn(allTestClangConfigs()), );
|
||||
|
||||
TEST_P(MutationTest, RemoveStatement_InCompound) {
|
||||
CheckTransformation(RemoveStatement, "void test() { [[100+100;]] test(); }",
|
||||
"void test() { test(); }");
|
||||
}
|
||||
|
||||
TEST_P(SyntaxTreeTest, SynthesizedNodes) {
|
||||
buildTree("", GetParam());
|
||||
TEST_P(MutationTest, RemoveStatement_InCompound_Empty) {
|
||||
CheckTransformation(RemoveStatement, "void test() { [[;]] }",
|
||||
"void test() { }");
|
||||
}
|
||||
|
||||
auto *C = syntax::createPunctuation(*Arena, tok::comma);
|
||||
ASSERT_NE(C, nullptr);
|
||||
EXPECT_EQ(C->token()->kind(), tok::comma);
|
||||
EXPECT_TRUE(C->canModify());
|
||||
EXPECT_FALSE(C->isOriginal());
|
||||
EXPECT_TRUE(C->isDetached());
|
||||
|
||||
auto *S = syntax::createEmptyStatement(*Arena);
|
||||
ASSERT_NE(S, nullptr);
|
||||
EXPECT_TRUE(S->canModify());
|
||||
EXPECT_FALSE(S->isOriginal());
|
||||
EXPECT_TRUE(S->isDetached());
|
||||
TEST_P(MutationTest, RemoveStatement_LeaveEmpty) {
|
||||
CheckTransformation(RemoveStatement, "void test() { if (1) [[{}]] else {} }",
|
||||
"void test() { if (1) ; else {} }");
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
//===- 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"
|
||||
|
||||
using namespace clang;
|
||||
using namespace clang::syntax;
|
||||
|
||||
namespace {
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, SyntaxTreeTest,
|
||||
::testing::ValuesIn(allTestClangConfigs()), );
|
||||
|
||||
TEST_P(SyntaxTreeTest, Leaf_Punctuation) {
|
||||
buildTree("", GetParam());
|
||||
|
||||
auto *C = syntax::createPunctuation(*Arena, tok::comma);
|
||||
ASSERT_NE(C, nullptr);
|
||||
EXPECT_EQ(C->token()->kind(), tok::comma);
|
||||
EXPECT_TRUE(C->canModify());
|
||||
EXPECT_FALSE(C->isOriginal());
|
||||
EXPECT_TRUE(C->isDetached());
|
||||
}
|
||||
|
||||
TEST_P(SyntaxTreeTest, Statement_Empty) {
|
||||
buildTree("", GetParam());
|
||||
|
||||
auto *S = syntax::createEmptyStatement(*Arena);
|
||||
ASSERT_NE(S, nullptr);
|
||||
EXPECT_TRUE(S->canModify());
|
||||
EXPECT_FALSE(S->isOriginal());
|
||||
EXPECT_TRUE(S->isDetached());
|
||||
}
|
||||
} // namespace
|
|
@ -43,8 +43,9 @@ ArrayRef<syntax::Token> tokens(syntax::Node *N) {
|
|||
return llvm::makeArrayRef(T->firstLeaf()->token(),
|
||||
T->lastLeaf()->token() + 1);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
std::vector<TestClangConfig> allTestClangConfigs() {
|
||||
std::vector<TestClangConfig> clang::syntax::allTestClangConfigs() {
|
||||
std::vector<TestClangConfig> all_configs;
|
||||
for (TestLanguage lang : {Lang_C89, Lang_C99, Lang_CXX03, Lang_CXX11,
|
||||
Lang_CXX14, Lang_CXX17, Lang_CXX20}) {
|
||||
|
@ -61,10 +62,6 @@ std::vector<TestClangConfig> allTestClangConfigs() {
|
|||
return all_configs;
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(SyntaxTreeTests, SyntaxTreeTest,
|
||||
testing::ValuesIn(allTestClangConfigs()), );
|
||||
} // namespace
|
||||
|
||||
syntax::TranslationUnit *
|
||||
SyntaxTreeTest::buildTree(StringRef Code, const TestClangConfig &ClangConfig) {
|
||||
// FIXME: this code is almost the identical to the one in TokensTest. Share
|
||||
|
@ -161,62 +158,6 @@ SyntaxTreeTest::buildTree(StringRef Code, const TestClangConfig &ClangConfig) {
|
|||
return Root;
|
||||
}
|
||||
|
||||
::testing::AssertionResult SyntaxTreeTest::treeDumpEqual(StringRef Code,
|
||||
StringRef Tree) {
|
||||
SCOPED_TRACE(llvm::join(GetParam().getCommandLineArgs(), " "));
|
||||
|
||||
auto *Root = buildTree(Code, GetParam());
|
||||
if (Diags->getClient()->getNumErrors() != 0) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< "Source file has syntax errors, they were printed to the test "
|
||||
"log";
|
||||
}
|
||||
auto Actual = StringRef(Root->dump(Arena->sourceManager())).trim().str();
|
||||
// EXPECT_EQ shows the diff between the two strings if they are different.
|
||||
EXPECT_EQ(Tree.trim().str(), Actual);
|
||||
if (Actual != Tree.trim().str()) {
|
||||
return ::testing::AssertionFailure();
|
||||
}
|
||||
return ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
::testing::AssertionResult
|
||||
SyntaxTreeTest::treeDumpEqualOnAnnotations(StringRef CodeWithAnnotations,
|
||||
ArrayRef<StringRef> TreeDumps) {
|
||||
SCOPED_TRACE(llvm::join(GetParam().getCommandLineArgs(), " "));
|
||||
|
||||
auto AnnotatedCode = llvm::Annotations(CodeWithAnnotations);
|
||||
auto *Root = buildTree(AnnotatedCode.code(), GetParam());
|
||||
|
||||
if (Diags->getClient()->getNumErrors() != 0) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< "Source file has syntax errors, they were printed to the test "
|
||||
"log";
|
||||
}
|
||||
|
||||
auto AnnotatedRanges = AnnotatedCode.ranges();
|
||||
if (AnnotatedRanges.size() != TreeDumps.size()) {
|
||||
return ::testing::AssertionFailure()
|
||||
<< "The number of annotated ranges in the source code is different "
|
||||
"to the number of their corresponding tree dumps.";
|
||||
}
|
||||
bool Failed = false;
|
||||
for (unsigned i = 0; i < AnnotatedRanges.size(); i++) {
|
||||
auto *AnnotatedNode = nodeByRange(AnnotatedRanges[i], Root);
|
||||
assert(AnnotatedNode);
|
||||
auto AnnotatedNodeDump =
|
||||
StringRef(AnnotatedNode->dump(Arena->sourceManager())).trim().str();
|
||||
// EXPECT_EQ shows the diff between the two strings if they are different.
|
||||
EXPECT_EQ(TreeDumps[i].trim().str(), AnnotatedNodeDump)
|
||||
<< "Dumps diverged for the code:\n"
|
||||
<< AnnotatedCode.code().slice(AnnotatedRanges[i].Begin,
|
||||
AnnotatedRanges[i].End);
|
||||
if (AnnotatedNodeDump != TreeDumps[i].trim().str())
|
||||
Failed = true;
|
||||
}
|
||||
return Failed ? ::testing::AssertionFailure() : ::testing::AssertionSuccess();
|
||||
}
|
||||
|
||||
syntax::Node *SyntaxTreeTest::nodeByRange(llvm::Annotations::Range R,
|
||||
syntax::Node *Root) {
|
||||
ArrayRef<syntax::Token> Toks = tokens(Root);
|
||||
|
|
|
@ -32,11 +32,6 @@ protected:
|
|||
TranslationUnit *buildTree(StringRef Code,
|
||||
const TestClangConfig &ClangConfig);
|
||||
|
||||
::testing::AssertionResult treeDumpEqual(StringRef Code, StringRef Tree);
|
||||
|
||||
::testing::AssertionResult
|
||||
treeDumpEqualOnAnnotations(StringRef CodeWithAnnotations,
|
||||
ArrayRef<StringRef> TreeDumps);
|
||||
/// Finds the deepest node in the tree that covers exactly \p R.
|
||||
/// FIXME: implement this efficiently and move to public syntax tree API.
|
||||
syntax::Node *nodeByRange(llvm::Annotations::Range R, syntax::Node *Root);
|
||||
|
@ -56,6 +51,8 @@ protected:
|
|||
std::unique_ptr<syntax::TokenBuffer> TB;
|
||||
std::unique_ptr<syntax::Arena> Arena;
|
||||
};
|
||||
|
||||
std::vector<TestClangConfig> allTestClangConfigs();
|
||||
} // namespace syntax
|
||||
} // namespace clang
|
||||
#endif // LLVM_CLANG_UNITTESTS_TOOLING_SYNTAX_TREETESTBASE_H
|
||||
|
|
Loading…
Reference in New Issue