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

Side by Side Diff: lib/src/argument_list_visitor.dart

Issue 1589823004: Support messages in assert(). (Closed) Base URL: https://github.com/dart-lang/dart_style.git@master
Patch Set: Created 4 years, 11 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 unified diff | Download patch
« no previous file with comments | « CHANGELOG.md ('k') | lib/src/source_visitor.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library dart_style.src.argument_list_visitor; 5 library dart_style.src.argument_list_visitor;
6 6
7 import 'dart:math' as math; 7 import 'dart:math' as math;
8 8
9 import 'package:analyzer/analyzer.dart'; 9 import 'package:analyzer/analyzer.dart';
10 import 'package:analyzer/src/generated/scanner.dart'; 10 import 'package:analyzer/src/generated/scanner.dart';
11 11
12 import 'chunk.dart'; 12 import 'chunk.dart';
13 import 'rule/argument.dart'; 13 import 'rule/argument.dart';
14 import 'rule/rule.dart'; 14 import 'rule/rule.dart';
15 import 'source_visitor.dart'; 15 import 'source_visitor.dart';
16 16
17 /// Helper class for [SourceVisitor] that handles visiting and writing an 17 /// Helper class for [SourceVisitor] that handles visiting and writing an
18 /// [ArgumentList], including all of the special code needed to handle function 18 /// [ArgumentList], including all of the special code needed to handle function
19 /// and collection arguments. 19 /// and collection arguments.
20 class ArgumentListVisitor { 20 class ArgumentListVisitor {
21 final SourceVisitor _visitor; 21 final SourceVisitor _visitor;
22 22
23 final ArgumentList _node; 23 /// The "(" before the argument list.
24 final Token _leftParenthesis;
25
26 /// The ")" after the argument list.
27 final Token _rightParenthesis;
28
29 /// All of the arguments, positional, named, and functions, in the argument
30 /// list.
31 final List<Expression> _allArguments;
24 32
25 /// The normal arguments preceding any block function arguments. 33 /// The normal arguments preceding any block function arguments.
26 final ArgumentSublist _arguments; 34 final ArgumentSublist _arguments;
27 35
28 /// The contiguous list of block function arguments, if any. 36 /// The contiguous list of block function arguments, if any.
29 /// 37 ///
30 /// Otherwise, this is `null`. 38 /// Otherwise, this is `null`.
31 final List<Expression> _functions; 39 final List<Expression> _functions;
32 40
33 /// If there are block function arguments, this is the arguments after them. 41 /// If there are block function arguments, this is the arguments after them.
34 /// 42 ///
35 /// Otherwise, this is `null`. 43 /// Otherwise, this is `null`.
36 final ArgumentSublist _argumentsAfterFunctions; 44 final ArgumentSublist _argumentsAfterFunctions;
37 45
38 /// Returns `true` if there is only a single positional argument. 46 /// Returns `true` if there is only a single positional argument.
39 bool get _isSingle => 47 bool get _isSingle =>
40 _node.arguments.length == 1 && _node.arguments.single is! NamedExpression; 48 _allArguments.length == 1 && _allArguments.single is! NamedExpression;
41 49
42 /// Whether this argument list has any collection or block function arguments. 50 /// Whether this argument list has any collection or block function arguments.
43 // TODO(rnystrom): Returning true based on collections is non-optimal. It 51 // TODO(rnystrom): Returning true based on collections is non-optimal. It
44 // forces a method chain to break into two but the result collection may not 52 // forces a method chain to break into two but the result collection may not
45 // actually split which can lead to a method chain that's allowed to break 53 // actually split which can lead to a method chain that's allowed to break
46 // where it shouldn't. 54 // where it shouldn't.
47 bool get hasBlockArguments => 55 bool get hasBlockArguments =>
48 _arguments._collections.isNotEmpty || _functions != null; 56 _arguments._collections.isNotEmpty || _functions != null;
49 57
50 factory ArgumentListVisitor(SourceVisitor visitor, ArgumentList node) { 58 factory ArgumentListVisitor(SourceVisitor visitor, ArgumentList node) {
59 return new ArgumentListVisitor.forArguments(
60 visitor, node.leftParenthesis, node.rightParenthesis, node.arguments);
61 }
62
63 factory ArgumentListVisitor.forArguments(
64 SourceVisitor visitor,
65 Token leftParenthesis,
66 Token rightParenthesis,
67 List<Expression> arguments) {
51 // Look for a single contiguous range of block function arguments. 68 // Look for a single contiguous range of block function arguments.
52 var functionsStart; 69 var functionsStart;
53 var functionsEnd; 70 var functionsEnd;
54 71
55 for (var i = 0; i < node.arguments.length; i++) { 72 for (var i = 0; i < arguments.length; i++) {
56 var argument = node.arguments[i]; 73 var argument = arguments[i];
57 if (_isBlockFunction(argument)) { 74 if (_isBlockFunction(argument)) {
58 if (functionsStart == null) functionsStart = i; 75 if (functionsStart == null) functionsStart = i;
59 76
60 // The functions must be one contiguous section. 77 // The functions must be one contiguous section.
61 if (functionsEnd != null && functionsEnd != i) { 78 if (functionsEnd != null && functionsEnd != i) {
62 functionsStart = null; 79 functionsStart = null;
63 functionsEnd = null; 80 functionsEnd = null;
64 break; 81 break;
65 } 82 }
66 83
(...skipping 14 matching lines...) Expand all
81 // }, 98 // },
82 // another: argument); 99 // another: argument);
83 // 100 //
84 // Over: 101 // Over:
85 // 102 //
86 // function(named: () { 103 // function(named: () {
87 // something(); 104 // something();
88 // } 105 // }
89 // another: argument); 106 // another: argument);
90 if (functionsStart != null && 107 if (functionsStart != null &&
91 node.arguments[0] is NamedExpression && 108 arguments[0] is NamedExpression &&
92 (functionsStart > 0 || functionsEnd < node.arguments.length)) { 109 (functionsStart > 0 || functionsEnd < arguments.length)) {
93 functionsStart = null; 110 functionsStart = null;
94 } 111 }
95 112
96 if (functionsStart == null) { 113 if (functionsStart == null) {
97 // No functions, so there is just a single argument list. 114 // No functions, so there is just a single argument list.
98 return new ArgumentListVisitor._(visitor, node, 115 return new ArgumentListVisitor._(
99 new ArgumentSublist(node.arguments, node.arguments), null, null); 116 visitor,
117 leftParenthesis,
118 rightParenthesis,
119 arguments,
120 new ArgumentSublist(arguments, arguments),
121 null,
122 null);
100 } 123 }
101 124
102 // Split the arguments into two independent argument lists with the 125 // Split the arguments into two independent argument lists with the
103 // functions in the middle. 126 // functions in the middle.
104 var argumentsBefore = node.arguments.take(functionsStart).toList(); 127 var argumentsBefore = arguments.take(functionsStart).toList();
105 var functions = node.arguments.sublist(functionsStart, functionsEnd); 128 var functions = arguments.sublist(functionsStart, functionsEnd);
106 var argumentsAfter = node.arguments.skip(functionsEnd).toList(); 129 var argumentsAfter = arguments.skip(functionsEnd).toList();
107 130
108 return new ArgumentListVisitor._( 131 return new ArgumentListVisitor._(
109 visitor, 132 visitor,
110 node, 133 leftParenthesis,
111 new ArgumentSublist(node.arguments, argumentsBefore), 134 rightParenthesis,
135 arguments,
136 new ArgumentSublist(arguments, argumentsBefore),
112 functions, 137 functions,
113 new ArgumentSublist(node.arguments, argumentsAfter)); 138 new ArgumentSublist(arguments, argumentsAfter));
114 } 139 }
115 140
116 ArgumentListVisitor._(this._visitor, this._node, this._arguments, 141 ArgumentListVisitor._(
117 this._functions, this._argumentsAfterFunctions); 142 this._visitor,
143 this._leftParenthesis,
144 this._rightParenthesis,
145 this._allArguments,
146 this._arguments,
147 this._functions,
148 this._argumentsAfterFunctions);
118 149
119 /// Builds chunks for the argument list. 150 /// Builds chunks for the argument list.
120 void visit() { 151 void visit() {
121 // If there is just one positional argument, it tends to look weird to 152 // If there is just one positional argument, it tends to look weird to
122 // split before it, so try not to. 153 // split before it, so try not to.
123 if (_isSingle) _visitor.builder.startSpan(); 154 if (_isSingle) _visitor.builder.startSpan();
124 155
125 // Nest around the parentheses in case there are comments before or after 156 // Nest around the parentheses in case there are comments before or after
126 // them. 157 // them.
127 _visitor.builder.nestExpression(); 158 _visitor.builder.nestExpression();
128 _visitor.builder.startSpan(); 159 _visitor.builder.startSpan();
129 _visitor.token(_node.leftParenthesis); 160 _visitor.token(_leftParenthesis);
130 161
131 _arguments.visit(_visitor); 162 _arguments.visit(_visitor);
132 163
133 _visitor.builder.endSpan(); 164 _visitor.builder.endSpan();
134 165
135 if (_functions != null) { 166 if (_functions != null) {
136 // TODO(rnystrom): It might look better to treat the parameter list of the 167 // TODO(rnystrom): It might look better to treat the parameter list of the
137 // first function as if it were an argument in the preceding argument list 168 // first function as if it were an argument in the preceding argument list
138 // instead of just having this little solo split here. That would try to 169 // instead of just having this little solo split here. That would try to
139 // keep the parameter list with other arguments when possible, and, I 170 // keep the parameter list with other arguments when possible, and, I
140 // think, generally look nicer. 171 // think, generally look nicer.
141 if (_functions.first == _node.arguments.first) { 172 if (_functions.first == _allArguments.first) {
142 _visitor.soloZeroSplit(); 173 _visitor.soloZeroSplit();
143 } else { 174 } else {
144 _visitor.soloSplit(); 175 _visitor.soloSplit();
145 } 176 }
146 177
147 for (var argument in _functions) { 178 for (var argument in _functions) {
148 if (argument != _functions.first) _visitor.space(); 179 if (argument != _functions.first) _visitor.space();
149 180
150 _visitor.visit(argument); 181 _visitor.visit(argument);
151 182
152 // Write the trailing comma. 183 // Write the trailing comma.
153 if (argument != _node.arguments.last) { 184 if (argument != _allArguments.last) {
154 _visitor.token(argument.endToken.next); 185 _visitor.token(argument.endToken.next);
155 } 186 }
156 } 187 }
157 188
158 _visitor.builder.startSpan(); 189 _visitor.builder.startSpan();
159 _argumentsAfterFunctions.visit(_visitor); 190 _argumentsAfterFunctions.visit(_visitor);
160 _visitor.builder.endSpan(); 191 _visitor.builder.endSpan();
161 } 192 }
162 193
163 _visitor.token(_node.rightParenthesis); 194 _visitor.token(_rightParenthesis);
164 195
165 _visitor.builder.unnest(); 196 _visitor.builder.unnest();
166 197
167 if (_isSingle) _visitor.builder.endSpan(); 198 if (_isSingle) _visitor.builder.endSpan();
168 } 199 }
169 200
170 /// Returns `true` if [expression] is a [FunctionExpression] with a non-empty 201 /// Returns `true` if [expression] is a [FunctionExpression] with a non-empty
171 /// block body. 202 /// block body.
172 static bool _isBlockFunction(Expression expression) { 203 static bool _isBlockFunction(Expression expression) {
173 if (expression is NamedExpression) { 204 if (expression is NamedExpression) {
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after
394 } else { 425 } else {
395 // Edge case: Likewise, don't force the argument to split if there is 426 // Edge case: Likewise, don't force the argument to split if there is
396 // only a single one, like: 427 // only a single one, like:
397 // 428 //
398 // outer(inner( 429 // outer(inner(
399 // longArgument)); 430 // longArgument));
400 rule.disableSplitOnInnerRules(); 431 rule.disableSplitOnInnerRules();
401 } 432 }
402 433
403 if (argument is NamedExpression) { 434 if (argument is NamedExpression) {
404 visitor.visitNamedArgument( 435 visitor.visitNamedArgument(argument, rule as NamedRule);
405 argument as NamedExpression, rule as NamedRule);
406 } else { 436 } else {
407 visitor.visit(argument); 437 visitor.visit(argument);
408 } 438 }
409 439
410 if (_collections.containsKey(argument)) { 440 if (_collections.containsKey(argument)) {
411 rule.enableSplitOnInnerRules(); 441 rule.enableSplitOnInnerRules();
412 } else if (_allArguments.length > 1) { 442 } else if (_allArguments.length > 1) {
413 visitor.builder.endBlockArgumentNesting(); 443 visitor.builder.endBlockArgumentNesting();
414 } else { 444 } else {
415 rule.enableSplitOnInnerRules(); 445 rule.enableSplitOnInnerRules();
(...skipping 21 matching lines...) Expand all
437 467
438 // TODO(rnystrom): Should we step into parenthesized expressions? 468 // TODO(rnystrom): Should we step into parenthesized expressions?
439 469
440 if (expression is ListLiteral) return expression.leftBracket; 470 if (expression is ListLiteral) return expression.leftBracket;
441 if (expression is MapLiteral) return expression.leftBracket; 471 if (expression is MapLiteral) return expression.leftBracket;
442 472
443 // Not a collection literal. 473 // Not a collection literal.
444 return null; 474 return null;
445 } 475 }
446 } 476 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | lib/src/source_visitor.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698