eduucaldas updated this revision to Diff 291261.
eduucaldas added a comment.

add previous patch to allow pre-merge checks


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87526/new/

https://reviews.llvm.org/D87526

Files:
  clang/include/clang/Tooling/Syntax/BuildTree.h
  clang/lib/Tooling/Syntax/Synthesis.cpp
  clang/unittests/Tooling/Syntax/SynthesisTest.cpp

Index: clang/unittests/Tooling/Syntax/SynthesisTest.cpp
===================================================================
--- clang/unittests/Tooling/Syntax/SynthesisTest.cpp
+++ clang/unittests/Tooling/Syntax/SynthesisTest.cpp
@@ -12,33 +12,107 @@
 
 #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 = createLeaf(*Arena, tok::comma);
+
+  EXPECT_TRUE(treeDumpEqual(C, R"txt(
+',' Detached synthesized
+  )txt"));
+}
+
+TEST_P(SynthesisTest, Leaf_Keyword) {
+  buildTree("", GetParam());
+
+  auto *C = createLeaf(*Arena, tok::kw_if);
+
+  EXPECT_TRUE(treeDumpEqual(C, R"txt(
+'if' Detached synthesized
+  )txt"));
+}
+
+TEST_P(SynthesisTest, Leaf_Identifier) {
+  buildTree("", GetParam());
+
+  auto *C = createLeaf(*Arena, tok::identifier, "a");
+
+  EXPECT_TRUE(treeDumpEqual(C, R"txt(
+'a' Detached synthesized
+  )txt"));
+}
+
+TEST_P(SynthesisTest, Leaf_Number) {
+  buildTree("", GetParam());
+
+  auto *C = createLeaf(*Arena, tok::numeric_constant, "1");
+
+  EXPECT_TRUE(treeDumpEqual(C, R"txt(
+'1' Detached synthesized
+  )txt"));
+}
+
+TEST_P(SynthesisTest, Tree_Empty) {
   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 *Tree = createEmptyTree(*Arena);
+
+  EXPECT_TRUE(treeDumpEqual(Tree, R"txt(
+UnknownExpression Detached synthesized
+  )txt"));
+}
+
+TEST_P(SynthesisTest, Tree_Simple) {
+  buildTree("", GetParam());
+
+  auto *IdA = createLeaf(*Arena, tok::identifier, "a");
+  auto *Comma = createLeaf(*Arena, tok::comma);
+  auto *IdB = createLeaf(*Arena, tok::identifier, "b");
+  auto *Tree = foldChildren(*Arena, {IdA, Comma, IdB});
+
+  EXPECT_TRUE(treeDumpEqual(Tree, R"txt(
+UnknownExpression Detached synthesized
+|-'a' synthesized
+|-',' synthesized
+`-'b' synthesized
+  )txt"));
 }
 
-TEST_P(SyntaxTreeTest, Statement_Empty) {
+TEST_P(SynthesisTest, Statement_EmptyStatement) {
   buildTree("", GetParam());
 
-  auto *S = syntax::createEmptyStatement(*Arena);
-  ASSERT_NE(S, nullptr);
-  EXPECT_TRUE(S->canModify());
-  EXPECT_FALSE(S->isOriginal());
-  EXPECT_TRUE(S->isDetached());
+  auto *S = createEmptyStatement(*Arena);
+  EXPECT_TRUE(treeDumpEqual(S, R"txt(
+EmptyStatement Detached synthesized
+`-';' synthesized
+  )txt"));
 }
 } // namespace
Index: clang/lib/Tooling/Syntax/Synthesis.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Synthesis.cpp
+++ clang/lib/Tooling/Syntax/Synthesis.cpp
@@ -5,13 +5,15 @@
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
+#include "clang/Basic/TokenKinds.h"
 #include "clang/Tooling/Syntax/BuildTree.h"
+#include "clang/Tooling/Syntax/Nodes.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 +23,74 @@
   }
 };
 
-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;
+namespace {
+syntax::Leaf *createLeafLowLevel(syntax::Arena &A, 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);
+  auto *L = new (A.getAllocator()) syntax::Leaf(Tokens.begin());
+  syntax::FactoryImpl::setCanModify(L);
   L->assertInvariants();
   return L;
 }
+} // namespace
 
-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,
+                                        StringRef Spelling) {
+  auto *Leaf = createLeafLowLevel(A, Spelling);
+  assert(Leaf->getToken()->kind() == K &&
+         "spelling is not lexed into the expected kind of token");
+  return Leaf;
+}
+
+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::Tree *clang::syntax::foldChildren(
+    syntax::Arena &A,
+    std::vector<std::pair<syntax::Node *, syntax::NodeRole>> Children,
+    syntax::NodeKind K) {
+  auto *T = new (A.getAllocator()) syntax::Tree(K);
+  FactoryImpl::setCanModify(T);
+  for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend();
+       std::advance(ChildIt, 1))
+    FactoryImpl::prependChildLowLevel(T, ChildIt->first, ChildIt->second);
+
+  T->assertInvariants();
+  return T;
+}
+
+// For testing purposes
+syntax::Tree *clang::syntax::foldChildren(syntax::Arena &A,
+                                          std::vector<syntax::Node *> Children,
+                                          syntax::NodeKind K) {
+  auto *T = new (A.getAllocator()) syntax::Tree(K);
+  FactoryImpl::setCanModify(T);
+  for (auto ChildIt = Children.rbegin(); ChildIt != Children.rend();
+       std::advance(ChildIt, 1))
+    FactoryImpl::prependChildLowLevel(T, *ChildIt, NodeRole::Unknown);
+
+  T->assertInvariants();
+  return T;
+}
+
+syntax::Tree *clang::syntax::createEmptyTree(syntax::Arena &A,
+                                             syntax::NodeKind K) {
+  auto *T = new (A.getAllocator()) syntax::Tree(K);
+  FactoryImpl::setCanModify(T);
+  T->assertInvariants();
+  return T;
+}
+
+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;
Index: clang/include/clang/Tooling/Syntax/BuildTree.h
===================================================================
--- clang/include/clang/Tooling/Syntax/BuildTree.h
+++ clang/include/clang/Tooling/Syntax/BuildTree.h
@@ -24,8 +24,26 @@
 
 // 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 Trees
+syntax::Tree *
+foldChildren(Arena &A, std::vector<std::pair<syntax::Node *, syntax::NodeRole>>,
+             syntax::NodeKind);
+syntax::Tree *foldChildren(Arena &A, std::vector<syntax::Node *> Children,
+                           syntax::NodeKind K = NodeKind::UnknownExpression);
+syntax::Tree *createEmptyTree(Arena &A,
+                              syntax::NodeKind K = NodeKind::UnknownExpression);
+
+// Synthesis of Syntax Nodes
 clang::syntax::EmptyStatement *createEmptyStatement(clang::syntax::Arena &A);
 
 } // namespace syntax
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D87526: [SyntaxTree... Eduardo Caldas via Phabricator via cfe-commits
    • [PATCH] D87526: [Synta... Eduardo Caldas via Phabricator via cfe-commits

Reply via email to