[clang] 4a5cc38 - [SyntaxTree][Synthesis] Implement `deepCopy`
Eduardo Caldas via cfe-commits
cfe-commits at lists.llvm.org
Mon Sep 21 02:28:19 PDT 2020
Author: Eduardo Caldas
Date: 2020-09-21T09:27:15Z
New Revision: 4a5cc389c51d267f39286a9a8c58c32f758b9d4b
URL: https://github.com/llvm/llvm-project/commit/4a5cc389c51d267f39286a9a8c58c32f758b9d4b
DIFF: https://github.com/llvm/llvm-project/commit/4a5cc389c51d267f39286a9a8c58c32f758b9d4b.diff
LOG: [SyntaxTree][Synthesis] Implement `deepCopy`
Differential Revision: https://reviews.llvm.org/D87749
Added:
Modified:
clang/include/clang/Tooling/Syntax/BuildTree.h
clang/lib/Tooling/Syntax/Synthesis.cpp
clang/unittests/Tooling/Syntax/SynthesisTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Tooling/Syntax/BuildTree.h b/clang/include/clang/Tooling/Syntax/BuildTree.h
index 452edf580ae1..7b36dff123f6 100644
--- a/clang/include/clang/Tooling/Syntax/BuildTree.h
+++ b/clang/include/clang/Tooling/Syntax/BuildTree.h
@@ -45,6 +45,17 @@ createTree(syntax::Arena &A,
// Synthesis of Syntax Nodes
syntax::EmptyStatement *createEmptyStatement(syntax::Arena &A);
+/// Creates a completely independent copy of `N` (a deep copy).
+///
+/// The copy is:
+/// * Detached, i.e. `Parent == NextSibling == nullptr` and
+/// `Role == Detached`.
+/// * Synthesized, i.e. `Original == false`.
+///
+/// `N` might be backed by source code but if any descendants of `N` are
+/// unmodifiable returns `nullptr`.
+syntax::Node *deepCopy(syntax::Arena &A, const syntax::Node *N);
+
} // namespace syntax
} // namespace clang
#endif
diff --git a/clang/lib/Tooling/Syntax/Synthesis.cpp b/clang/lib/Tooling/Syntax/Synthesis.cpp
index f171d26512d9..c8fcac27e0d5 100644
--- a/clang/lib/Tooling/Syntax/Synthesis.cpp
+++ b/clang/lib/Tooling/Syntax/Synthesis.cpp
@@ -28,10 +28,12 @@ class clang::syntax::FactoryImpl {
}
};
+// FIXME: `createLeaf` is based on `syntax::tokenize` internally, as such it
+// doesn't support digraphs or line continuations.
syntax::Leaf *clang::syntax::createLeaf(syntax::Arena &A, tok::TokenKind K,
StringRef Spelling) {
auto Tokens =
- FactoryImpl::lexBuffer(A, llvm::MemoryBuffer::getMemBuffer(Spelling))
+ FactoryImpl::lexBuffer(A, llvm::MemoryBuffer::getMemBufferCopy(Spelling))
.second;
assert(Tokens.size() == 1);
assert(Tokens.front().kind() == K &&
@@ -192,14 +194,52 @@ syntax::Tree *clang::syntax::createTree(
syntax::NodeKind K) {
auto *T = allocateTree(A, K);
FactoryImpl::setCanModify(T);
- for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend();
- std::advance(ChildIt, 1))
+ for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend(); ++ChildIt)
FactoryImpl::prependChildLowLevel(T, ChildIt->first, ChildIt->second);
T->assertInvariants();
return T;
}
+namespace {
+bool canModifyAllDescendants(const syntax::Node *N) {
+ if (const auto *L = dyn_cast<syntax::Leaf>(N))
+ return L->canModify();
+
+ const auto *T = cast<syntax::Tree>(N);
+
+ if (!T->canModify())
+ return false;
+ for (const auto *Child = T->getFirstChild(); Child;
+ Child = Child->getNextSibling())
+ if (!canModifyAllDescendants(Child))
+ return false;
+
+ return true;
+}
+
+syntax::Node *deepCopyImpl(syntax::Arena &A, const syntax::Node *N) {
+ if (const auto *L = dyn_cast<syntax::Leaf>(N))
+ return createLeaf(A, L->getToken()->kind(),
+ L->getToken()->text(A.getSourceManager()));
+
+ const auto *T = cast<syntax::Tree>(N);
+ std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children;
+ for (const auto *Child = T->getFirstChild(); Child;
+ Child = Child->getNextSibling())
+ Children.push_back({deepCopyImpl(A, Child), Child->getRole()});
+
+ return createTree(A, Children, N->getKind());
+}
+} // namespace
+
+syntax::Node *clang::syntax::deepCopy(syntax::Arena &A, const Node *N) {
+ if (!canModifyAllDescendants(N))
+ return nullptr;
+
+ return deepCopyImpl(A, N);
+}
+
syntax::EmptyStatement *clang::syntax::createEmptyStatement(syntax::Arena &A) {
return cast<EmptyStatement>(
createTree(A, {{createLeaf(A, tok::semi), NodeRole::Unknown}},
diff --git a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp
index 8d9fb706eac3..2af1fcf8f317 100644
--- a/clang/unittests/Tooling/Syntax/SynthesisTest.cpp
+++ b/clang/unittests/Tooling/Syntax/SynthesisTest.cpp
@@ -163,6 +163,63 @@ BinaryOperatorExpression Detached 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 = deepCopy(*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 = deepCopy(*Arena, OriginalTree);
+ EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
+TranslationUnit Detached synthesized
+`-SimpleDeclaration synthesized
+ |-'int' synthesized
+ |-SimpleDeclarator Declarator synthesized
+ | `-'a' synthesized
+ `-';' synthesized
+ )txt"));
+}
+
+TEST_P(SynthesisTest, DeepCopy_Child) {
+ auto *OriginalTree = buildTree("int a;", GetParam());
+
+ auto *Copy = deepCopy(*Arena, OriginalTree->getFirstChild());
+ EXPECT_TRUE(treeDumpEqual(Copy, R"txt(
+SimpleDeclaration Detached synthesized
+|-'int' synthesized
+|-SimpleDeclarator Declarator 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 = deepCopy(*Arena, OriginalTree);
+ EXPECT_TRUE(Copy == nullptr);
+}
+
TEST_P(SynthesisTest, Statement_EmptyStatement) {
buildTree("", GetParam());
More information about the cfe-commits
mailing list