diff --git a/clang/include/clang/Tooling/Syntax/Tree.h b/clang/include/clang/Tooling/Syntax/Tree.h --- a/clang/include/clang/Tooling/Syntax/Tree.h +++ b/clang/include/clang/Tooling/Syntax/Tree.h @@ -211,7 +211,7 @@ /// Iterator through elements and their corresponding delimiters. Missing /// elements and delimiters are represented as null pointers. Below we give - /// examples of what this iteration would looks like. + /// examples of what this iteration looks like. /// /// In a separated list: /// "a, b, c" <=> [("a" , ","), ("b" , "," ), ("c" , null)] diff --git a/clang/unittests/Tooling/Syntax/TreeTest.cpp b/clang/unittests/Tooling/Syntax/TreeTest.cpp --- a/clang/unittests/Tooling/Syntax/TreeTest.cpp +++ b/clang/unittests/Tooling/Syntax/TreeTest.cpp @@ -359,42 +359,143 @@ EXPECT_EQ(dumpNodes(List->getElementsAsNodes()), "['a', 'b', 'c']"); } -TEST_P(ListTest, List_Iterator_StableDereference) { +TEST_P(ListTest, List_Terminated_Iterator_Parent) { if (!GetParam().isCXX()) { return; } buildTree("", GetParam()); - // "a:: b:: c" - auto *List = dyn_cast(syntax::createTree( + // "a b:: :: c" + auto *List = dyn_cast(syntax::createTree( *Arena, { {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement}, + }, + NodeKind::NestedNameSpecifier)); + + EXPECT_EQ(List->getElementsAsNodesAndDelimitersBeforeBegin().getParent(), + List); + + for (auto It = List->getElementsAsNodesAndDelimitersBegin(), + End = List->getElementsAsNodesAndDelimitersEnd(); + It != End; ++It) + EXPECT_EQ(It.getParent(), List); + + EXPECT_EQ(List->getElementsAsNodesAndDelimitersEnd().getParent(), List); +} + +TEST_P(ListTest, List_Terminated_Iterator_Equality) { + if (!GetParam().isCXX()) { + return; + } + buildTree("", GetParam()); + + // "a b:: :: c" + auto *List = dyn_cast(syntax::createTree( + *Arena, + { + {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement}, {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement}, {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::coloncolon), NodeRole::ListDelimiter}, {createLeaf(*Arena, tok::identifier, "c"), NodeRole::ListElement}, }, NodeKind::NestedNameSpecifier)); - auto It = List->getElementsAsNodesAndDelimitersBegin(); - syntax::List::ElementAndDelimiter First = {It.getElement(), - It.getDelimiter()}; - auto ItAssign = It; + // different iterators are different. + for (auto BeforeIt = List->getElementsAsNodesAndDelimitersBeforeBegin(), + End = List->getElementsAsNodesAndDelimitersEnd(); + BeforeIt != End; ++BeforeIt) { + auto It = BeforeIt; + ++It; + for (; It != End; ++It) { + EXPECT_NE(BeforeIt, It); + } + } - EXPECT_EQ(dumpElementAndDelimiter(First), "('a', '::')"); - ++It; - EXPECT_EQ(dumpElementAndDelimiter(First), "('a', '::')"); + // Equal iterators are equal. + for (auto It = List->getElementsAsNodesAndDelimitersBegin(), + It2 = List->getElementsAsNodesAndDelimitersBegin(), + End = List->getElementsAsNodesAndDelimitersEnd(); + It != End && It2 != End;) { + EXPECT_EQ(++It, ++It2); + } - EXPECT_EQ(ItAssign.getElement(), First.element); + // Different sentinel iterators are different. + EXPECT_NE(List->getElementsAsNodesAndDelimitersBeforeBegin(), + List->getElementsAsNodesAndDelimitersEnd()); +} - auto It2 = ++(++List->getElementsAsNodesAndDelimitersBeforeBegin()); - EXPECT_EQ(It, It2); - EXPECT_EQ(It.getElement(), It2.getElement()); - EXPECT_EQ(It.getDelimiter(), It2.getDelimiter()); +TEST_P(ListTest, List_Separated_Iterator_Parent) { + if (!GetParam().isCXX()) { + return; + } + buildTree("", GetParam()); + + // "a b, ," + auto *List = dyn_cast(syntax::createTree( + *Arena, + { + {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter}, + }, + NodeKind::CallArguments)); + + EXPECT_EQ(List->getElementsAsNodesAndDelimitersBeforeBegin().getParent(), + List); + + for (auto It = List->getElementsAsNodesAndDelimitersBegin(), + End = List->getElementsAsNodesAndDelimitersEnd(); + It != End; ++It) + EXPECT_EQ(It.getParent(), List); + + EXPECT_EQ(List->getElementsAsNodesAndDelimitersEnd().getParent(), List); +} + +TEST_P(ListTest, List_Separated_Iterator_Equality) { + if (!GetParam().isCXX()) { + return; + } + buildTree("", GetParam()); + + // "a b, ," + auto *List = dyn_cast(syntax::createTree( + *Arena, + { + {createLeaf(*Arena, tok::identifier, "a"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::identifier, "b"), NodeRole::ListElement}, + {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter}, + {createLeaf(*Arena, tok::comma), NodeRole::ListDelimiter}, + }, + NodeKind::CallArguments)); + + // different iterators are different. + for (auto BeforeIt = List->getElementsAsNodesAndDelimitersBeforeBegin(), + End = List->getElementsAsNodesAndDelimitersEnd(); + BeforeIt != End; ++BeforeIt) { + auto It = BeforeIt; + ++It; + for (; It != End; ++It) { + EXPECT_NE(BeforeIt, It); + } + } + + // Equal iterators are equal. + for (auto It = List->getElementsAsNodesAndDelimitersBegin(), + It2 = List->getElementsAsNodesAndDelimitersBegin(), + End = List->getElementsAsNodesAndDelimitersEnd(); + It != End && It2 != End;) { + EXPECT_EQ(++It, ++It2); + } - ++It; - ++It; - EXPECT_EQ(It, List->getElementsAsNodesAndDelimitersEnd()); + // Different sentinel iterators are different. + EXPECT_NE(List->getElementsAsNodesAndDelimitersBeforeBegin(), + List->getElementsAsNodesAndDelimitersEnd()); } } // namespace