| OLD | NEW |
| 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 'package:analyzer/analyzer.dart'; | 7 import 'package:analyzer/analyzer.dart'; |
| 8 | 8 |
| 9 import 'chunk.dart'; | 9 import 'chunk.dart'; |
| 10 import 'rule/argument.dart'; | 10 import 'rule/argument.dart'; |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 90 var argumentsAfter = node.arguments.skip(functionsEnd).toList(); | 90 var argumentsAfter = node.arguments.skip(functionsEnd).toList(); |
| 91 | 91 |
| 92 return new ArgumentListVisitor._( | 92 return new ArgumentListVisitor._( |
| 93 visitor, | 93 visitor, |
| 94 node, | 94 node, |
| 95 new ArgumentSublist(node.arguments, argumentsBefore), | 95 new ArgumentSublist(node.arguments, argumentsBefore), |
| 96 functions, | 96 functions, |
| 97 new ArgumentSublist(node.arguments, argumentsAfter)); | 97 new ArgumentSublist(node.arguments, argumentsAfter)); |
| 98 } | 98 } |
| 99 | 99 |
| 100 ArgumentListVisitor._( | 100 ArgumentListVisitor._(this._visitor, this._node, this._arguments, |
| 101 this._visitor, | 101 this._functions, this._argumentsAfterFunctions); |
| 102 this._node, | |
| 103 this._arguments, | |
| 104 this._functions, | |
| 105 this._argumentsAfterFunctions); | |
| 106 | 102 |
| 107 /// Builds chunks for the call chain. | 103 /// Builds chunks for the call chain. |
| 108 void visit() { | 104 void visit() { |
| 109 // If there is just one positional argument, it tends to look weird to | 105 // If there is just one positional argument, it tends to look weird to |
| 110 // split before it, so try not to. | 106 // split before it, so try not to. |
| 111 if (_isSingle) _visitor.builder.startSpan(); | 107 if (_isSingle) _visitor.builder.startSpan(); |
| 112 | 108 |
| 113 // Nest around the parentheses in case there are comments before or after | 109 // Nest around the parentheses in case there are comments before or after |
| 114 // them. | 110 // them. |
| 115 _visitor.builder.nestExpression(); | 111 _visitor.builder.nestExpression(); |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 155 if (_isSingle) _visitor.builder.endSpan(); | 151 if (_isSingle) _visitor.builder.endSpan(); |
| 156 } | 152 } |
| 157 | 153 |
| 158 /// Returns `true` if [expression] is a [FunctionExpression] with a block | 154 /// Returns `true` if [expression] is a [FunctionExpression] with a block |
| 159 /// body. | 155 /// body. |
| 160 static bool _isBlockFunction(Expression expression) { | 156 static bool _isBlockFunction(Expression expression) { |
| 161 if (expression is NamedExpression) { | 157 if (expression is NamedExpression) { |
| 162 expression = (expression as NamedExpression).expression; | 158 expression = (expression as NamedExpression).expression; |
| 163 } | 159 } |
| 164 | 160 |
| 161 // Allow functions wrapped in dotted method calls like "a.b.c(() { ... })". |
| 162 if (expression is MethodInvocation) { |
| 163 if (!_isValidWrappingTarget(expression.target)) return false; |
| 164 if (expression.argumentList.arguments.length != 1) return false; |
| 165 |
| 166 return _isBlockFunction(expression.argumentList.arguments.single); |
| 167 } |
| 168 |
| 165 // Curly body functions are. | 169 // Curly body functions are. |
| 166 if (expression is! FunctionExpression) return false; | 170 if (expression is! FunctionExpression) return false; |
| 167 var function = expression as FunctionExpression; | 171 var function = expression as FunctionExpression; |
| 168 return function.body is BlockFunctionBody; | 172 return function.body is BlockFunctionBody; |
| 169 } | 173 } |
| 174 |
| 175 /// Returns `true` if [expression] is a valid method invocation target for |
| 176 /// an invocation that wraps a function literal argument. |
| 177 static bool _isValidWrappingTarget(Expression expression) { |
| 178 // Allow bare function calls. |
| 179 if (expression == null) return true; |
| 180 |
| 181 // Allow property accesses. |
| 182 while (expression is PropertyAccess) { |
| 183 expression = (expression as PropertyAccess).target; |
| 184 } |
| 185 |
| 186 if (expression is PrefixedIdentifier) return true; |
| 187 if (expression is SimpleIdentifier) return true; |
| 188 |
| 189 return false; |
| 190 } |
| 170 } | 191 } |
| 171 | 192 |
| 172 /// A range of arguments from a complete argument list. | 193 /// A range of arguments from a complete argument list. |
| 173 /// | 194 /// |
| 174 /// One of these typically covers all of the arguments in an invocation. But, | 195 /// One of these typically covers all of the arguments in an invocation. But, |
| 175 /// when an argument list has block functions in the middle, the arguments | 196 /// when an argument list has block functions in the middle, the arguments |
| 176 /// before and after the functions are treated as separate independent lists. | 197 /// before and after the functions are treated as separate independent lists. |
| 177 /// In that case, there will be two of these. | 198 /// In that case, there will be two of these. |
| 178 class ArgumentSublist { | 199 class ArgumentSublist { |
| 179 /// The full argument list from the AST. | 200 /// The full argument list from the AST. |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 var positionalRule = rule; | 347 var positionalRule = rule; |
| 327 var namedRule = new NamedRule(_collectionRule); | 348 var namedRule = new NamedRule(_collectionRule); |
| 328 visitor.builder.startRule(namedRule); | 349 visitor.builder.startRule(namedRule); |
| 329 | 350 |
| 330 // Let the positional args force the named ones to split. | 351 // Let the positional args force the named ones to split. |
| 331 if (positionalRule != null) { | 352 if (positionalRule != null) { |
| 332 positionalRule.setNamedArgsRule(namedRule); | 353 positionalRule.setNamedArgsRule(namedRule); |
| 333 } | 354 } |
| 334 | 355 |
| 335 // Split before the first named argument. | 356 // Split before the first named argument. |
| 336 namedRule.beforeArguments(visitor.builder.split( | 357 namedRule.beforeArguments( |
| 337 space: !_isFirstArgument(_named.first))); | 358 visitor.builder.split(space: !_isFirstArgument(_named.first))); |
| 338 | 359 |
| 339 for (var argument in _named) { | 360 for (var argument in _named) { |
| 340 _visitArgument(visitor, namedRule, argument); | 361 _visitArgument(visitor, namedRule, argument); |
| 341 | 362 |
| 342 // Write the split. | 363 // Write the split. |
| 343 if (argument != _named.last) visitor.split(); | 364 if (argument != _named.last) visitor.split(); |
| 344 } | 365 } |
| 345 | 366 |
| 346 visitor.builder.endRule(); | 367 visitor.builder.endRule(); |
| 347 } | 368 } |
| 348 | 369 |
| 349 void _visitArgument(SourceVisitor visitor, ArgumentRule rule, Expression argum
ent) { | 370 void _visitArgument( |
| 371 SourceVisitor visitor, ArgumentRule rule, Expression argument) { |
| 350 // If we're about to write a collection argument, handle it specially. | 372 // If we're about to write a collection argument, handle it specially. |
| 351 if (_collections.contains(argument)) { | 373 if (_collections.contains(argument)) { |
| 352 if (rule != null) rule.beforeCollection(); | 374 if (rule != null) rule.beforeCollection(); |
| 353 | 375 |
| 354 // Tell it to use the rule we've already created. | 376 // Tell it to use the rule we've already created. |
| 355 visitor.setNextLiteralBodyRule(_collectionRule); | 377 visitor.setNextLiteralBodyRule(_collectionRule); |
| 356 } else if (_hasMultipleArguments) { | 378 } else if (_hasMultipleArguments) { |
| 357 // Corner case: If there is just a single argument, don't bump the | 379 // Corner case: If there is just a single argument, don't bump the |
| 358 // nesting. This lets us avoid spurious indentation in cases like: | 380 // nesting. This lets us avoid spurious indentation in cases like: |
| 359 // | 381 // |
| (...skipping 27 matching lines...) Expand all Loading... |
| 387 /// indentation to make them look more statement-like. | 409 /// indentation to make them look more statement-like. |
| 388 static bool _isCollectionArgument(Expression expression) { | 410 static bool _isCollectionArgument(Expression expression) { |
| 389 if (expression is NamedExpression) { | 411 if (expression is NamedExpression) { |
| 390 expression = (expression as NamedExpression).expression; | 412 expression = (expression as NamedExpression).expression; |
| 391 } | 413 } |
| 392 | 414 |
| 393 // TODO(rnystrom): Should we step into parenthesized expressions? | 415 // TODO(rnystrom): Should we step into parenthesized expressions? |
| 394 | 416 |
| 395 return expression is ListLiteral || expression is MapLiteral; | 417 return expression is ListLiteral || expression is MapLiteral; |
| 396 } | 418 } |
| 397 } | 419 } |
| OLD | NEW |