diff options
author | Sam McCall <sam.mccall@gmail.com> | 2020-10-23 12:23:29 +0200 |
---|---|---|
committer | Sam McCall <sam.mccall@gmail.com> | 2020-10-28 12:37:57 +0100 |
commit | d4934eb5f876cdc97a9a8665bd654351fbbcb66b (patch) | |
tree | 5450cdc3a2ef9b1a18059e43e18ac6d679d52b0b /clang/unittests/Tooling/Syntax/TreeTest.cpp | |
parent | edfb2f8b235ff72f00375ae2424f7eb98da08234 (diff) | |
download | llvm-d4934eb5f876cdc97a9a8665bd654351fbbcb66b.zip llvm-d4934eb5f876cdc97a9a8665bd654351fbbcb66b.tar.gz llvm-d4934eb5f876cdc97a9a8665bd654351fbbcb66b.tar.bz2 |
[Syntax] Add iterators over children of syntax trees.
This gives us slightly nicer syntax (foreach) for idioms currently expressed
as a loop, and the option to use range algorithms where it makes sense
(e.g. llvm::all_of et al encapsulate the needed flow control in a useful way).
It's also a building block for iteration over filtered views (e.g. iterate over
all Stmt children, with the right type):
for (const Statement &S : filter<Statement>(N.children()))
...
I realize the recent direction has been mostly towards strongly-typed
node-specific facilities, but I think it's important we have convenient
generic facilities too.
Differential Revision: https://reviews.llvm.org/D90023
Diffstat (limited to 'clang/unittests/Tooling/Syntax/TreeTest.cpp')
-rw-r--r-- | clang/unittests/Tooling/Syntax/TreeTest.cpp | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp index fba3164..ed839e2 100644 --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -8,6 +8,7 @@ #include "clang/Tooling/Syntax/Tree.h" #include "TreeTestBase.h" +#include "clang/Basic/SourceManager.h" #include "clang/Tooling/Syntax/BuildTree.h" #include "clang/Tooling/Syntax/Nodes.h" #include "llvm/ADT/STLExtras.h" @@ -17,6 +18,7 @@ using namespace clang; using namespace clang::syntax; namespace { +using testing::ElementsAre; class TreeTest : public SyntaxTreeTest { private: @@ -124,6 +126,56 @@ TEST_P(TreeTest, LastLeaf) { } } +TEST_F(TreeTest, Iterators) { + buildTree("", allTestClangConfigs().front()); + std::vector<Node *> Children = {createLeaf(*Arena, tok::identifier, "a"), + createLeaf(*Arena, tok::identifier, "b"), + createLeaf(*Arena, tok::identifier, "c")}; + auto *Tree = syntax::createTree(*Arena, + {{Children[0], NodeRole::LeftHandSide}, + {Children[1], NodeRole::OperatorToken}, + {Children[2], NodeRole::RightHandSide}}, + NodeKind::TranslationUnit); + const auto *ConstTree = Tree; + + auto Range = Tree->getChildren(); + EXPECT_THAT(Range, ElementsAre(role(NodeRole::LeftHandSide), + role(NodeRole::OperatorToken), + role(NodeRole::RightHandSide))); + + auto ConstRange = ConstTree->getChildren(); + EXPECT_THAT(ConstRange, ElementsAre(role(NodeRole::LeftHandSide), + role(NodeRole::OperatorToken), + role(NodeRole::RightHandSide))); + + // FIXME: mutate and observe no invalidation. Mutations are private for now... + auto It = Range.begin(); + auto CIt = ConstRange.begin(); + static_assert(std::is_same<decltype(*It), syntax::Node &>::value, + "mutable range"); + static_assert(std::is_same<decltype(*CIt), const syntax::Node &>::value, + "const range"); + + for (unsigned I = 0; I < 3; ++I) { + EXPECT_EQ(It, CIt); + EXPECT_TRUE(It); + EXPECT_TRUE(CIt); + EXPECT_EQ(It.asPointer(), Children[I]); + EXPECT_EQ(CIt.asPointer(), Children[I]); + EXPECT_EQ(&*It, Children[I]); + EXPECT_EQ(&*CIt, Children[I]); + ++It; + ++CIt; + } + EXPECT_EQ(It, CIt); + EXPECT_EQ(It, Tree::ChildIterator()); + EXPECT_EQ(CIt, Tree::ConstChildIterator()); + EXPECT_FALSE(It); + EXPECT_FALSE(CIt); + EXPECT_EQ(nullptr, It.asPointer()); + EXPECT_EQ(nullptr, CIt.asPointer()); +} + class ListTest : public SyntaxTreeTest { private: std::string dumpQuotedTokensOrNull(const Node *N) { |