Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Unified Diff: tools/gn/parse_tree.cc

Issue 962003002: gn format: Have format sort sources (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: unsigned numbers in test Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/gn/parse_tree.h ('k') | tools/gn/parse_tree_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/gn/parse_tree.cc
diff --git a/tools/gn/parse_tree.cc b/tools/gn/parse_tree.cc
index 74f493b601741f7a36e970674118b79635a4ca55..503cb98e8f1e157b4e03468cb951bbb89135af97 100644
--- a/tools/gn/parse_tree.cc
+++ b/tools/gn/parse_tree.cc
@@ -19,6 +19,27 @@ std::string IndentFor(int value) {
return std::string(value, ' ');
}
+bool IsSortRangeSeparator(const ParseNode* node, const ParseNode* prev) {
+ // If it's a block comment, or has an attached comment with a blank line
+ // before it, then we break the range at this point.
+ return node->AsBlockComment() != nullptr ||
+ (prev && node->comments() && !node->comments()->before().empty() &&
+ (node->GetRange().begin().line_number() >
+ prev->GetRange().end().line_number() +
+ static_cast<int>(node->comments()->before().size() + 1)));
+}
+
+base::StringPiece GetStringRepresentation(const ParseNode* node) {
+ DCHECK(node->AsLiteral() || node->AsIdentifier() || node->AsAccessor());
+ if (node->AsLiteral())
+ return node->AsLiteral()->value().value();
+ else if (node->AsIdentifier())
+ return node->AsIdentifier()->value().value();
+ else if (node->AsAccessor())
+ return node->AsAccessor()->base().value();
+ return base::StringPiece();
+}
+
} // namespace
Comments::Comments() {
@@ -194,6 +215,12 @@ Value AccessorNode::ExecuteScopeAccess(Scope* scope, Err* err) const {
return *result;
}
+void AccessorNode::SetNewLocation(int line_number) {
+ Location old = base_.location();
+ base_.set_location(
+ Location(old.file(), line_number, old.char_offset(), old.byte()));
+}
+
// BinaryOpNode ---------------------------------------------------------------
BinaryOpNode::BinaryOpNode() {
@@ -436,6 +463,12 @@ void IdentifierNode::Print(std::ostream& out, int indent) const {
PrintComments(out, indent);
}
+void IdentifierNode::SetNewLocation(int line_number) {
+ Location old = value_.location();
+ value_.set_location(
+ Location(old.file(), line_number, old.char_offset(), old.byte()));
+}
+
// ListNode -------------------------------------------------------------------
ListNode::ListNode() : prefer_multiline_(false) {
@@ -490,6 +523,116 @@ void ListNode::Print(std::ostream& out, int indent) const {
end_->Print(out, indent + 1);
}
+void ListNode::SortAsStringsList() {
+ // Sorts alphabetically. Partitions first on BlockCommentNodes and sorts each
+ // partition separately.
+ for (auto sr : GetSortRanges()) {
+ // Save the original line number so that we can re-assign ranges. We assume
+ // they're contiguous lines because GetSortRanges() does so above. We need
+ // to re-assign these line numbers primiarily because `gn format` uses them
+ // to determine whether two nodes were initially separated by a blank line
+ // or not.
+ int start_line = contents_[sr.begin]->GetRange().begin().line_number();
+ const ParseNode* original_first = contents_[sr.begin];
+ std::sort(contents_.begin() + sr.begin, contents_.begin() + sr.end,
+ [](const ParseNode* a, const ParseNode* b) {
+ base::StringPiece astr = GetStringRepresentation(a);
+ base::StringPiece bstr = GetStringRepresentation(b);
+ return astr < bstr;
+ });
+ // If the beginning of the range had before comments, and the first node
+ // moved during the sort, then move its comments to the new head of the
+ // range.
+ if (original_first->comments() && contents_[sr.begin] != original_first) {
+ for (const auto& hc : original_first->comments()->before()) {
+ const_cast<ParseNode*>(contents_[sr.begin])
+ ->comments_mutable()
+ ->append_before(hc);
+ }
+ const_cast<ParseNode*>(original_first)
+ ->comments_mutable()
+ ->clear_before();
+ }
+ const ParseNode* prev = nullptr;
+ for (size_t i = sr.begin; i != sr.end; ++i) {
+ const ParseNode* node = contents_[i];
+ DCHECK(node->AsLiteral() || node->AsIdentifier() || node->AsAccessor());
+ int line_number =
+ prev ? prev->GetRange().end().line_number() + 1 : start_line;
+ if (node->AsLiteral()) {
+ const_cast<LiteralNode*>(node->AsLiteral())
+ ->SetNewLocation(line_number);
+ } else if (node->AsIdentifier()) {
+ const_cast<IdentifierNode*>(node->AsIdentifier())
+ ->SetNewLocation(line_number);
+ } else if (node->AsAccessor()) {
+ const_cast<AccessorNode*>(node->AsAccessor())
+ ->SetNewLocation(line_number);
+ }
+ prev = node;
+ }
+ }
+}
+
+// Breaks the ParseNodes of |contents| up by ranges that should be separately
+// sorted. In particular, we break at a block comment, or an item that has an
+// attached "before" comment and is separated by a blank line from the item
+// before it. The assumption is that both of these indicate a separate 'section'
+// of a sources block across which items should not be inter-sorted.
+std::vector<ListNode::SortRange> ListNode::GetSortRanges() const {
+ std::vector<SortRange> ranges;
+ const ParseNode* prev = nullptr;
+ size_t begin = 0;
+ for (size_t i = begin; i < contents_.size(); prev = contents_[i++]) {
+ if (IsSortRangeSeparator(contents_[i], prev)) {
+ if (i > begin) {
+ ranges.push_back(SortRange(begin, i));
+ // If |i| is an item with an attached comment, then we start the next
+ // range at that point, because we want to include it in the sort.
+ // Otherwise, it's a block comment which we skip over entirely because
+ // we don't want to move or include it in the sort. The two cases are:
+ //
+ // sources = [
+ // "a",
+ // "b",
+ //
+ // #
+ // # This is a block comment.
+ // #
+ //
+ // "c",
+ // "d",
+ // ]
+ //
+ // which contains 5 elements, and for which the ranges would be { [0,
+ // 2), [3, 5) } (notably excluding 2, the block comment), and:
+ //
+ // sources = [
+ // "a",
+ // "b",
+ //
+ // # This is a header comment.
+ // "c",
+ // "d",
+ // ]
+ //
+ // which contains 4 elements, index 2 containing an attached 'before'
+ // comments, and the ranges should be { [0, 2), [2, 4) }.
+ if (!contents_[i]->AsBlockComment())
+ begin = i;
+ else
+ begin = i + 1;
+ } else {
+ // If it was a one item range, just skip over it.
+ begin = i + 1;
+ }
+ }
+ }
+ if (begin != contents_.size())
+ ranges.push_back(SortRange(begin, contents_.size()));
+ return ranges;
+}
+
// LiteralNode -----------------------------------------------------------------
LiteralNode::LiteralNode() {
@@ -544,6 +687,12 @@ void LiteralNode::Print(std::ostream& out, int indent) const {
PrintComments(out, indent);
}
+void LiteralNode::SetNewLocation(int line_number) {
+ Location old = value_.location();
+ value_.set_location(
+ Location(old.file(), line_number, old.char_offset(), old.byte()));
+}
+
// UnaryOpNode ----------------------------------------------------------------
UnaryOpNode::UnaryOpNode() {
@@ -608,7 +757,6 @@ void BlockCommentNode::Print(std::ostream& out, int indent) const {
PrintComments(out, indent);
}
-
// EndNode ---------------------------------------------------------------------
EndNode::EndNode(const Token& token) : value_(token) {
« no previous file with comments | « tools/gn/parse_tree.h ('k') | tools/gn/parse_tree_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698