eduucaldas updated this revision to Diff 296996.
eduucaldas added a comment.
Better comments
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D88106/new/
https://reviews.llvm.org/D88106
Files:
clang/include/clang/Tooling/Syntax/Tree.h
clang/lib/Tooling/Syntax/Nodes.cpp
clang/lib/Tooling/Syntax/Tree.cpp
Index: clang/lib/Tooling/Syntax/Tree.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Tree.cpp
+++ clang/lib/Tooling/Syntax/Tree.cpp
@@ -9,6 +9,7 @@
#include "clang/Basic/TokenKinds.h"
#include "clang/Tooling/Syntax/Nodes.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Casting.h"
#include <cassert>
@@ -294,89 +295,111 @@
}
}
-std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>
-syntax::List::getElementsAsNodesAndDelimiters() {
- if (!getFirstChild())
- return {};
-
- std::vector<syntax::List::ElementAndDelimiter<Node>> Children;
- syntax::Node *ElementWithoutDelimiter = nullptr;
- for (auto *C = getFirstChild(); C; C = C->getNextSibling()) {
- switch (C->getRole()) {
- case syntax::NodeRole::ListElement: {
- if (ElementWithoutDelimiter) {
- Children.push_back({ElementWithoutDelimiter, nullptr});
- }
- ElementWithoutDelimiter = C;
- break;
- }
- case syntax::NodeRole::ListDelimiter: {
- Children.push_back({ElementWithoutDelimiter, cast<syntax::Leaf>(C)});
- ElementWithoutDelimiter = nullptr;
- break;
- }
- default:
- llvm_unreachable(
- "A list can have only elements and delimiters as children.");
- }
+syntax::List::ElementAndDelimiter<syntax::Node>
+syntax::List::getWithDelimiter(syntax::Node *Element) {
+ assert(Element && Element->getRole() == syntax::NodeRole::ListElement);
+ auto *Next = Element->getNextSibling();
+ if (!Next)
+ return {Element, nullptr};
+ switch (Next->getRole()) {
+ case syntax::NodeRole::ListElement:
+ return {Element, nullptr};
+ case syntax::NodeRole::ListDelimiter:
+ return {Element, cast<syntax::Leaf>(Next)};
+ default:
+ llvm_unreachable(
+ "A list can have only elements and delimiters as children.");
}
+}
- switch (getTerminationKind()) {
- case syntax::List::TerminationKind::Separated: {
- Children.push_back({ElementWithoutDelimiter, nullptr});
- break;
- }
- case syntax::List::TerminationKind::Terminated:
- case syntax::List::TerminationKind::MaybeTerminated: {
- if (ElementWithoutDelimiter) {
- Children.push_back({ElementWithoutDelimiter, nullptr});
+llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>>
+syntax::List::getElementAndDelimiterAfterDelimiter(syntax::Leaf *Delimiter) {
+ assert(Delimiter && Delimiter->getRole() == syntax::NodeRole::ListDelimiter);
+ auto *List = cast<syntax::List>(Delimiter->getParent());
+ auto *Next = Delimiter->getNextSibling();
+ if (!Next) {
+ switch (List->getTerminationKind()) {
+ // List is separated and ends with delimiter
+ // => missing last ElementAndDelimiter.
+ case syntax::List::TerminationKind::Separated:
+ return llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>>(
+ {nullptr, nullptr});
+ case syntax::List::TerminationKind::Terminated:
+ case syntax::List::TerminationKind::MaybeTerminated:
+ return None;
}
- break;
}
+ switch (Next->getRole()) {
+ case syntax::NodeRole::ListElement:
+ return getWithDelimiter(Next);
+
+ // Consecutive Delimiters => missing Element
+ case syntax::NodeRole::ListDelimiter:
+ return llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>>(
+ {nullptr, cast<Leaf>(Next)});
+ default:
+ llvm_unreachable(
+ "A list can have only elements and delimiters as children.");
}
-
- return Children;
}
-// Almost the same implementation of `getElementsAsNodesAndDelimiters` but
-// ignoring delimiters
-std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {
- if (!getFirstChild())
- return {};
+llvm::Optional<syntax::List::ElementAndDelimiter<syntax::Node>>
+syntax::List::getElementAndDelimiterAfterElement(syntax::Node *Element) {
+ assert(Element && Element->getRole() == syntax::NodeRole::ListElement);
+ auto *Next = Element->getNextSibling();
+ // a b, x => End of list, this was the last ElementAndDelimiter.
+ if (!Next)
+ return None;
- std::vector<syntax::Node *> Children;
- syntax::Node *ElementWithoutDelimiter = nullptr;
- for (auto *C = getFirstChild(); C; C = C->getNextSibling()) {
- switch (C->getRole()) {
- case syntax::NodeRole::ListElement: {
- if (ElementWithoutDelimiter) {
- Children.push_back(ElementWithoutDelimiter);
- }
- ElementWithoutDelimiter = C;
- break;
- }
- case syntax::NodeRole::ListDelimiter: {
- Children.push_back(ElementWithoutDelimiter);
- ElementWithoutDelimiter = nullptr;
- break;
- }
- default:
- llvm_unreachable("A list has only elements or delimiters.");
- }
+ switch (Next->getRole()) {
+ // x b, c => next ElementAndDelimiter starts with 'b'.
+ case syntax::NodeRole::ListElement:
+ return getWithDelimiter(Next);
+
+ // a x, c => next ElementAndDelimiter starts after ','.
+ case syntax::NodeRole::ListDelimiter:
+ return getElementAndDelimiterAfterDelimiter(cast<Leaf>(Next));
+
+ default:
+ llvm_unreachable(
+ "A list can have only elements and delimiters as children.");
}
+}
- switch (getTerminationKind()) {
- case syntax::List::TerminationKind::Separated: {
- Children.push_back(ElementWithoutDelimiter);
- break;
+syntax::List::ElementAndDelimiterIterator syntax::List::getEnd() {
+ return llvm::Optional<ElementAndDelimiter<Node>>(None);
+}
+
+syntax::List::ElementAndDelimiterIterator syntax::List::getBegin() {
+ auto *First = getFirstChild();
+ if (!First)
+ return getEnd();
+ switch (First->getRole()) {
+ case syntax::NodeRole::ListElement:
+ return llvm::Optional<ElementAndDelimiter<Node>>(getWithDelimiter(First));
+ case syntax::NodeRole::ListDelimiter:
+ return llvm::Optional<ElementAndDelimiter<Node>>(
+ {nullptr, cast<Leaf>(First)});
+ default:
+ llvm_unreachable(
+ "A list can have only elements and delimiters as children.");
}
- case syntax::List::TerminationKind::Terminated:
- case syntax::List::TerminationKind::MaybeTerminated: {
- if (ElementWithoutDelimiter) {
- Children.push_back(ElementWithoutDelimiter);
- }
- break;
+}
+
+std::vector<syntax::List::ElementAndDelimiter<syntax::Node>>
+syntax::List::getElementsAsNodesAndDelimiters() {
+ auto Children = std::vector<syntax::List::ElementAndDelimiter<Node>>();
+ for (auto C : getRange()) {
+ Children.push_back(C);
}
+
+ return Children;
+}
+
+std::vector<syntax::Node *> syntax::List::getElementsAsNodes() {
+ auto Children = std::vector<syntax::Node *>();
+ for (auto C : getRange()) {
+ Children.push_back(C.element);
}
return Children;
Index: clang/lib/Tooling/Syntax/Nodes.cpp
===================================================================
--- clang/lib/Tooling/Syntax/Nodes.cpp
+++ clang/lib/Tooling/Syntax/Nodes.cpp
@@ -230,91 +230,78 @@
// vector
std::vector<syntax::NameSpecifier *>
syntax::NestedNameSpecifier::getSpecifiers() {
- auto SpecifiersAsNodes = getElementsAsNodes();
- std::vector<syntax::NameSpecifier *> Children;
- for (const auto &Element : SpecifiersAsNodes) {
- Children.push_back(llvm::cast<syntax::NameSpecifier>(Element));
- }
+ auto Children = std::vector<syntax::NameSpecifier *>();
+ for (auto C : getRange())
+ Children.push_back(cast<syntax::NameSpecifier>(C.element));
+
return Children;
}
std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>>
syntax::NestedNameSpecifier::getSpecifiersAndDoubleColons() {
- auto SpecifiersAsNodesAndDoubleColons = getElementsAsNodesAndDelimiters();
- std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>>
- Children;
- for (const auto &SpecifierAndDoubleColon : SpecifiersAsNodesAndDoubleColons) {
- Children.push_back(
- {llvm::cast<syntax::NameSpecifier>(SpecifierAndDoubleColon.element),
- SpecifierAndDoubleColon.delimiter});
- }
+ auto Children =
+ std::vector<syntax::List::ElementAndDelimiter<syntax::NameSpecifier>>();
+ for (auto C : getRange())
+ Children.push_back({cast<syntax::NameSpecifier>(C.element), C.delimiter});
+
return Children;
}
std::vector<syntax::Expression *> syntax::CallArguments::getArguments() {
- auto ArgumentsAsNodes = getElementsAsNodes();
- std::vector<syntax::Expression *> Children;
- for (const auto &ArgumentAsNode : ArgumentsAsNodes) {
- Children.push_back(llvm::cast<syntax::Expression>(ArgumentAsNode));
- }
+ auto Children = std::vector<syntax::Expression *>();
+ for (auto C : getRange())
+ Children.push_back(cast<syntax::Expression>(C.element));
+
return Children;
}
std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>>
syntax::CallArguments::getArgumentsAndCommas() {
- auto ArgumentsAsNodesAndCommas = getElementsAsNodesAndDelimiters();
- std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>> Children;
- for (const auto &ArgumentAsNodeAndComma : ArgumentsAsNodesAndCommas) {
- Children.push_back(
- {llvm::cast<syntax::Expression>(ArgumentAsNodeAndComma.element),
- ArgumentAsNodeAndComma.delimiter});
- }
+ auto Children =
+ std::vector<syntax::List::ElementAndDelimiter<syntax::Expression>>();
+ for (auto C : getRange())
+ Children.push_back({cast<syntax::Expression>(C.element), C.delimiter});
+
return Children;
}
std::vector<syntax::SimpleDeclaration *>
syntax::ParameterDeclarationList::getParameterDeclarations() {
- auto ParametersAsNodes = getElementsAsNodes();
- std::vector<syntax::SimpleDeclaration *> Children;
- for (const auto &ParameterAsNode : ParametersAsNodes) {
- Children.push_back(llvm::cast<syntax::SimpleDeclaration>(ParameterAsNode));
- }
+ auto Children = std::vector<syntax::SimpleDeclaration *>();
+ for (auto C : getRange())
+ Children.push_back(cast<syntax::SimpleDeclaration>(C.element));
+
return Children;
}
std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>>
syntax::ParameterDeclarationList::getParametersAndCommas() {
- auto ParametersAsNodesAndCommas = getElementsAsNodesAndDelimiters();
- std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>>
- Children;
- for (const auto &ParameterAsNodeAndComma : ParametersAsNodesAndCommas) {
+ auto Children = std::vector<
+ syntax::List::ElementAndDelimiter<syntax::SimpleDeclaration>>();
+ for (auto C : getRange())
Children.push_back(
- {llvm::cast<syntax::SimpleDeclaration>(ParameterAsNodeAndComma.element),
- ParameterAsNodeAndComma.delimiter});
- }
+ {cast<syntax::SimpleDeclaration>(C.element), C.delimiter});
+
return Children;
}
std::vector<syntax::SimpleDeclarator *>
syntax::DeclaratorList::getDeclarators() {
- auto DeclaratorsAsNodes = getElementsAsNodes();
- std::vector<syntax::SimpleDeclarator *> Children;
- for (const auto &DeclaratorAsNode : DeclaratorsAsNodes) {
- Children.push_back(llvm::cast<syntax::SimpleDeclarator>(DeclaratorAsNode));
- }
+ auto Children = std::vector<syntax::SimpleDeclarator *>();
+ for (auto C : getRange())
+ Children.push_back(cast<syntax::SimpleDeclarator>(C.element));
+
return Children;
}
std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>>
syntax::DeclaratorList::getDeclaratorsAndCommas() {
- auto DeclaratorsAsNodesAndCommas = getElementsAsNodesAndDelimiters();
- std::vector<syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>>
- Children;
- for (const auto &DeclaratorAsNodeAndComma : DeclaratorsAsNodesAndCommas) {
+ auto Children = std::vector<
+ syntax::List::ElementAndDelimiter<syntax::SimpleDeclarator>>();
+ for (auto C : getRange())
Children.push_back(
- {llvm::cast<syntax::SimpleDeclarator>(DeclaratorAsNodeAndComma.element),
- DeclaratorAsNodeAndComma.delimiter});
- }
+ {cast<syntax::SimpleDeclarator>(C.element), C.delimiter});
+
return Children;
}
Index: clang/include/clang/Tooling/Syntax/Tree.h
===================================================================
--- clang/include/clang/Tooling/Syntax/Tree.h
+++ clang/include/clang/Tooling/Syntax/Tree.h
@@ -28,6 +28,8 @@
#include "clang/Tooling/Syntax/Tokens.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/iterator.h"
+#include "llvm/ADT/iterator_range.h"
#include "llvm/Support/Allocator.h"
#include <cstdint>
@@ -201,10 +203,16 @@
/// delimited-list(element, delimiter, termination, canBeEmpty)
class List : public Tree {
public:
- template <typename Element> struct ElementAndDelimiter {
- Element *element;
- Leaf *delimiter;
- };
+ using Tree::Tree;
+ static bool classof(const Node *N);
+
+ // These can't be implemented with the information we have!
+
+ /// Returns the appropriate delimiter for this list.
+ ///
+ /// Useful for discovering the correct delimiter to use when adding
+ /// elements to empty or one-element lists.
+ clang::tok::TokenKind getDelimiterTokenKind() const;
enum class TerminationKind {
Terminated,
@@ -212,12 +220,29 @@
Separated,
};
- using Tree::Tree;
- static bool classof(const Node *N);
- /// Returns the elements and corresponding delimiters. Missing elements
- /// and delimiters are represented as null pointers.
+ TerminationKind getTerminationKind() const;
+
+ /// Whether this list can be empty in syntactically and semantically correct
+ /// code.
+ ///
+ /// This list may be empty when the source code has errors even if
+ /// canBeEmpty() returns false.
+ bool canBeEmpty() const;
+
+public:
+ template <typename Element> struct ElementAndDelimiter {
+ Element *element;
+ Leaf *delimiter;
+ bool operator==(const ElementAndDelimiter &Other) const {
+ return element == Other.element && delimiter == Other.delimiter;
+ }
+ };
+
+ /// Iterator through elements and their corresponding delimiters. Missing
+ /// elements and delimiters are represented as null pointers. Below we give
+ /// examples of how this iteration would look like:
///
- /// For example, in a separated list:
+ /// In a separated list:
/// "a, b, c" <=> [("a" , ","), ("b" , "," ), ("c" , null)]
/// "a, , c" <=> [("a" , ","), (null, "," ), ("c" , null)]
/// "a, b c" <=> [("a" , ","), ("b" , null), ("c" , null)]
@@ -228,6 +253,57 @@
/// "a; ; c;" <=> [("a" , ";"), (null, ";" ), ("c" , ";" )]
/// "a; b c;" <=> [("a" , ";"), ("b" , null), ("c" , ";" )]
/// "a; b; c" <=> [("a" , ";"), ("b" , ";" ), ("c" , null)]
+ class ElementAndDelimiterIterator
+ : public llvm::iterator_facade_base<ElementAndDelimiterIterator,
+ std::forward_iterator_tag,
+ ElementAndDelimiter<Node>> {
+ public:
+ ElementAndDelimiterIterator(llvm::Optional<ElementAndDelimiter<Node>> ED)
+ : EDI(ED) {}
+
+ ElementAndDelimiterIterator &operator++() {
+ assert(EDI.hasValue() && "Incrementing sentinel iterator.");
+ if (auto *Delimiter = EDI.getValue().delimiter)
+ EDI = getElementAndDelimiterAfterDelimiter(Delimiter);
+ else if (auto *Element = EDI.getValue().element)
+ EDI = getElementAndDelimiterAfterElement(Element);
+ else
+ EDI = None;
+ return *this;
+ }
+
+ ElementAndDelimiter<Node> &operator*() {
+ assert(EDI.hasValue() && "Dereferencing sentinel iterator.");
+ return EDI.getValue();
+ }
+
+ const ElementAndDelimiter<Node> &operator*() const {
+ assert(EDI.hasValue() && "Dereferencing sentinel iterator.");
+ return EDI.getValue();
+ }
+
+ bool operator==(const ElementAndDelimiterIterator &Other) const {
+ return EDI == Other.EDI;
+ }
+
+ private:
+ llvm::Optional<ElementAndDelimiter<Node>> EDI;
+ };
+
+ ElementAndDelimiterIterator getBegin();
+ ElementAndDelimiterIterator getEnd();
+
+ using ElementsAndDelimitersRange =
+ llvm::iterator_range<ElementAndDelimiterIterator>;
+
+ ElementsAndDelimitersRange getRange() {
+ return ElementsAndDelimitersRange(getBegin(), getEnd());
+ }
+
+ // Returns the elements of the list, and their corresponding delimiters.
+ // Missing elements are represented as null pointers. Iterating through
+ // `getElementsAsNodesAndDelimiters()` is equivalent to iterating through
+ // `getRange()`
std::vector<ElementAndDelimiter<Node>> getElementsAsNodesAndDelimiters();
/// Returns the elements of the list. Missing elements are represented
@@ -235,22 +311,13 @@
/// `getElementsAsNodesAndDelimiters()`.
std::vector<Node *> getElementsAsNodes();
- // These can't be implemented with the information we have!
-
- /// Returns the appropriate delimiter for this list.
- ///
- /// Useful for discovering the correct delimiter to use when adding
- /// elements to empty or one-element lists.
- clang::tok::TokenKind getDelimiterTokenKind() const;
-
- TerminationKind getTerminationKind() const;
-
- /// Whether this list can be empty in syntactically and semantically correct
- /// code.
- ///
- /// This list may be empty when the source code has errors even if
- /// canBeEmpty() returns false.
- bool canBeEmpty() const;
+private:
+ // Auxiliary methods for implementing `ElementAndDelimiterIterator`.
+ static ElementAndDelimiter<Node> getWithDelimiter(Node *Element);
+ static llvm::Optional<ElementAndDelimiter<Node>>
+ getElementAndDelimiterAfterDelimiter(Leaf *Delimiter);
+ static llvm::Optional<ElementAndDelimiter<Node>>
+ getElementAndDelimiterAfterElement(Node *Element);
};
} // namespace syntax
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits