| Index: dart_style/lib/src/argument_list_visitor.dart
|
| diff --git a/dart_style/lib/src/argument_list_visitor.dart b/dart_style/lib/src/argument_list_visitor.dart
|
| deleted file mode 100644
|
| index c45b73724827255098d99f0f86c7a0c6a4045d40..0000000000000000000000000000000000000000
|
| --- a/dart_style/lib/src/argument_list_visitor.dart
|
| +++ /dev/null
|
| @@ -1,419 +0,0 @@
|
| -// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -library dart_style.src.argument_list_visitor;
|
| -
|
| -import 'package:analyzer/analyzer.dart';
|
| -
|
| -import 'chunk.dart';
|
| -import 'rule/argument.dart';
|
| -import 'rule/rule.dart';
|
| -import 'source_visitor.dart';
|
| -
|
| -/// Helper class for [SourceVisitor] that handles visiting and writing an
|
| -/// [ArgumentList], including all of the special code needed to handle function
|
| -/// and collection arguments.
|
| -class ArgumentListVisitor {
|
| - final SourceVisitor _visitor;
|
| -
|
| - final ArgumentList _node;
|
| -
|
| - /// The normal arguments preceding any block function arguments.
|
| - final ArgumentSublist _arguments;
|
| -
|
| - /// The contiguous list of block function arguments, if any.
|
| - ///
|
| - /// Otherwise, this is `null`.
|
| - final List<Expression> _functions;
|
| -
|
| - /// If there are block function arguments, this is the arguments after them.
|
| - ///
|
| - /// Otherwise, this is `null`.
|
| - final ArgumentSublist _argumentsAfterFunctions;
|
| -
|
| - /// Returns `true` if there is only a single positional argument.
|
| - bool get _isSingle =>
|
| - _node.arguments.length == 1 && _node.arguments.single is! NamedExpression;
|
| -
|
| - /// Whether this argument list has any collection or block function arguments.
|
| - bool get hasBlockArguments =>
|
| - _arguments._collections.isNotEmpty || _functions != null;
|
| -
|
| - /// Whether this argument list should force the containing method chain to
|
| - /// add a level of block nesting.
|
| - bool get nestMethodArguments {
|
| - // If there are block arguments, we don't want the method to force them to
|
| - // the right.
|
| - if (hasBlockArguments) return false;
|
| -
|
| - // Corner case: If there is just a single argument, don't bump the nesting.
|
| - // This lets us avoid spurious indentation in cases like:
|
| - //
|
| - // object.method(function(() {
|
| - // body;
|
| - // }));
|
| - return _node.arguments.length > 1;
|
| - }
|
| -
|
| - factory ArgumentListVisitor(SourceVisitor visitor, ArgumentList node) {
|
| - // Look for a single contiguous range of block function arguments.
|
| - var functionsStart;
|
| - var functionsEnd;
|
| -
|
| - for (var i = 0; i < node.arguments.length; i++) {
|
| - var argument = node.arguments[i];
|
| - if (_isBlockFunction(argument)) {
|
| - if (functionsStart == null) functionsStart = i;
|
| -
|
| - // The functions must be one contiguous section.
|
| - if (functionsEnd != null && functionsEnd != i) {
|
| - functionsStart = null;
|
| - functionsEnd = null;
|
| - break;
|
| - }
|
| -
|
| - functionsEnd = i + 1;
|
| - }
|
| - }
|
| -
|
| - if (functionsStart == null) {
|
| - // No functions, so there is just a single argument list.
|
| - return new ArgumentListVisitor._(visitor, node,
|
| - new ArgumentSublist(node.arguments, node.arguments), null, null);
|
| - }
|
| -
|
| - // Split the arguments into two independent argument lists with the
|
| - // functions in the middle.
|
| - var argumentsBefore = node.arguments.take(functionsStart).toList();
|
| - var functions = node.arguments.sublist(functionsStart, functionsEnd);
|
| - var argumentsAfter = node.arguments.skip(functionsEnd).toList();
|
| -
|
| - return new ArgumentListVisitor._(
|
| - visitor,
|
| - node,
|
| - new ArgumentSublist(node.arguments, argumentsBefore),
|
| - functions,
|
| - new ArgumentSublist(node.arguments, argumentsAfter));
|
| - }
|
| -
|
| - ArgumentListVisitor._(this._visitor, this._node, this._arguments,
|
| - this._functions, this._argumentsAfterFunctions);
|
| -
|
| - /// Builds chunks for the call chain.
|
| - void visit() {
|
| - // If there is just one positional argument, it tends to look weird to
|
| - // split before it, so try not to.
|
| - if (_isSingle) _visitor.builder.startSpan();
|
| -
|
| - // Nest around the parentheses in case there are comments before or after
|
| - // them.
|
| - _visitor.builder.nestExpression();
|
| - _visitor.builder.startSpan();
|
| - _visitor.token(_node.leftParenthesis);
|
| -
|
| - _arguments.visit(_visitor);
|
| -
|
| - _visitor.builder.endSpan();
|
| -
|
| - if (_functions != null) {
|
| - // TODO(rnystrom): It might look better to treat the parameter list of the
|
| - // first function as if it were an argument in the preceding argument list
|
| - // instead of just having this little solo split here. That would try to
|
| - // keep the parameter list with other arguments when possible, and, I
|
| - // think, generally look nicer.
|
| - if (_functions.first == _node.arguments.first) {
|
| - _visitor.soloZeroSplit();
|
| - } else {
|
| - _visitor.soloSplit();
|
| - }
|
| -
|
| - for (var argument in _functions) {
|
| - if (argument != _functions.first) _visitor.space();
|
| -
|
| - _visitor.visit(argument);
|
| -
|
| - // Write the trailing comma.
|
| - if (argument != _node.arguments.last) {
|
| - _visitor.token(argument.endToken.next);
|
| - }
|
| - }
|
| -
|
| - _visitor.builder.startSpan();
|
| - _argumentsAfterFunctions.visit(_visitor);
|
| - _visitor.builder.endSpan();
|
| - }
|
| -
|
| - _visitor.token(_node.rightParenthesis);
|
| -
|
| - _visitor.builder.unnest();
|
| -
|
| - if (_isSingle) _visitor.builder.endSpan();
|
| - }
|
| -
|
| - /// Returns `true` if [expression] is a [FunctionExpression] with a block
|
| - /// body.
|
| - static bool _isBlockFunction(Expression expression) {
|
| - if (expression is NamedExpression) {
|
| - expression = (expression as NamedExpression).expression;
|
| - }
|
| -
|
| - // Allow functions wrapped in dotted method calls like "a.b.c(() { ... })".
|
| - if (expression is MethodInvocation) {
|
| - if (!_isValidWrappingTarget(expression.target)) return false;
|
| - if (expression.argumentList.arguments.length != 1) return false;
|
| -
|
| - return _isBlockFunction(expression.argumentList.arguments.single);
|
| - }
|
| -
|
| - // Curly body functions are.
|
| - if (expression is! FunctionExpression) return false;
|
| - var function = expression as FunctionExpression;
|
| - return function.body is BlockFunctionBody;
|
| - }
|
| -
|
| - /// Returns `true` if [expression] is a valid method invocation target for
|
| - /// an invocation that wraps a function literal argument.
|
| - static bool _isValidWrappingTarget(Expression expression) {
|
| - // Allow bare function calls.
|
| - if (expression == null) return true;
|
| -
|
| - // Allow property accesses.
|
| - while (expression is PropertyAccess) {
|
| - expression = (expression as PropertyAccess).target;
|
| - }
|
| -
|
| - if (expression is PrefixedIdentifier) return true;
|
| - if (expression is SimpleIdentifier) return true;
|
| -
|
| - return false;
|
| - }
|
| -}
|
| -
|
| -/// A range of arguments from a complete argument list.
|
| -///
|
| -/// One of these typically covers all of the arguments in an invocation. But,
|
| -/// when an argument list has block functions in the middle, the arguments
|
| -/// before and after the functions are treated as separate independent lists.
|
| -/// In that case, there will be two of these.
|
| -class ArgumentSublist {
|
| - /// The full argument list from the AST.
|
| - final List<Expression> _allArguments;
|
| -
|
| - /// The positional arguments, in order.
|
| - final List<Expression> _positional;
|
| -
|
| - /// The named arguments, in order.
|
| - final List<Expression> _named;
|
| -
|
| - /// The arguments that are collection literals that get special formatting.
|
| - final Set<Expression> _collections;
|
| -
|
| - /// The number of leading collections.
|
| - ///
|
| - /// If all arguments are collections, this counts them.
|
| - final int _leadingCollections;
|
| -
|
| - /// The number of trailing collections.
|
| - ///
|
| - /// If all arguments are collections, this is zero.
|
| - final int _trailingCollections;
|
| -
|
| - /// The rule used to split the bodies of all of the collection arguments.
|
| - Rule get _collectionRule {
|
| - // Lazy initialize.
|
| - if (_collectionRuleField == null && _collections.isNotEmpty) {
|
| - _collectionRuleField = new SimpleRule(cost: Cost.splitCollections);
|
| - }
|
| -
|
| - return _collectionRuleField;
|
| - }
|
| -
|
| - Rule _collectionRuleField;
|
| -
|
| - bool get _hasMultipleArguments => _positional.length + _named.length > 1;
|
| -
|
| - factory ArgumentSublist(
|
| - List<Expression> allArguments, List<Expression> arguments) {
|
| - // Assumes named arguments follow all positional ones.
|
| - var positional =
|
| - arguments.takeWhile((arg) => arg is! NamedExpression).toList();
|
| - var named = arguments.skip(positional.length).toList();
|
| -
|
| - var collections = arguments.where(_isCollectionArgument).toSet();
|
| -
|
| - // Count the leading arguments that are collection literals.
|
| - var leadingCollections = 0;
|
| - for (var argument in arguments) {
|
| - if (!collections.contains(argument)) break;
|
| - leadingCollections++;
|
| - }
|
| -
|
| - // Count the trailing arguments that are collection literals.
|
| - var trailingCollections = 0;
|
| - if (leadingCollections != arguments.length) {
|
| - for (var argument in arguments.reversed) {
|
| - if (!collections.contains(argument)) break;
|
| - trailingCollections++;
|
| - }
|
| - }
|
| -
|
| - // If only some of the named arguments are collections, treat none of them
|
| - // specially. Avoids cases like:
|
| - //
|
| - // function(
|
| - // a: arg,
|
| - // b: [
|
| - // ...
|
| - // ]);
|
| - if (trailingCollections < named.length) trailingCollections = 0;
|
| -
|
| - // Collections must all be a prefix or suffix of the argument list (and not
|
| - // both).
|
| - if (leadingCollections != collections.length) leadingCollections = 0;
|
| - if (trailingCollections != collections.length) trailingCollections = 0;
|
| -
|
| - // Ignore any collections in the middle of the argument list.
|
| - if (leadingCollections == 0 && trailingCollections == 0) {
|
| - collections.clear();
|
| - }
|
| -
|
| - return new ArgumentSublist._(allArguments, positional, named, collections,
|
| - leadingCollections, trailingCollections);
|
| - }
|
| -
|
| - ArgumentSublist._(this._allArguments, this._positional, this._named,
|
| - this._collections, this._leadingCollections, this._trailingCollections);
|
| -
|
| - void visit(SourceVisitor visitor) {
|
| - var rule = _visitPositional(visitor);
|
| - _visitNamed(visitor, rule);
|
| - }
|
| -
|
| - /// Writes the positional arguments, if any.
|
| - PositionalRule _visitPositional(SourceVisitor visitor) {
|
| - if (_positional.isEmpty) return null;
|
| -
|
| - // Allow splitting after "(".
|
| - var rule;
|
| - if (_positional.length == 1) {
|
| - rule = new SinglePositionalRule(_collectionRule,
|
| - splitsOnInnerRules: _allArguments.length > 1 &&
|
| - !_isCollectionArgument(_positional.first));
|
| - } else {
|
| - // Only count the positional bodies in the positional rule.
|
| - var leadingPositional = _leadingCollections;
|
| - if (_leadingCollections == _positional.length + _named.length) {
|
| - leadingPositional -= _named.length;
|
| - }
|
| -
|
| - var trailingPositional = _trailingCollections - _named.length;
|
| - rule = new MultiplePositionalRule(
|
| - _collectionRule, leadingPositional, trailingPositional);
|
| - }
|
| -
|
| - visitor.builder.startRule(rule);
|
| -
|
| - var chunk;
|
| - if (_isFirstArgument(_positional.first)) {
|
| - chunk = visitor.zeroSplit();
|
| - } else {
|
| - chunk = visitor.split();
|
| - }
|
| - rule.beforeArgument(chunk);
|
| -
|
| - // Try to not split the arguments.
|
| - visitor.builder.startSpan(Cost.positionalArguments);
|
| -
|
| - for (var argument in _positional) {
|
| - _visitArgument(visitor, rule, argument);
|
| -
|
| - // Positional arguments split independently.
|
| - if (argument != _positional.last) {
|
| - rule.beforeArgument(visitor.split());
|
| - }
|
| - }
|
| -
|
| - visitor.builder.endSpan();
|
| - visitor.builder.endRule();
|
| -
|
| - return rule;
|
| - }
|
| -
|
| - /// Writes the named arguments, if any.
|
| - void _visitNamed(SourceVisitor visitor, PositionalRule rule) {
|
| - if (_named.isEmpty) return;
|
| -
|
| - var positionalRule = rule;
|
| - var namedRule = new NamedRule(_collectionRule);
|
| - visitor.builder.startRule(namedRule);
|
| -
|
| - // Let the positional args force the named ones to split.
|
| - if (positionalRule != null) {
|
| - positionalRule.setNamedArgsRule(namedRule);
|
| - }
|
| -
|
| - // Split before the first named argument.
|
| - namedRule.beforeArguments(
|
| - visitor.builder.split(space: !_isFirstArgument(_named.first)));
|
| -
|
| - for (var argument in _named) {
|
| - _visitArgument(visitor, namedRule, argument);
|
| -
|
| - // Write the split.
|
| - if (argument != _named.last) visitor.split();
|
| - }
|
| -
|
| - visitor.builder.endRule();
|
| - }
|
| -
|
| - void _visitArgument(
|
| - SourceVisitor visitor, ArgumentRule rule, Expression argument) {
|
| - // If we're about to write a collection argument, handle it specially.
|
| - if (_collections.contains(argument)) {
|
| - if (rule != null) rule.beforeCollection();
|
| -
|
| - // Tell it to use the rule we've already created.
|
| - visitor.setNextLiteralBodyRule(_collectionRule);
|
| - } else if (_hasMultipleArguments) {
|
| - // Corner case: If there is just a single argument, don't bump the
|
| - // nesting. This lets us avoid spurious indentation in cases like:
|
| - //
|
| - // function(function(() {
|
| - // body;
|
| - // }));
|
| - visitor.builder.startBlockArgumentNesting();
|
| - }
|
| -
|
| - visitor.visit(argument);
|
| -
|
| - if (_collections.contains(argument)) {
|
| - if (rule != null) rule.afterCollection();
|
| - } else if (_hasMultipleArguments) {
|
| - visitor.builder.endBlockArgumentNesting();
|
| - }
|
| -
|
| - // Write the trailing comma.
|
| - if (!_isLastArgument(argument)) {
|
| - visitor.token(argument.endToken.next);
|
| - }
|
| - }
|
| -
|
| - bool _isFirstArgument(Expression argument) => argument == _allArguments.first;
|
| -
|
| - bool _isLastArgument(Expression argument) => argument == _allArguments.last;
|
| -
|
| - /// Returns true if [expression] denotes a collection literal argument.
|
| - ///
|
| - /// Similar to block functions, collection arguments can get special
|
| - /// indentation to make them look more statement-like.
|
| - static bool _isCollectionArgument(Expression expression) {
|
| - if (expression is NamedExpression) {
|
| - expression = (expression as NamedExpression).expression;
|
| - }
|
| -
|
| - // TODO(rnystrom): Should we step into parenthesized expressions?
|
| -
|
| - return expression is ListLiteral || expression is MapLiteral;
|
| - }
|
| -}
|
|
|