[PATCH] D87779: [SyntaxTree] Test `findFirstLeaf` and `findLastLeaf`
This revision was automatically updated to reflect the committed changes. Closed by commit rGaf582c9b0f3a: [SyntaxTree] Test `findFirstLeaf` and `findLastLeaf` (authored by eduucaldas). Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D87779/new/ https://reviews.llvm.org/D87779 Files: clang/lib/Tooling/Syntax/Tree.cpp clang/unittests/Tooling/Syntax/CMakeLists.txt clang/unittests/Tooling/Syntax/TreeTest.cpp Index: clang/unittests/Tooling/Syntax/TreeTest.cpp === --- /dev/null +++ clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -0,0 +1,125 @@ +//===- TreeTest.cpp -*- C++ -*-===// +// +// 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 +// +//===--===// + +#include "clang/Tooling/Syntax/Tree.h" +#include "TreeTestBase.h" +#include "clang/Tooling/Syntax/BuildTree.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace clang::syntax; + +namespace { + +class TreeTest : public SyntaxTreeTest { +private: + Tree *createTree(ArrayRef Children) { +std::vector> ChildrenWithRoles; +ChildrenWithRoles.reserve(Children.size()); +for (const auto *Child : Children) { + ChildrenWithRoles.push_back( + std::make_pair(deepCopy(*Arena, Child), NodeRole::Unknown)); +} +return clang::syntax::createTree(*Arena, ChildrenWithRoles, + NodeKind::UnknownExpression); + } + + // Generate Forests by combining `Children` into `ParentCount` Trees. + // + // We do this recursively. + std::vector> + generateAllForests(ArrayRef Children, unsigned ParentCount) { +assert(ParentCount > 0); +// If there is only one Parent node, then combine `Children` under +// this Parent. +if (ParentCount == 1) + return {{createTree(Children)}}; + +// Otherwise, combine `ChildrenCount` children under the last parent and +// solve the smaller problem without these children and this parent. Do this +// for every `ChildrenCount` and combine the results. +std::vector> AllForests; +for (unsigned ChildrenCount = 0; ChildrenCount <= Children.size(); + ++ChildrenCount) { + auto *LastParent = createTree(Children.take_back(ChildrenCount)); + for (auto : generateAllForests(Children.drop_back(ChildrenCount), + ParentCount - 1)) { +Forest.push_back(LastParent); +AllForests.push_back(Forest); + } +} +return AllForests; + } + +protected: + // Generates all trees with a `Base` of `Node`s and `NodeCountPerLayer` + // `Node`s per layer. An example of Tree with `Base` = {`(`, `)`} and + // `NodeCountPerLayer` = {2, 2}: + // Tree + // |-Tree + // `-Tree + //|-Tree + //| `-'(' + //`-Tree + // `-')' + std::vector + generateAllTreesWithShape(ArrayRef Base, +ArrayRef NodeCountPerLayer) { +// We compute the solution per layer. A layer is a collection of bases, +// where each base has the same number of nodes, given by +// `NodeCountPerLayer`. +auto GenerateNextLayer = [this](ArrayRef> Layer, +unsigned NextLayerNodeCount) { + std::vector> NextLayer; + for (const auto : Layer) { +for (const auto : + generateAllForests(Base, NextLayerNodeCount)) { + NextLayer.push_back( + std::vector(NextBase.begin(), NextBase.end())); +} + } + return NextLayer; +}; + +std::vector> Layer = {Base}; +for (auto NodeCount : NodeCountPerLayer) + Layer = GenerateNextLayer(Layer, NodeCount); + +std::vector AllTrees; +AllTrees.reserve(Layer.size()); +for (const auto : Layer) + AllTrees.push_back(createTree(Base)); + +return AllTrees; + } +}; + +INSTANTIATE_TEST_CASE_P(TreeTests, TreeTest, +::testing::ValuesIn(allTestClangConfigs()), ); + +TEST_P(TreeTest, FirstLeaf) { + buildTree("", GetParam()); + std::vector Leafs = {createLeaf(*Arena, tok::l_paren), + createLeaf(*Arena, tok::r_paren)}; + for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) { +ASSERT_TRUE(Tree->findFirstLeaf() != nullptr); +EXPECT_EQ(Tree->findFirstLeaf()->getToken()->kind(), tok::l_paren); + } +} + +TEST_P(TreeTest, LastLeaf) { + buildTree("", GetParam()); + std::vector Leafs = {createLeaf(*Arena, tok::l_paren), + createLeaf(*Arena, tok::r_paren)}; + for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) { +ASSERT_TRUE(Tree->findLastLeaf() != nullptr); +
[PATCH] D87779: [SyntaxTree] Test `findFirstLeaf` and `findLastLeaf`
eduucaldas updated this revision to Diff 293167. eduucaldas added a comment. Comment `generateAllTreesWithShape` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D87779/new/ https://reviews.llvm.org/D87779 Files: clang/lib/Tooling/Syntax/Tree.cpp clang/unittests/Tooling/Syntax/CMakeLists.txt clang/unittests/Tooling/Syntax/TreeTest.cpp Index: clang/unittests/Tooling/Syntax/TreeTest.cpp === --- /dev/null +++ clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -0,0 +1,125 @@ +//===- TreeTest.cpp -*- C++ -*-===// +// +// 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 +// +//===--===// + +#include "clang/Tooling/Syntax/Tree.h" +#include "TreeTestBase.h" +#include "clang/Tooling/Syntax/BuildTree.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace clang::syntax; + +namespace { + +class TreeTest : public SyntaxTreeTest { +private: + Tree *createTree(ArrayRef Children) { +std::vector> ChildrenWithRoles; +ChildrenWithRoles.reserve(Children.size()); +for (const auto *Child : Children) { + ChildrenWithRoles.push_back( + std::make_pair(deepCopy(*Arena, Child), NodeRole::Unknown)); +} +return clang::syntax::createTree(*Arena, ChildrenWithRoles, + NodeKind::UnknownExpression); + } + + // Generate Forests by combining `Children` into `ParentCount` Trees. + // + // We do this recursively. + std::vector> + generateAllForests(ArrayRef Children, unsigned ParentCount) { +assert(ParentCount > 0); +// If there is only one Parent node, then combine `Children` under +// this Parent. +if (ParentCount == 1) + return {{createTree(Children)}}; + +// Otherwise, combine `ChildrenCount` children under the last parent and +// solve the smaller problem without these children and this parent. Do this +// for every `ChildrenCount` and combine the results. +std::vector> AllForests; +for (unsigned ChildrenCount = 0; ChildrenCount <= Children.size(); + ++ChildrenCount) { + auto *LastParent = createTree(Children.take_back(ChildrenCount)); + for (auto : generateAllForests(Children.drop_back(ChildrenCount), + ParentCount - 1)) { +Forest.push_back(LastParent); +AllForests.push_back(Forest); + } +} +return AllForests; + } + +protected: + // Generates all trees with a `Base` of `Node`s and `NodeCountPerLayer` + // `Node`s per layer. An example of Tree with `Base` = {`(`, `)`} and + // `NodeCountPerLayer` = {2, 2}: + // Tree + // |-Tree + // `-Tree + //|-Tree + //| `-'(' + //`-Tree + // `-')' + std::vector + generateAllTreesWithShape(ArrayRef Base, +ArrayRef NodeCountPerLayer) { +// We compute the solution per layer. A layer is a collection of bases, +// where each base has the same number of nodes, given by +// `NodeCountPerLayer`. +auto GenerateNextLayer = [this](ArrayRef> Layer, +unsigned NextLayerNodeCount) { + std::vector> NextLayer; + for (const auto : Layer) { +for (const auto : + generateAllForests(Base, NextLayerNodeCount)) { + NextLayer.push_back( + std::vector(NextBase.begin(), NextBase.end())); +} + } + return NextLayer; +}; + +std::vector> Layer = {Base}; +for (auto NodeCount : NodeCountPerLayer) + Layer = GenerateNextLayer(Layer, NodeCount); + +std::vector AllTrees; +AllTrees.reserve(Layer.size()); +for (const auto : Layer) + AllTrees.push_back(createTree(Base)); + +return AllTrees; + } +}; + +INSTANTIATE_TEST_CASE_P(TreeTests, TreeTest, +::testing::ValuesIn(allTestClangConfigs()), ); + +TEST_P(TreeTest, FirstLeaf) { + buildTree("", GetParam()); + std::vector Leafs = {createLeaf(*Arena, tok::l_paren), + createLeaf(*Arena, tok::r_paren)}; + for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) { +ASSERT_TRUE(Tree->findFirstLeaf() != nullptr); +EXPECT_EQ(Tree->findFirstLeaf()->getToken()->kind(), tok::l_paren); + } +} + +TEST_P(TreeTest, LastLeaf) { + buildTree("", GetParam()); + std::vector Leafs = {createLeaf(*Arena, tok::l_paren), + createLeaf(*Arena, tok::r_paren)}; + for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) { +ASSERT_TRUE(Tree->findLastLeaf() != nullptr); +EXPECT_EQ(Tree->findLastLeaf()->getToken()->kind(), tok::r_paren); + } +} + +} // namespace Index:
[PATCH] D87779: [SyntaxTree] Test `findFirstLeaf` and `findLastLeaf`
eduucaldas updated this revision to Diff 293163. eduucaldas marked 3 inline comments as done. eduucaldas added a comment. - Answer Review - Change names in `generateAllTreesWithShape` - `auto x = vector()` -> `vector x;` Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D87779/new/ https://reviews.llvm.org/D87779 Files: clang/lib/Tooling/Syntax/Tree.cpp clang/unittests/Tooling/Syntax/CMakeLists.txt clang/unittests/Tooling/Syntax/TreeTest.cpp Index: clang/unittests/Tooling/Syntax/TreeTest.cpp === --- /dev/null +++ clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -0,0 +1,123 @@ +//===- TreeTest.cpp -*- C++ -*-===// +// +// 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 +// +//===--===// + +#include "clang/Tooling/Syntax/Tree.h" +#include "TreeTestBase.h" +#include "clang/Tooling/Syntax/BuildTree.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace clang::syntax; + +namespace { + +class TreeTest : public SyntaxTreeTest { +private: + Tree *createTree(ArrayRef Children) { +std::vector> ChildrenWithRoles; +ChildrenWithRoles.reserve(Children.size()); +for (const auto *Child : Children) { + ChildrenWithRoles.push_back( + std::make_pair(deepCopy(*Arena, Child), NodeRole::Unknown)); +} +return clang::syntax::createTree(*Arena, ChildrenWithRoles, + NodeKind::UnknownExpression); + } + + // Generate Forests by combining `Children` into `ParentCount` Trees. + // + // We do this recursively. + std::vector> + generateAllForests(ArrayRef Children, unsigned ParentCount) { +assert(ParentCount > 0); +// If there is only one Parent node, then combine `Children` under +// this Parent. +if (ParentCount == 1) + return {{createTree(Children)}}; + +// Otherwise, combine `ChildrenCount` children under the last parent and +// solve the smaller problem without these children and this parent. Do this +// for every `ChildrenCount` and combine the results. +std::vector> AllForests; +for (unsigned ChildrenCount = 0; ChildrenCount <= Children.size(); + ++ChildrenCount) { + auto *LastParent = createTree(Children.take_back(ChildrenCount)); + for (auto : generateAllForests(Children.drop_back(ChildrenCount), + ParentCount - 1)) { +Forest.push_back(LastParent); +AllForests.push_back(Forest); + } +} +return AllForests; + } + +protected: + // Generates all trees with a `Base` of `Node`s and `NodeCountPerLayer` + // `Node`s per layer. An example of Tree with `Base` = {`(`, `)`} and + // `NodeCountPerLayer` = {2, 2}: + // Tree + // |-Tree + // `-Tree + //|-Tree + //| `-'(' + //`-Tree + // `-')' + std::vector + generateAllTreesWithShape(ArrayRef Base, +ArrayRef NodeCountPerLayer) { +auto GenerateNextLayer = [this](ArrayRef> Layer, +unsigned NextLayerNodeCount) { + std::vector> NextLayer; + for (const auto : Layer) { +for (const auto : + generateAllForests(Base, NextLayerNodeCount)) { + NextLayer.push_back( + std::vector(NextBase.begin(), NextBase.end())); +} + } + return NextLayer; +}; + +std::vector> Layer = {Base}; +for (auto NodeCount : NodeCountPerLayer) { + Layer = GenerateNextLayer(Layer, NodeCount); +} + +std::vector AllTrees; +AllTrees.reserve(Layer.size()); +for (const auto : Layer) { + AllTrees.push_back(createTree(Base)); +} +return AllTrees; + } +}; + +INSTANTIATE_TEST_CASE_P(TreeTests, TreeTest, +::testing::ValuesIn(allTestClangConfigs()), ); + +TEST_P(TreeTest, FirstLeaf) { + buildTree("", GetParam()); + std::vector Leafs = {createLeaf(*Arena, tok::l_paren), + createLeaf(*Arena, tok::r_paren)}; + for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) { +ASSERT_TRUE(Tree->findFirstLeaf() != nullptr); +EXPECT_EQ(Tree->findFirstLeaf()->getToken()->kind(), tok::l_paren); + } +} + +TEST_P(TreeTest, LastLeaf) { + buildTree("", GetParam()); + std::vector Leafs = {createLeaf(*Arena, tok::l_paren), + createLeaf(*Arena, tok::r_paren)}; + for (const auto *Tree : generateAllTreesWithShape(Leafs, {3u})) { +ASSERT_TRUE(Tree->findLastLeaf() != nullptr); +EXPECT_EQ(Tree->findLastLeaf()->getToken()->kind(), tok::r_paren); + } +} + +} // namespace Index: clang/unittests/Tooling/Syntax/CMakeLists.txt
[PATCH] D87779: [SyntaxTree] Test `findFirstLeaf` and `findLastLeaf`
gribozavr2 added inline comments. Comment at: clang/unittests/Tooling/Syntax/TreeTest.cpp:9 +// +// This file tests the Syntax Tree base API. +// Please elaborate what "base API" covers -- specifically, what classes and such. However, I'm not sure it is necessary to have this comment at all. Up to you. Comment at: clang/unittests/Tooling/Syntax/TreeTest.cpp:39 +return ::testing::AssertionSuccess(); + } + Is this copied from somewhere? I feel like other tests have this function already. Can we share? Comment at: clang/unittests/Tooling/Syntax/TreeTest.cpp:52 + + // Generate Forests by combining `Children` under `ParentCount` Trees. + // under => into? Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D87779/new/ https://reviews.llvm.org/D87779 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D87779: [SyntaxTree] Test `findFirstLeaf` and `findLastLeaf`
eduucaldas created this revision. Herald added subscribers: cfe-commits, mgorny. Herald added a project: clang. eduucaldas requested review of this revision. - Introduce `TreeTest.cpp` to unit test `Tree.h` - Add `generateAllTreesWithShape` to generating test cases - Add tests for `findFirstLeaf` and `findLastLeaf` - Fix implementations of `findFirstLeaf` and `findLastLeaf` that had been broken when empty `Tree` were present. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D87779 Files: clang/lib/Tooling/Syntax/Tree.cpp clang/unittests/Tooling/Syntax/CMakeLists.txt clang/unittests/Tooling/Syntax/TreeTest.cpp Index: clang/unittests/Tooling/Syntax/TreeTest.cpp === --- /dev/null +++ clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -0,0 +1,141 @@ +//===- TreeTest.cpp -*- C++ -*-===// +// +// 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 the Syntax Tree base API. +// +//===--===// + +#include "clang/Tooling/Syntax/Tree.h" +#include "TreeTestBase.h" +#include "clang/Tooling/Syntax/BuildTree.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace clang::syntax; + +namespace { + +class TreeTest : public SyntaxTreeTest { +protected: + ::testing::AssertionResult treeDumpEqual(const 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(); + } + + Tree *createTree(ArrayRef Children) { +auto ChildrenWithRoles = std::vector>(); +ChildrenWithRoles.reserve(Children.size()); +for (const auto *Child : Children) { + ChildrenWithRoles.push_back( + std::make_pair(deepCopy(*Arena, Child), NodeRole::Unknown)); +} +return clang::syntax::createTree(*Arena, ChildrenWithRoles, + NodeKind::UnknownExpression); + } + + // Generate Forests by combining `Children` under `ParentCount` Trees. + // + // We do this recursively. + std::vector> + generateAllForests(ArrayRef Children, unsigned ParentCount) { +assert(ParentCount > 0); +// If there is only one Parent node, we need to combine `Children` under +// this Parent. +if (ParentCount == 1) + return {{createTree(Children)}}; + +// Otherwise, we combine `ChildrenCount` children under the last parent and +// solve the smaller problem without these children and this parent. Finally +// we combine the results for every possible `ChildrenCount`. +auto AllForests = std::vector>(); +for (unsigned ChildrenCount = 0; ChildrenCount <= Children.size(); + ++ChildrenCount) { + auto *LastParent = createTree(Children.take_back(ChildrenCount)); + for (auto : generateAllForests(Children.drop_back(ChildrenCount), + ParentCount - 1)) { +Forest.push_back(LastParent); +AllForests.push_back(Forest); + } +} +return AllForests; + } + + // Generates all trees with a `Base` layer of `Node`s and `NodeCountPerLayer` + // `Node`s per layer. An example of Tree with `Base` = {`(`, `)`} and + // `NodeCountPerLayer` = {2, 2}: + // Tree + // |-Tree + // `-Tree + //|-Tree + //| `-'(' + //`-Tree + // `-')' + std::vector + generateAllTreesWithShape(ArrayRef Base, +ArrayRef NodeCountPerLayer) { +auto GenerateNextLayers = [this](ArrayRef> Bases, + unsigned NodeCount) { + auto NextLayers = std::vector>(); + for (const auto : Bases) { +for (const auto : generateAllForests(Base, NodeCount)) { + NextLayers.push_back( + std::vector(NextLayer.begin(), NextLayer.end())); +} + } + return NextLayers; +}; + +auto Layers = std::vector>({Base}); +for (auto NodeCount : NodeCountPerLayer) { + Layers = GenerateNextLayers(Layers, NodeCount); +} + +auto AllTrees = std::vector(); +AllTrees.reserve(Layers.size()); +for (const auto : Layers) { + AllTrees.push_back(createTree(Layer)); +} +return AllTrees; + } +}; + +INSTANTIATE_TEST_CASE_P(TreeTests, TreeTest, +