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

Side by Side Diff: packages/dart_style/lib/src/source_visitor.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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 | « packages/dart_style/lib/src/rule/rule.dart ('k') | packages/dart_style/lib/src/whitespace.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.source_visitor; 5 library dart_style.src.source_visitor;
6 6
7 import 'package:analyzer/analyzer.dart'; 7 import 'package:analyzer/analyzer.dart';
8 import 'package:analyzer/src/generated/scanner.dart'; 8 import 'package:analyzer/dart/ast/token.dart';
9 import 'package:analyzer/src/generated/source.dart'; 9 import 'package:analyzer/src/generated/source.dart';
10 10
11 import 'argument_list_visitor.dart'; 11 import 'argument_list_visitor.dart';
12 import 'call_chain_visitor.dart'; 12 import 'call_chain_visitor.dart';
13 import 'chunk.dart'; 13 import 'chunk.dart';
14 import 'chunk_builder.dart'; 14 import 'chunk_builder.dart';
15 import 'dart_formatter.dart'; 15 import 'dart_formatter.dart';
16 import 'rule/argument.dart'; 16 import 'rule/argument.dart';
17 import 'rule/combinator.dart'; 17 import 'rule/combinator.dart';
18 import 'rule/metadata.dart'; 18 import 'rule/metadata.dart';
19 import 'rule/rule.dart'; 19 import 'rule/rule.dart';
20 import 'rule/type_argument.dart'; 20 import 'rule/type_argument.dart';
21 import 'source_code.dart'; 21 import 'source_code.dart';
22 import 'whitespace.dart'; 22 import 'whitespace.dart';
23 23
24 /// Visits every token of the AST and passes all of the relevant bits to a 24 /// Visits every token of the AST and passes all of the relevant bits to a
25 /// [ChunkBuilder]. 25 /// [ChunkBuilder].
26 class SourceVisitor implements AstVisitor { 26 class SourceVisitor extends ThrowingAstVisitor {
27 /// The builder for the block that is currently being visited. 27 /// The builder for the block that is currently being visited.
28 ChunkBuilder builder; 28 ChunkBuilder builder;
29 29
30 final DartFormatter _formatter; 30 final DartFormatter _formatter;
31 31
32 /// Cached line info for calculating blank lines. 32 /// Cached line info for calculating blank lines.
33 LineInfo _lineInfo; 33 LineInfo _lineInfo;
34 34
35 /// The source being formatted. 35 /// The source being formatted.
36 final SourceCode _source; 36 final SourceCode _source;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 /// 126 ///
127 /// This is a bit complex to handle the rules for formatting positional and 127 /// This is a bit complex to handle the rules for formatting positional and
128 /// named arguments. The goals, in rough order of descending priority are: 128 /// named arguments. The goals, in rough order of descending priority are:
129 /// 129 ///
130 /// 1. Keep everything on the first line. 130 /// 1. Keep everything on the first line.
131 /// 2. Keep the named arguments together on the next line. 131 /// 2. Keep the named arguments together on the next line.
132 /// 3. Keep everything together on the second line. 132 /// 3. Keep everything together on the second line.
133 /// 4. Split between one or more positional arguments, trying to keep as many 133 /// 4. Split between one or more positional arguments, trying to keep as many
134 /// on earlier lines as possible. 134 /// on earlier lines as possible.
135 /// 5. Split the named arguments each onto their own line. 135 /// 5. Split the named arguments each onto their own line.
136 visitArgumentList(ArgumentList node) { 136 visitArgumentList(ArgumentList node, {bool nestExpression: true}) {
137 // Corner case: handle empty argument lists. 137 // Corner case: handle empty argument lists.
138 if (node.arguments.isEmpty) { 138 if (node.arguments.isEmpty) {
139 token(node.leftParenthesis); 139 token(node.leftParenthesis);
140 140
141 // If there is a comment inside the parens, do allow splitting before it. 141 // If there is a comment inside the parens, do allow splitting before it.
142 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); 142 if (node.rightParenthesis.precedingComments != null) soloZeroSplit();
143 143
144 token(node.rightParenthesis); 144 token(node.rightParenthesis);
145 return; 145 return;
146 } 146 }
147 147
148 // If the argument list has a trailing comma, format it like a collection
149 // literal where each argument goes on its own line, they are indented +2,
150 // and the ")" ends up on its own line.
151 if (node.arguments.last.endToken.next.type == TokenType.COMMA) {
152 _visitCollectionLiteral(
153 null, node.leftParenthesis, node.arguments, node.rightParenthesis);
154 return;
155 }
156
157 if (nestExpression) builder.nestExpression();
148 new ArgumentListVisitor(this, node).visit(); 158 new ArgumentListVisitor(this, node).visit();
159 if (nestExpression) builder.unnest();
149 } 160 }
150 161
151 visitAsExpression(AsExpression node) { 162 visitAsExpression(AsExpression node) {
152 builder.startSpan(); 163 builder.startSpan();
164 builder.nestExpression();
153 visit(node.expression); 165 visit(node.expression);
154 soloSplit(); 166 soloSplit();
155 token(node.asOperator); 167 token(node.asOperator);
156 space(); 168 space();
157 visit(node.type); 169 visit(node.type);
170 builder.unnest();
158 builder.endSpan(); 171 builder.endSpan();
159 } 172 }
160 173
174 // TODO(rnystrom): Type annotate once analyzer publishes a version with the
175 // new AST type.
176 // TODO(rnystrom): Test.
177 visitAssertInitializer(node) {
178 _simpleStatement(node, () {
179 token(node.assertKeyword);
180
181 var arguments = <Expression>[node.condition];
182 if (node.message != null) arguments.add(node.message);
183
184 builder.nestExpression();
185 var visitor = new ArgumentListVisitor.forArguments(
186 this, node.leftParenthesis, node.rightParenthesis, arguments);
187 visitor.visit();
188 builder.unnest();
189 });
190 }
191
161 visitAssertStatement(AssertStatement node) { 192 visitAssertStatement(AssertStatement node) {
162 _simpleStatement(node, () { 193 _simpleStatement(node, () {
163 token(node.assertKeyword); 194 token(node.assertKeyword);
164 token(node.leftParenthesis); 195
165 soloZeroSplit(); 196 var arguments = [node.condition];
166 visit(node.condition); 197 if (node.message != null) arguments.add(node.message);
167 token(node.rightParenthesis); 198
199 var visitor = new ArgumentListVisitor.forArguments(
200 this, node.leftParenthesis, node.rightParenthesis, arguments);
201 visitor.visit();
168 }); 202 });
169 } 203 }
170 204
171 visitAssignmentExpression(AssignmentExpression node) { 205 visitAssignmentExpression(AssignmentExpression node) {
172 builder.nestExpression(); 206 builder.nestExpression();
173 207
174 visit(node.leftHandSide); 208 visit(node.leftHandSide);
175 _visitAssignment(node.operator, node.rightHandSide); 209 _visitAssignment(node.operator, node.rightHandSide);
176 210
177 builder.unnest(); 211 builder.unnest();
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
234 268
235 visitBlock(Block node) { 269 visitBlock(Block node) {
236 // Don't allow splitting in an empty block. 270 // Don't allow splitting in an empty block.
237 if (node.statements.isEmpty && 271 if (node.statements.isEmpty &&
238 node.rightBracket.precedingComments == null) { 272 node.rightBracket.precedingComments == null) {
239 token(node.leftBracket); 273 token(node.leftBracket);
240 token(node.rightBracket); 274 token(node.rightBracket);
241 return; 275 return;
242 } 276 }
243 277
244 // For a block that is not a function body, just bump the indentation and 278 // If the block is a function body, it may get expression-level indentation,
245 // keep it in the current block. 279 // so handle it specially. Otherwise, just bump the indentation and keep it
246 if (node.parent is! BlockFunctionBody) { 280 // in the current block.
247 _writeBody(node.leftBracket, node.rightBracket, body: () { 281 if (node.parent is BlockFunctionBody) {
248 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); 282 _startLiteralBody(node.leftBracket);
249 }); 283 } else {
250 return; 284 _beginBody(node.leftBracket);
251 } 285 }
252 286
253 _startLiteralBody(node.leftBracket); 287 var needsDouble = true;
254 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); 288 for (var statement in node.statements) {
255 _endLiteralBody(node.rightBracket, forceSplit: node.statements.isNotEmpty); 289 if (needsDouble) {
290 twoNewlines();
291 } else {
292 oneOrTwoNewlines();
293 }
294
295 visit(statement);
296
297 needsDouble = false;
298 if (statement is FunctionDeclarationStatement) {
299 // Add a blank line after non-empty block functions.
300 var body = statement.functionDeclaration.functionExpression.body;
301 if (body is BlockFunctionBody) {
302 needsDouble = body.block.statements.isNotEmpty;
303 }
304 }
305 }
306
307 if (node.statements.isNotEmpty) newline();
308
309 if (node.parent is BlockFunctionBody) {
310 _endLiteralBody(node.rightBracket,
311 forceSplit: node.statements.isNotEmpty);
312 } else {
313 _endBody(node.rightBracket);
314 }
256 } 315 }
257 316
258 visitBlockFunctionBody(BlockFunctionBody node) { 317 visitBlockFunctionBody(BlockFunctionBody node) {
259 // Space after the parameter list. 318 // Space after the parameter list.
260 space(); 319 space();
261 320
262 // The "async" or "sync" keyword. 321 // The "async" or "sync" keyword.
263 token(node.keyword); 322 token(node.keyword);
264 323
265 // The "*" in "async*" or "sync*". 324 // The "*" in "async*" or "sync*".
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
332 /// Whether a cascade should be allowed to be inline as opposed to one 391 /// Whether a cascade should be allowed to be inline as opposed to one
333 /// expression per line. 392 /// expression per line.
334 bool _allowInlineCascade(List<Expression> sections) { 393 bool _allowInlineCascade(List<Expression> sections) {
335 if (sections.length < 2) return true; 394 if (sections.length < 2) return true;
336 395
337 var name; 396 var name;
338 // We could be more forgiving about what constitutes sections with 397 // We could be more forgiving about what constitutes sections with
339 // consistent names but for now we require all sections to have the same 398 // consistent names but for now we require all sections to have the same
340 // method name. 399 // method name.
341 for (var expression in sections) { 400 for (var expression in sections) {
342 if (expression is! MethodInvocation) return false; 401 if (expression is MethodInvocation) {
343 if (name == null) { 402 if (name == null) {
344 name = expression.methodName.name; 403 name = expression.methodName.name;
345 } else if (name != expression.methodName.name) { 404 } else if (name != expression.methodName.name) {
405 return false;
406 }
407 } else {
346 return false; 408 return false;
347 } 409 }
348 } 410 }
349 return true; 411 return true;
350 } 412 }
351 413
352 visitCatchClause(CatchClause node) { 414 visitCatchClause(CatchClause node) {
353 token(node.onKeyword, after: space); 415 token(node.onKeyword, after: space);
354 visit(node.exceptionType); 416 visit(node.exceptionType);
355 417
356 if (node.catchKeyword != null) { 418 if (node.catchKeyword != null) {
357 if (node.exceptionType != null) { 419 if (node.exceptionType != null) {
358 space(); 420 space();
359 } 421 }
360 token(node.catchKeyword); 422 token(node.catchKeyword);
361 space(); 423 space();
362 token(node.leftParenthesis); 424 token(node.leftParenthesis);
363 visit(node.exceptionParameter); 425 visit(node.exceptionParameter);
364 token(node.comma, after: space); 426 token(node.comma, after: space);
365 visit(node.stackTraceParameter); 427 visit(node.stackTraceParameter);
366 token(node.rightParenthesis); 428 token(node.rightParenthesis);
367 space(); 429 space();
368 } else { 430 } else {
369 space(); 431 space();
370 } 432 }
371 visit(node.body); 433 visit(node.body);
372 } 434 }
373 435
374 visitClassDeclaration(ClassDeclaration node) { 436 visitClassDeclaration(ClassDeclaration node) {
375 visitDeclarationMetadata(node.metadata); 437 visitMetadata(node.metadata);
376 438
377 builder.nestExpression(); 439 builder.nestExpression();
378 modifier(node.abstractKeyword); 440 modifier(node.abstractKeyword);
379 token(node.classKeyword); 441 token(node.classKeyword);
380 space(); 442 space();
381 visit(node.name); 443 visit(node.name);
382 visit(node.typeParameters); 444 visit(node.typeParameters);
383 visit(node.extendsClause); 445 visit(node.extendsClause);
384 446
385 builder.startRule(new CombinatorRule()); 447 builder.startRule(new CombinatorRule());
386 visit(node.withClause); 448 visit(node.withClause);
387 visit(node.implementsClause); 449 visit(node.implementsClause);
388 builder.endRule(); 450 builder.endRule();
389 451
390 visit(node.nativeClause, before: space); 452 visit(node.nativeClause, before: space);
391 space(); 453 space();
392 454
393 builder.unnest(); 455 builder.unnest();
394 _writeBody(node.leftBracket, node.rightBracket, body: () { 456 _beginBody(node.leftBracket);
395 if (node.members.isNotEmpty) {
396 for (var member in node.members) {
397 visit(member);
398 457
399 if (member == node.members.last) { 458 if (node.members.isNotEmpty) {
400 newline(); 459 for (var member in node.members) {
401 break; 460 visit(member);
402 }
403 461
404 var needsDouble = false; 462 if (member == node.members.last) {
405 if (member is ClassDeclaration) { 463 newline();
406 // Add a blank line after classes. 464 break;
407 twoNewlines(); 465 }
408 } else if (member is MethodDeclaration) {
409 // Add a blank line after non-empty block methods.
410 var method = member as MethodDeclaration;
411 if (method.body is BlockFunctionBody) {
412 var body = method.body as BlockFunctionBody;
413 needsDouble = body.block.statements.isNotEmpty;
414 }
415 }
416 466
417 if (needsDouble) { 467 var needsDouble = false;
418 twoNewlines(); 468 if (member is ClassDeclaration) {
419 } else { 469 // Add a blank line after classes.
420 // Variables and arrow-bodied members can be more tightly packed if 470 twoNewlines();
421 // the user wants to group things together. 471 } else if (member is MethodDeclaration) {
422 oneOrTwoNewlines(); 472 // Add a blank line after non-empty block methods.
473 if (member.body is BlockFunctionBody) {
474 var body = member.body as BlockFunctionBody;
475 needsDouble = body.block.statements.isNotEmpty;
423 } 476 }
424 } 477 }
478
479 if (needsDouble) {
480 twoNewlines();
481 } else {
482 // Variables and arrow-bodied members can be more tightly packed if
483 // the user wants to group things together.
484 oneOrTwoNewlines();
485 }
425 } 486 }
426 }); 487 }
488
489 _endBody(node.rightBracket);
427 } 490 }
428 491
429 visitClassTypeAlias(ClassTypeAlias node) { 492 visitClassTypeAlias(ClassTypeAlias node) {
430 visitDeclarationMetadata(node.metadata); 493 visitMetadata(node.metadata);
431 494
432 _simpleStatement(node, () { 495 _simpleStatement(node, () {
433 modifier(node.abstractKeyword); 496 modifier(node.abstractKeyword);
434 token(node.typedefKeyword); 497 token(node.typedefKeyword);
435 space(); 498 space();
436 visit(node.name); 499 visit(node.name);
437 visit(node.typeParameters); 500 visit(node.typeParameters);
438 space(); 501 space();
439 token(node.equals); 502 token(node.equals);
440 space(); 503 space();
(...skipping 18 matching lines...) Expand all
459 var directives = node.directives; 522 var directives = node.directives;
460 if (directives.isNotEmpty && directives.first is LibraryDirective) { 523 if (directives.isNotEmpty && directives.first is LibraryDirective) {
461 visit(directives.first); 524 visit(directives.first);
462 twoNewlines(); 525 twoNewlines();
463 526
464 directives = directives.skip(1); 527 directives = directives.skip(1);
465 } 528 }
466 529
467 visitNodes(directives, between: oneOrTwoNewlines); 530 visitNodes(directives, between: oneOrTwoNewlines);
468 531
469 if (node.declarations.isNotEmpty) { 532 var needsDouble = true;
470 var needsDouble = true; 533 for (var declaration in node.declarations) {
534 // Add a blank line before classes.
535 if (declaration is ClassDeclaration) needsDouble = true;
471 536
472 for (var declaration in node.declarations) { 537 if (needsDouble) {
473 // Add a blank line before classes. 538 twoNewlines();
474 if (declaration is ClassDeclaration) needsDouble = true; 539 } else {
540 // Variables and arrow-bodied members can be more tightly packed if
541 // the user wants to group things together.
542 oneOrTwoNewlines();
543 }
475 544
476 if (needsDouble) { 545 visit(declaration);
477 twoNewlines();
478 } else {
479 // Variables and arrow-bodied members can be more tightly packed if
480 // the user wants to group things together.
481 oneOrTwoNewlines();
482 }
483 546
484 visit(declaration); 547 needsDouble = false;
485 548 if (declaration is ClassDeclaration) {
486 needsDouble = false; 549 // Add a blank line after classes.
487 if (declaration is ClassDeclaration) { 550 needsDouble = true;
488 // Add a blank line after classes. 551 } else if (declaration is FunctionDeclaration) {
489 needsDouble = true; 552 // Add a blank line after non-empty block functions.
490 } else if (declaration is FunctionDeclaration) { 553 var body = declaration.functionExpression.body;
491 // Add a blank line after non-empty block functions. 554 if (body is BlockFunctionBody) {
492 var function = declaration as FunctionDeclaration; 555 needsDouble = body.block.statements.isNotEmpty;
493 if (function.functionExpression.body is BlockFunctionBody) {
494 var body = function.functionExpression.body as BlockFunctionBody;
495 needsDouble = body.block.statements.isNotEmpty;
496 }
497 } 556 }
498 } 557 }
499 } 558 }
500 } 559 }
501 560
502 visitConditionalExpression(ConditionalExpression node) { 561 visitConditionalExpression(ConditionalExpression node) {
503 builder.nestExpression(); 562 builder.nestExpression();
504 563
564 // Start lazily so we don't force the operator to split if a line comment
565 // appears before the first operand. If we split after one clause in a
566 // conditional, always split after both.
567 builder.startLazyRule();
568 visit(node.condition);
569
505 // Push any block arguments all the way past the leading "?" and ":". 570 // Push any block arguments all the way past the leading "?" and ":".
506 builder.nestExpression(indent: Indent.block, now: true); 571 builder.nestExpression(indent: Indent.block, now: true);
507 builder.startBlockArgumentNesting(); 572 builder.startBlockArgumentNesting();
508 builder.unnest(); 573 builder.unnest();
509 574
510 visit(node.condition);
511
512 builder.startSpan(); 575 builder.startSpan();
513 576
514 // If we split after one clause in a conditional, always split after both.
515 builder.startRule();
516 split(); 577 split();
517 token(node.question); 578 token(node.question);
518 space(); 579 space();
519
520 builder.nestExpression(); 580 builder.nestExpression();
521 visit(node.thenExpression); 581 visit(node.thenExpression);
522 builder.unnest(); 582 builder.unnest();
523 583
524 split(); 584 split();
525 token(node.colon); 585 token(node.colon);
526 space(); 586 space();
527
528 visit(node.elseExpression); 587 visit(node.elseExpression);
529 588
530 builder.endRule(); 589 builder.endRule();
531 builder.endSpan(); 590 builder.endSpan();
532 builder.endBlockArgumentNesting(); 591 builder.endBlockArgumentNesting();
533 builder.unnest(); 592 builder.unnest();
534 } 593 }
535 594
595 visitConfiguration(Configuration node) {
596 token(node.ifKeyword);
597 space();
598 token(node.leftParenthesis);
599 visit(node.name);
600
601 if (node.equalToken != null) {
602 builder.nestExpression();
603 space();
604 token(node.equalToken);
605 soloSplit();
606 visit(node.value);
607 builder.unnest();
608 }
609
610 token(node.rightParenthesis);
611 space();
612 visit(node.uri);
613 }
614
536 visitConstructorDeclaration(ConstructorDeclaration node) { 615 visitConstructorDeclaration(ConstructorDeclaration node) {
537 visitMemberMetadata(node.metadata); 616 visitMetadata(node.metadata);
538 617
539 modifier(node.externalKeyword); 618 modifier(node.externalKeyword);
540 modifier(node.constKeyword); 619 modifier(node.constKeyword);
541 modifier(node.factoryKeyword); 620 modifier(node.factoryKeyword);
542 visit(node.returnType); 621 visit(node.returnType);
543 token(node.period); 622 token(node.period);
544 visit(node.name); 623 visit(node.name);
545 624
546 // Make the rule for the ":" span both the preceding parameter list and 625 // Make the rule for the ":" span both the preceding parameter list and
547 // the entire initialization list. This ensures that we split before the 626 // the entire initialization list. This ensures that we split before the
548 // ":" if the parameters and initialization list don't all fit on one line. 627 // ":" if the parameters and initialization list don't all fit on one line.
549 builder.startRule(); 628 builder.startRule();
550 629
551 // If the redirecting constructor happens to wrap, we want to make sure 630 // If the redirecting constructor happens to wrap, we want to make sure
552 // the parameter list gets more deeply indented. 631 // the parameter list gets more deeply indented.
553 if (node.redirectedConstructor != null) builder.nestExpression(); 632 if (node.redirectedConstructor != null) builder.nestExpression();
554 633
555 _visitBody(node.parameters, node.body, () { 634 _visitBody(null, node.parameters, node.body, () {
556 // Check for redirects or initializer lists. 635 // Check for redirects or initializer lists.
557 if (node.redirectedConstructor != null) { 636 if (node.redirectedConstructor != null) {
558 _visitConstructorRedirects(node); 637 _visitConstructorRedirects(node);
559 builder.unnest(); 638 builder.unnest();
560 } else if (node.initializers.isNotEmpty) { 639 } else if (node.initializers.isNotEmpty) {
561 _visitConstructorInitializers(node); 640 _visitConstructorInitializers(node);
562 } 641 }
563 }); 642 });
564 } 643 }
565 644
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 token(node.whileKeyword); 738 token(node.whileKeyword);
660 space(); 739 space();
661 token(node.leftParenthesis); 740 token(node.leftParenthesis);
662 soloZeroSplit(); 741 soloZeroSplit();
663 visit(node.condition); 742 visit(node.condition);
664 token(node.rightParenthesis); 743 token(node.rightParenthesis);
665 token(node.semicolon); 744 token(node.semicolon);
666 builder.unnest(); 745 builder.unnest();
667 } 746 }
668 747
748 visitDottedName(DottedName node) {
749 for (var component in node.components) {
750 // Write the preceding ".".
751 if (component != node.components.first) {
752 token(component.beginToken.previous);
753 }
754
755 visit(component);
756 }
757 }
758
669 visitDoubleLiteral(DoubleLiteral node) { 759 visitDoubleLiteral(DoubleLiteral node) {
670 token(node.literal); 760 token(node.literal);
671 } 761 }
672 762
673 visitEmptyFunctionBody(EmptyFunctionBody node) { 763 visitEmptyFunctionBody(EmptyFunctionBody node) {
674 token(node.semicolon); 764 token(node.semicolon);
675 } 765 }
676 766
677 visitEmptyStatement(EmptyStatement node) { 767 visitEmptyStatement(EmptyStatement node) {
678 token(node.semicolon); 768 token(node.semicolon);
679 } 769 }
680 770
681 visitEnumConstantDeclaration(EnumConstantDeclaration node) { 771 visitEnumConstantDeclaration(EnumConstantDeclaration node) {
682 visit(node.name); 772 visit(node.name);
683 } 773 }
684 774
685 visitEnumDeclaration(EnumDeclaration node) { 775 visitEnumDeclaration(EnumDeclaration node) {
686 visitDeclarationMetadata(node.metadata); 776 visitMetadata(node.metadata);
687 777
688 token(node.enumKeyword); 778 token(node.enumKeyword);
689 space(); 779 space();
690 visit(node.name); 780 visit(node.name);
691 space(); 781 space();
692 782
693 _writeBody(node.leftBracket, node.rightBracket, space: true, body: () { 783 _beginBody(node.leftBracket, space: true);
694 visitCommaSeparatedNodes(node.constants, between: split); 784 visitCommaSeparatedNodes(node.constants, between: split);
695 }); 785
786 // If there is a trailing comma, always force the constants to split.
787 if (node.constants.last.endToken.next.type == TokenType.COMMA) {
788 builder.forceRules();
789 }
790
791 _endBody(node.rightBracket, space: true);
696 } 792 }
697 793
698 visitExportDirective(ExportDirective node) { 794 visitExportDirective(ExportDirective node) {
699 visitDeclarationMetadata(node.metadata); 795 visitMetadata(node.metadata);
700 796
701 _simpleStatement(node, () { 797 _simpleStatement(node, () {
702 token(node.keyword); 798 token(node.keyword);
703 space(); 799 space();
704 visit(node.uri); 800 visit(node.uri);
705 801
802 _visitConfigurations(node.configurations);
803
706 builder.startRule(new CombinatorRule()); 804 builder.startRule(new CombinatorRule());
707 visitNodes(node.combinators); 805 visitNodes(node.combinators);
708 builder.endRule(); 806 builder.endRule();
709 }); 807 });
710 } 808 }
711 809
712 visitExpressionFunctionBody(ExpressionFunctionBody node) { 810 visitExpressionFunctionBody(ExpressionFunctionBody node) {
713 // Space after the parameter list. 811 // Space after the parameter list.
714 space(); 812 space();
715 813
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
750 } 848 }
751 849
752 visitExtendsClause(ExtendsClause node) { 850 visitExtendsClause(ExtendsClause node) {
753 soloSplit(); 851 soloSplit();
754 token(node.extendsKeyword); 852 token(node.extendsKeyword);
755 space(); 853 space();
756 visit(node.superclass); 854 visit(node.superclass);
757 } 855 }
758 856
759 visitFieldDeclaration(FieldDeclaration node) { 857 visitFieldDeclaration(FieldDeclaration node) {
760 visitMemberMetadata(node.metadata); 858 visitMetadata(node.metadata);
761 859
762 _simpleStatement(node, () { 860 _simpleStatement(node, () {
763 modifier(node.staticKeyword); 861 modifier(node.staticKeyword);
862 modifier(node.covariantKeyword);
764 visit(node.fields); 863 visit(node.fields);
765 }); 864 });
766 } 865 }
767 866
768 visitFieldFormalParameter(FieldFormalParameter node) { 867 visitFieldFormalParameter(FieldFormalParameter node) {
769 visitParameterMetadata(node.metadata, () { 868 visitParameterMetadata(node.metadata, () {
869 modifier(node.covariantKeyword);
770 token(node.keyword, after: space); 870 token(node.keyword, after: space);
771 visit(node.type, after: space); 871 visit(node.type, after: space);
772 token(node.thisKeyword); 872 token(node.thisKeyword);
773 token(node.period); 873 token(node.period);
774 visit(node.identifier); 874 visit(node.identifier);
775 visit(node.parameters); 875 visit(node.parameters);
776 }); 876 });
777 } 877 }
778 878
779 visitForEachStatement(ForEachStatement node) { 879 visitForEachStatement(ForEachStatement node) {
780 builder.nestExpression(); 880 builder.nestExpression();
781 token(node.awaitKeyword, after: space); 881 token(node.awaitKeyword, after: space);
782 token(node.forKeyword); 882 token(node.forKeyword);
783 space(); 883 space();
784 token(node.leftParenthesis); 884 token(node.leftParenthesis);
785 if (node.loopVariable != null) { 885 if (node.loopVariable != null) {
786 visit(node.loopVariable); 886 visit(node.loopVariable);
787 } else { 887 } else {
788 visit(node.identifier); 888 visit(node.identifier);
789 } 889 }
790 soloSplit(); 890 soloSplit();
791 token(node.inKeyword); 891 token(node.inKeyword);
792 space(); 892 space();
793 visit(node.iterable); 893 visit(node.iterable);
794 token(node.rightParenthesis); 894 token(node.rightParenthesis);
795 builder.unnest(now: false); 895 builder.unnest();
796 896
797 _visitLoopBody(node.body); 897 _visitLoopBody(node.body);
798 } 898 }
799 899
800 visitFormalParameterList(FormalParameterList node) { 900 visitFormalParameterList(FormalParameterList node,
901 {bool nestExpression: true}) {
801 // Corner case: empty parameter lists. 902 // Corner case: empty parameter lists.
802 if (node.parameters.isEmpty) { 903 if (node.parameters.isEmpty) {
803 token(node.leftParenthesis); 904 token(node.leftParenthesis);
804 905
805 // If there is a comment, do allow splitting before it. 906 // If there is a comment, do allow splitting before it.
806 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); 907 if (node.rightParenthesis.precedingComments != null) soloZeroSplit();
807 908
808 token(node.rightParenthesis); 909 token(node.rightParenthesis);
809 return; 910 return;
810 } 911 }
811 912
913 // If the parameter list has a trailing comma, format it like a collection
914 // literal where each parameter goes on its own line, they are indented +2,
915 // and the ")" ends up on its own line.
916 if (node.parameters.last.endToken.next.type == TokenType.COMMA) {
917 _visitTrailingCommaParameterList(node);
918 return;
919 }
920
812 var requiredParams = node.parameters 921 var requiredParams = node.parameters
813 .where((param) => param is! DefaultFormalParameter) 922 .where((param) => param is! DefaultFormalParameter)
814 .toList(); 923 .toList();
815 var optionalParams = node.parameters 924 var optionalParams = node.parameters
816 .where((param) => param is DefaultFormalParameter) 925 .where((param) => param is DefaultFormalParameter)
817 .toList(); 926 .toList();
818 927
819 builder.nestExpression(); 928 if (nestExpression) builder.nestExpression();
820 token(node.leftParenthesis); 929 token(node.leftParenthesis);
821 930
822 _metadataRules.add(new MetadataRule()); 931 _metadataRules.add(new MetadataRule());
823 932
824 var rule; 933 var rule;
825 if (requiredParams.isNotEmpty) { 934 if (requiredParams.isNotEmpty) {
826 if (requiredParams.length > 1) { 935 rule = new PositionalRule(null, 0, 0);
827 rule = new MultiplePositionalRule(null, 0, 0);
828 } else {
829 rule = new SinglePositionalRule(null);
830 }
831
832 _metadataRules.last.bindPositionalRule(rule); 936 _metadataRules.last.bindPositionalRule(rule);
833 937
834 builder.startRule(rule); 938 builder.startRule(rule);
835 if (_isInLambda(node)) { 939 if (_isInLambda(node)) {
836 // Don't allow splitting before the first argument (i.e. right after 940 // Don't allow splitting before the first argument (i.e. right after
837 // the bare "(" in a lambda. Instead, just stuff a null chunk in there 941 // the bare "(" in a lambda. Instead, just stuff a null chunk in there
838 // to avoid confusing the arg rule. 942 // to avoid confusing the arg rule.
839 rule.beforeArgument(null); 943 rule.beforeArgument(null);
840 } else { 944 } else {
841 // Split before the first argument. 945 // Split before the first argument.
842 rule.beforeArgument(zeroSplit()); 946 rule.beforeArgument(zeroSplit());
843 } 947 }
844 948
845 builder.startSpan(); 949 builder.startSpan();
846 950
847 for (var param in requiredParams) { 951 for (var param in requiredParams) {
848 visit(param); 952 visit(param);
849 953
850 // Write the trailing comma. 954 // Write the following comma.
851 if (param != node.parameters.last) token(param.endToken.next); 955 if (param.endToken.next.type == TokenType.COMMA) {
956 token(param.endToken.next);
957 }
852 958
853 if (param != requiredParams.last) rule.beforeArgument(split()); 959 if (param != requiredParams.last) rule.beforeArgument(split());
854 } 960 }
855 961
856 builder.endSpan(); 962 builder.endSpan();
857 builder.endRule(); 963 builder.endRule();
858 } 964 }
859 965
860 if (optionalParams.isNotEmpty) { 966 if (optionalParams.isNotEmpty) {
861 var namedRule = new NamedRule(null, 0, 0); 967 var namedRule = new NamedRule(null, 0, 0);
862 if (rule != null) rule.setNamedArgsRule(namedRule); 968 if (rule != null) rule.setNamedArgsRule(namedRule);
863 969
864 _metadataRules.last.bindNamedRule(namedRule); 970 _metadataRules.last.bindNamedRule(namedRule);
865 971
866 builder.startRule(namedRule); 972 builder.startRule(namedRule);
867 973
868 // Make sure multi-line default values are indented. 974 // Make sure multi-line default values are indented.
869 builder.startBlockArgumentNesting(); 975 builder.startBlockArgumentNesting();
870 976
871 namedRule.beforeArgument(builder.split(space: requiredParams.isNotEmpty)); 977 namedRule.beforeArgument(builder.split(space: requiredParams.isNotEmpty));
872 978
873 // "[" or "{" for optional parameters. 979 // "[" or "{" for optional parameters.
874 token(node.leftDelimiter); 980 token(node.leftDelimiter);
875 981
876 for (var param in optionalParams) { 982 for (var param in optionalParams) {
877 visit(param); 983 visit(param);
878 984
879 // Write the trailing comma. 985 // Write the following comma.
880 if (param != node.parameters.last) token(param.endToken.next); 986 if (param.endToken.next.type == TokenType.COMMA) {
987 token(param.endToken.next);
988 }
989
881 if (param != optionalParams.last) namedRule.beforeArgument(split()); 990 if (param != optionalParams.last) namedRule.beforeArgument(split());
882 } 991 }
883 992
884 builder.endBlockArgumentNesting(); 993 builder.endBlockArgumentNesting();
885 builder.endRule(); 994 builder.endRule();
886 995
887 // "]" or "}" for optional parameters. 996 // "]" or "}" for optional parameters.
888 token(node.rightDelimiter); 997 token(node.rightDelimiter);
889 } 998 }
890 999
891 _metadataRules.removeLast(); 1000 _metadataRules.removeLast();
892 1001
893 token(node.rightParenthesis); 1002 token(node.rightParenthesis);
894 builder.unnest(); 1003 if (nestExpression) builder.unnest();
895 } 1004 }
896 1005
897 visitForStatement(ForStatement node) { 1006 visitForStatement(ForStatement node) {
898 builder.nestExpression(); 1007 builder.nestExpression();
899 token(node.forKeyword); 1008 token(node.forKeyword);
900 space(); 1009 space();
901 token(node.leftParenthesis); 1010 token(node.leftParenthesis);
902 1011
903 builder.startRule(); 1012 builder.startRule();
904 1013
905 // The initialization clause. 1014 // The initialization clause.
906 if (node.initialization != null) { 1015 if (node.initialization != null) {
907 visit(node.initialization); 1016 visit(node.initialization);
908 } else if (node.variables != null) { 1017 } else if (node.variables != null) {
909 // Nest split variables more so they aren't at the same level 1018 // Nest split variables more so they aren't at the same level
910 // as the rest of the loop clauses. 1019 // as the rest of the loop clauses.
911 builder.nestExpression(); 1020 builder.nestExpression();
912 1021
913 // Allow the variables to stay unsplit even if the clauses split. 1022 // Allow the variables to stay unsplit even if the clauses split.
914 builder.startRule(); 1023 builder.startRule();
915 1024
916 var declaration = node.variables; 1025 var declaration = node.variables;
917 visitDeclarationMetadata(declaration.metadata); 1026 visitMetadata(declaration.metadata);
918 modifier(declaration.keyword); 1027 modifier(declaration.keyword);
919 visit(declaration.type, after: space); 1028 visit(declaration.type, after: space);
920 1029
921 visitCommaSeparatedNodes(declaration.variables, between: () { 1030 visitCommaSeparatedNodes(declaration.variables, between: () {
922 split(); 1031 split();
923 }); 1032 });
924 1033
925 builder.endRule(); 1034 builder.endRule();
926 builder.unnest(); 1035 builder.unnest();
927 } 1036 }
(...skipping 26 matching lines...) Expand all
954 1063
955 visitFunctionDeclaration(FunctionDeclaration node) { 1064 visitFunctionDeclaration(FunctionDeclaration node) {
956 _visitMemberDeclaration(node, node.functionExpression); 1065 _visitMemberDeclaration(node, node.functionExpression);
957 } 1066 }
958 1067
959 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { 1068 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
960 visit(node.functionDeclaration); 1069 visit(node.functionDeclaration);
961 } 1070 }
962 1071
963 visitFunctionExpression(FunctionExpression node) { 1072 visitFunctionExpression(FunctionExpression node) {
964 _visitBody(node.parameters, node.body); 1073 // TODO(rnystrom): This is working but not tested. As of 2016/11/29, the
1074 // latest version of analyzer on pub does not parse generic lambdas. When
1075 // a version of it that does is published, upgrade dart_style to use it and
1076 // then test it:
1077 //
1078 // >>> generic function expression
1079 // main() {
1080 // var generic = < T,S >(){};
1081 // }
1082 // <<<
1083 // main() {
1084 // var generic = <T, S>() {};
1085 // }
1086 _visitBody(node.typeParameters, node.parameters, node.body);
965 } 1087 }
966 1088
967 visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { 1089 visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
968 visit(node.function); 1090 visit(node.function);
969 visit(node.argumentList); 1091 visit(node.argumentList);
970 } 1092 }
971 1093
972 visitFunctionTypeAlias(FunctionTypeAlias node) { 1094 visitFunctionTypeAlias(FunctionTypeAlias node) {
973 visitDeclarationMetadata(node.metadata); 1095 visitMetadata(node.metadata);
974 1096
975 _simpleStatement(node, () { 1097 _simpleStatement(node, () {
976 token(node.typedefKeyword); 1098 token(node.typedefKeyword);
977 space(); 1099 space();
978 visit(node.returnType, after: space); 1100 visit(node.returnType, after: space);
979 visit(node.name); 1101 visit(node.name);
980 visit(node.typeParameters); 1102 visit(node.typeParameters);
981 visit(node.parameters); 1103 visit(node.parameters);
982 }); 1104 });
983 } 1105 }
984 1106
985 visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { 1107 visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
986 visitParameterMetadata(node.metadata, () { 1108 visitParameterMetadata(node.metadata, () {
1109 modifier(node.covariantKeyword);
987 visit(node.returnType, after: space); 1110 visit(node.returnType, after: space);
988 1111
989 // Try to keep the function's parameters with its name. 1112 // Try to keep the function's parameters with its name.
990 builder.startSpan(); 1113 builder.startSpan();
991 visit(node.identifier); 1114 visit(node.identifier);
992 visit(node.parameters); 1115 visit(node.parameters);
993 builder.endSpan(); 1116 builder.endSpan();
994 }); 1117 });
995 } 1118 }
996 1119
997 visitHideCombinator(HideCombinator node) { 1120 visitHideCombinator(HideCombinator node) {
998 _visitCombinator(node.keyword, node.hiddenNames); 1121 _visitCombinator(node.keyword, node.hiddenNames);
999 } 1122 }
1000 1123
1001 visitIfStatement(IfStatement node) { 1124 visitIfStatement(IfStatement node) {
1002 builder.nestExpression(); 1125 builder.nestExpression();
1003 token(node.ifKeyword); 1126 token(node.ifKeyword);
1004 space(); 1127 space();
1005 token(node.leftParenthesis); 1128 token(node.leftParenthesis);
1006 visit(node.condition); 1129 visit(node.condition);
1007 token(node.rightParenthesis); 1130 token(node.rightParenthesis);
1008 builder.unnest(now: false); 1131 builder.unnest();
1009 1132
1010 visitClause(Statement clause) { 1133 visitClause(Statement clause) {
1011 if (clause is Block || clause is IfStatement) { 1134 if (clause is Block || clause is IfStatement) {
1012 space(); 1135 space();
1013 visit(clause); 1136 visit(clause);
1014 } else { 1137 } else {
1015 // Allow splitting in an expression-bodied if even though it's against 1138 // Allow splitting in a statement-bodied if even though it's against
1016 // the style guide. Since we can't fix the code itself to follow the 1139 // the style guide. Since we can't fix the code itself to follow the
1017 // style guide, we should at least format it as well as we can. 1140 // style guide, we should at least format it as well as we can.
1018 builder.nestExpression(indent: 2, now: true); 1141 builder.indent();
1019 builder.startRule(); 1142 builder.startRule();
1020 1143
1021 // If there is an else clause, always split before both the then and 1144 // If there is an else clause, always split before both the then and
1022 // else statements. 1145 // else statements.
1023 if (node.elseStatement != null) { 1146 if (node.elseStatement != null) {
1024 builder.writeWhitespace(Whitespace.nestedNewline); 1147 builder.writeWhitespace(Whitespace.newline);
1025 } else { 1148 } else {
1026 split(); 1149 builder.split(nest: false, space: true);
1027 } 1150 }
1028 1151
1029 visit(clause); 1152 visit(clause);
1030 1153
1031 builder.endRule(); 1154 builder.endRule();
1032 builder.unnest(); 1155 builder.unindent();
1033 } 1156 }
1034 } 1157 }
1035 1158
1036 visitClause(node.thenStatement); 1159 visitClause(node.thenStatement);
1037 1160
1038 if (node.elseStatement != null) { 1161 if (node.elseStatement != null) {
1039 if (node.thenStatement is Block) { 1162 if (node.thenStatement is Block) {
1040 space(); 1163 space();
1041 } else { 1164 } else {
1042 // Corner case where an else follows a single-statement then clause. 1165 // Corner case where an else follows a single-statement then clause.
1043 // This is against the style guide, but we still need to handle it. If 1166 // This is against the style guide, but we still need to handle it. If
1044 // it happens, put the else on the next line. 1167 // it happens, put the else on the next line.
1045 newline(); 1168 newline();
1046 } 1169 }
1047 1170
1048 token(node.elseKeyword); 1171 token(node.elseKeyword);
1049 visitClause(node.elseStatement); 1172 visitClause(node.elseStatement);
1050 } 1173 }
1051 } 1174 }
1052 1175
1053 visitImplementsClause(ImplementsClause node) { 1176 visitImplementsClause(ImplementsClause node) {
1054 _visitCombinator(node.implementsKeyword, node.interfaces); 1177 _visitCombinator(node.implementsKeyword, node.interfaces);
1055 } 1178 }
1056 1179
1057 visitImportDirective(ImportDirective node) { 1180 visitImportDirective(ImportDirective node) {
1058 visitDeclarationMetadata(node.metadata); 1181 visitMetadata(node.metadata);
1059 1182
1060 _simpleStatement(node, () { 1183 _simpleStatement(node, () {
1061 token(node.keyword); 1184 token(node.keyword);
1062 space(); 1185 space();
1063 visit(node.uri); 1186 visit(node.uri);
1064 1187
1188 _visitConfigurations(node.configurations);
1189
1065 if (node.asKeyword != null) { 1190 if (node.asKeyword != null) {
1066 soloSplit(); 1191 soloSplit();
1067 token(node.deferredKeyword, after: space); 1192 token(node.deferredKeyword, after: space);
1068 token(node.asKeyword); 1193 token(node.asKeyword);
1069 space(); 1194 space();
1070 visit(node.prefix); 1195 visit(node.prefix);
1071 } 1196 }
1072 1197
1073 builder.startRule(new CombinatorRule()); 1198 builder.startRule(new CombinatorRule());
1074 visitNodes(node.combinators); 1199 visitNodes(node.combinators);
(...skipping 21 matching lines...) Expand all
1096 /// call chains. 1221 /// call chains.
1097 void finishIndexExpression(IndexExpression node) { 1222 void finishIndexExpression(IndexExpression node) {
1098 if (node.target is IndexExpression) { 1223 if (node.target is IndexExpression) {
1099 // Edge case: On a chain of [] accesses, allow splitting between them. 1224 // Edge case: On a chain of [] accesses, allow splitting between them.
1100 // Produces nicer output in cases like: 1225 // Produces nicer output in cases like:
1101 // 1226 //
1102 // someJson['property']['property']['property']['property']... 1227 // someJson['property']['property']['property']['property']...
1103 soloZeroSplit(); 1228 soloZeroSplit();
1104 } 1229 }
1105 1230
1106 builder.startSpan(); 1231 builder.startSpan(Cost.index);
1107 token(node.leftBracket); 1232 token(node.leftBracket);
1108 soloZeroSplit(); 1233 soloZeroSplit();
1109 visit(node.index); 1234 visit(node.index);
1110 token(node.rightBracket); 1235 token(node.rightBracket);
1111 builder.endSpan(); 1236 builder.endSpan();
1112 } 1237 }
1113 1238
1114 visitInstanceCreationExpression(InstanceCreationExpression node) { 1239 visitInstanceCreationExpression(InstanceCreationExpression node) {
1115 builder.startSpan(); 1240 builder.startSpan();
1116 token(node.keyword); 1241 token(node.keyword);
1117 space(); 1242 space();
1118 builder.startSpan(Cost.constructorName); 1243 builder.startSpan(Cost.constructorName);
1244
1245 // Start the expression nesting for the argument list here, in case this
1246 // is a generic constructor with type arguments. If it is, we need the type
1247 // arguments to be nested too so they get indented past the arguments.
1248 builder.nestExpression();
1119 visit(node.constructorName); 1249 visit(node.constructorName);
1250
1120 builder.endSpan(); 1251 builder.endSpan();
1121 visit(node.argumentList); 1252 visitArgumentList(node.argumentList, nestExpression: false);
1122 builder.endSpan(); 1253 builder.endSpan();
1254
1255 builder.unnest();
1123 } 1256 }
1124 1257
1125 visitIntegerLiteral(IntegerLiteral node) { 1258 visitIntegerLiteral(IntegerLiteral node) {
1126 token(node.literal); 1259 token(node.literal);
1127 } 1260 }
1128 1261
1129 visitInterpolationExpression(InterpolationExpression node) { 1262 visitInterpolationExpression(InterpolationExpression node) {
1130 token(node.leftBracket); 1263 token(node.leftBracket);
1131 visit(node.expression); 1264 visit(node.expression);
1132 token(node.rightBracket); 1265 token(node.rightBracket);
1133 } 1266 }
1134 1267
1135 visitInterpolationString(InterpolationString node) { 1268 visitInterpolationString(InterpolationString node) {
1136 token(node.contents); 1269 token(node.contents);
1137 } 1270 }
1138 1271
1139 visitIsExpression(IsExpression node) { 1272 visitIsExpression(IsExpression node) {
1140 builder.startSpan(); 1273 builder.startSpan();
1274 builder.nestExpression();
1141 visit(node.expression); 1275 visit(node.expression);
1142 soloSplit(); 1276 soloSplit();
1143 token(node.isOperator); 1277 token(node.isOperator);
1144 token(node.notOperator); 1278 token(node.notOperator);
1145 space(); 1279 space();
1146 visit(node.type); 1280 visit(node.type);
1281 builder.unnest();
1147 builder.endSpan(); 1282 builder.endSpan();
1148 } 1283 }
1149 1284
1150 visitLabel(Label node) { 1285 visitLabel(Label node) {
1151 visit(node.label); 1286 visit(node.label);
1152 token(node.colon); 1287 token(node.colon);
1153 } 1288 }
1154 1289
1155 visitLabeledStatement(LabeledStatement node) { 1290 visitLabeledStatement(LabeledStatement node) {
1156 visitNodes(node.labels, between: space, after: space); 1291 _visitLabels(node.labels);
1157 visit(node.statement); 1292 visit(node.statement);
1158 } 1293 }
1159 1294
1160 visitLibraryDirective(LibraryDirective node) { 1295 visitLibraryDirective(LibraryDirective node) {
1161 visitDeclarationMetadata(node.metadata); 1296 visitMetadata(node.metadata);
1162 1297
1163 _simpleStatement(node, () { 1298 _simpleStatement(node, () {
1164 token(node.keyword); 1299 token(node.keyword);
1165 space(); 1300 space();
1166 visit(node.name); 1301 visit(node.name);
1167 }); 1302 });
1168 } 1303 }
1169 1304
1170 visitLibraryIdentifier(LibraryIdentifier node) { 1305 visitLibraryIdentifier(LibraryIdentifier node) {
1171 visit(node.components.first); 1306 visit(node.components.first);
(...skipping 30 matching lines...) Expand all
1202 visitMethodInvocation(MethodInvocation node) { 1337 visitMethodInvocation(MethodInvocation node) {
1203 // If there's no target, this is a "bare" function call like "foo(1, 2)", 1338 // If there's no target, this is a "bare" function call like "foo(1, 2)",
1204 // or a section in a cascade. Handle this case specially. 1339 // or a section in a cascade. Handle this case specially.
1205 if (node.target == null) { 1340 if (node.target == null) {
1206 // Try to keep the entire method invocation one line. 1341 // Try to keep the entire method invocation one line.
1207 builder.startSpan(); 1342 builder.startSpan();
1208 builder.nestExpression(); 1343 builder.nestExpression();
1209 1344
1210 // This will be non-null for cascade sections. 1345 // This will be non-null for cascade sections.
1211 token(node.operator); 1346 token(node.operator);
1212 token(node.methodName.token); 1347 visit(node.methodName);
1213 visit(node.argumentList); 1348
1349 // TODO(rnystrom): Currently, there are no constraints between a generic
1350 // method's type arguments and arguments. That can lead to some funny
1351 // splitting like:
1352 //
1353 // method<VeryLongType,
1354 // AnotherTypeArgument>(argument,
1355 // argument, argument, argument);
1356 //
1357 // The indentation is fine, but splitting in the middle of each argument
1358 // list looks kind of strange. If this ends up happening in real world
1359 // code, consider putting a constraint between them.
1360 visit(node.typeArguments);
1361 visitArgumentList(node.argumentList, nestExpression: false);
1214 1362
1215 builder.unnest(); 1363 builder.unnest();
1216 builder.endSpan(); 1364 builder.endSpan();
1217 return; 1365 return;
1218 } 1366 }
1219 1367
1220 new CallChainVisitor(this, node).visit(); 1368 new CallChainVisitor(this, node).visit();
1221 } 1369 }
1222 1370
1223 visitNamedExpression(NamedExpression node) { 1371 visitNamedExpression(NamedExpression node) {
1224 builder.nestExpression(); 1372 visitNamedArgument(node);
1225 builder.startSpan();
1226 visit(node.name);
1227
1228 // Don't allow a split between a name and a collection. Instead, we want
1229 // the collection itself to split, or to split before the argument.
1230 if (node.expression is ListLiteral || node.expression is MapLiteral) {
1231 space();
1232 } else {
1233 soloSplit();
1234 }
1235
1236 visit(node.expression);
1237 builder.endSpan();
1238 builder.unnest();
1239 } 1373 }
1240 1374
1241 visitNativeClause(NativeClause node) { 1375 visitNativeClause(NativeClause node) {
1242 token(node.nativeKeyword); 1376 token(node.nativeKeyword);
1243 space(); 1377 space();
1244 visit(node.name); 1378 visit(node.name);
1245 } 1379 }
1246 1380
1247 visitNativeFunctionBody(NativeFunctionBody node) { 1381 visitNativeFunctionBody(NativeFunctionBody node) {
1248 _simpleStatement(node, () { 1382 _simpleStatement(node, () {
(...skipping 12 matching lines...) Expand all
1261 1395
1262 visitParenthesizedExpression(ParenthesizedExpression node) { 1396 visitParenthesizedExpression(ParenthesizedExpression node) {
1263 builder.nestExpression(); 1397 builder.nestExpression();
1264 token(node.leftParenthesis); 1398 token(node.leftParenthesis);
1265 visit(node.expression); 1399 visit(node.expression);
1266 builder.unnest(); 1400 builder.unnest();
1267 token(node.rightParenthesis); 1401 token(node.rightParenthesis);
1268 } 1402 }
1269 1403
1270 visitPartDirective(PartDirective node) { 1404 visitPartDirective(PartDirective node) {
1271 visitDeclarationMetadata(node.metadata); 1405 visitMetadata(node.metadata);
1272 1406
1273 _simpleStatement(node, () { 1407 _simpleStatement(node, () {
1274 token(node.keyword); 1408 token(node.keyword);
1275 space(); 1409 space();
1276 visit(node.uri); 1410 visit(node.uri);
1277 }); 1411 });
1278 } 1412 }
1279 1413
1280 visitPartOfDirective(PartOfDirective node) { 1414 visitPartOfDirective(PartOfDirective node) {
1281 visitDeclarationMetadata(node.metadata); 1415 visitMetadata(node.metadata);
1282 1416
1283 _simpleStatement(node, () { 1417 _simpleStatement(node, () {
1284 token(node.keyword); 1418 token(node.keyword);
1285 space(); 1419 space();
1286 token(node.ofKeyword); 1420 token(node.ofKeyword);
1287 space(); 1421 space();
1288 visit(node.libraryName); 1422 visit(node.libraryName);
1289 }); 1423 });
1290 } 1424 }
1291 1425
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1342 visit(node.expression, before: space); 1476 visit(node.expression, before: space);
1343 }); 1477 });
1344 } 1478 }
1345 1479
1346 visitScriptTag(ScriptTag node) { 1480 visitScriptTag(ScriptTag node) {
1347 // The lexeme includes the trailing newline. Strip it off since the 1481 // The lexeme includes the trailing newline. Strip it off since the
1348 // formatter ensures it gets a newline after it. Since the script tag must 1482 // formatter ensures it gets a newline after it. Since the script tag must
1349 // come at the top of the file, we don't have to worry about preceding 1483 // come at the top of the file, we don't have to worry about preceding
1350 // comments or whitespace. 1484 // comments or whitespace.
1351 _writeText(node.scriptTag.lexeme.trim(), node.offset); 1485 _writeText(node.scriptTag.lexeme.trim(), node.offset);
1352 1486 newline();
1353 oneOrTwoNewlines();
1354 } 1487 }
1355 1488
1356 visitShowCombinator(ShowCombinator node) { 1489 visitShowCombinator(ShowCombinator node) {
1357 _visitCombinator(node.keyword, node.shownNames); 1490 _visitCombinator(node.keyword, node.shownNames);
1358 } 1491 }
1359 1492
1360 visitSimpleFormalParameter(SimpleFormalParameter node) { 1493 visitSimpleFormalParameter(SimpleFormalParameter node) {
1361 visitParameterMetadata(node.metadata, () { 1494 visitParameterMetadata(node.metadata, () {
1495 modifier(node.covariantKeyword);
1362 modifier(node.keyword); 1496 modifier(node.keyword);
1363 visit(node.type, after: space); 1497 visit(node.type, after: space);
1364 visit(node.identifier); 1498 visit(node.identifier);
1365 }); 1499 });
1366 } 1500 }
1367 1501
1368 visitSimpleIdentifier(SimpleIdentifier node) { 1502 visitSimpleIdentifier(SimpleIdentifier node) {
1369 token(node.token); 1503 token(node.token);
1370 } 1504 }
1371 1505
(...skipping 27 matching lines...) Expand all
1399 visit(node.argumentList); 1533 visit(node.argumentList);
1400 1534
1401 builder.endSpan(); 1535 builder.endSpan();
1402 } 1536 }
1403 1537
1404 visitSuperExpression(SuperExpression node) { 1538 visitSuperExpression(SuperExpression node) {
1405 token(node.superKeyword); 1539 token(node.superKeyword);
1406 } 1540 }
1407 1541
1408 visitSwitchCase(SwitchCase node) { 1542 visitSwitchCase(SwitchCase node) {
1409 visitNodes(node.labels, between: space, after: space); 1543 _visitLabels(node.labels);
1410 token(node.keyword); 1544 token(node.keyword);
1411 space(); 1545 space();
1412 visit(node.expression); 1546 visit(node.expression);
1413 token(node.colon); 1547 token(node.colon);
1414 1548
1415 builder.indent(); 1549 builder.indent();
1416 // TODO(rnystrom): Allow inline cases? 1550 // TODO(rnystrom): Allow inline cases?
1417 newline(); 1551 newline();
1418 1552
1419 visitNodes(node.statements, between: oneOrTwoNewlines); 1553 visitNodes(node.statements, between: oneOrTwoNewlines);
1420 builder.unindent(); 1554 builder.unindent();
1421 } 1555 }
1422 1556
1423 visitSwitchDefault(SwitchDefault node) { 1557 visitSwitchDefault(SwitchDefault node) {
1424 visitNodes(node.labels, between: space, after: space); 1558 _visitLabels(node.labels);
1425 token(node.keyword); 1559 token(node.keyword);
1426 token(node.colon); 1560 token(node.colon);
1427 1561
1428 builder.indent(); 1562 builder.indent();
1429 // TODO(rnystrom): Allow inline cases? 1563 // TODO(rnystrom): Allow inline cases?
1430 newline(); 1564 newline();
1431 1565
1432 visitNodes(node.statements, between: oneOrTwoNewlines); 1566 visitNodes(node.statements, between: oneOrTwoNewlines);
1433 builder.unindent(); 1567 builder.unindent();
1434 } 1568 }
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
1470 token(node.thisKeyword); 1604 token(node.thisKeyword);
1471 } 1605 }
1472 1606
1473 visitThrowExpression(ThrowExpression node) { 1607 visitThrowExpression(ThrowExpression node) {
1474 token(node.throwKeyword); 1608 token(node.throwKeyword);
1475 space(); 1609 space();
1476 visit(node.expression); 1610 visit(node.expression);
1477 } 1611 }
1478 1612
1479 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { 1613 visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
1480 visitDeclarationMetadata(node.metadata); 1614 visitMetadata(node.metadata);
1481 1615
1482 _simpleStatement(node, () { 1616 _simpleStatement(node, () {
1483 visit(node.variables); 1617 visit(node.variables);
1484 }); 1618 });
1485 } 1619 }
1486 1620
1487 visitTryStatement(TryStatement node) { 1621 visitTryStatement(TryStatement node) {
1488 token(node.tryKeyword); 1622 token(node.tryKeyword);
1489 space(); 1623 space();
1490 visit(node.body); 1624 visit(node.body);
(...skipping 24 matching lines...) Expand all
1515 1649
1516 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); 1650 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters);
1517 1651
1518 _metadataRules.removeLast(); 1652 _metadataRules.removeLast();
1519 } 1653 }
1520 1654
1521 visitVariableDeclaration(VariableDeclaration node) { 1655 visitVariableDeclaration(VariableDeclaration node) {
1522 visit(node.name); 1656 visit(node.name);
1523 if (node.initializer == null) return; 1657 if (node.initializer == null) return;
1524 1658
1525 _visitAssignment(node.equals, node.initializer); 1659 // If there are multiple variables being declared, we want to nest the
1660 // initializers farther so they don't line up with the variables. Bad:
1661 //
1662 // var a =
1663 // aValue,
1664 // b =
1665 // bValue;
1666 //
1667 // Good:
1668 //
1669 // var a =
1670 // aValue,
1671 // b =
1672 // bValue;
1673 var hasMultipleVariables =
1674 (node.parent as VariableDeclarationList).variables.length > 1;
1675
1676 _visitAssignment(node.equals, node.initializer, nest: hasMultipleVariables);
1526 } 1677 }
1527 1678
1528 visitVariableDeclarationList(VariableDeclarationList node) { 1679 visitVariableDeclarationList(VariableDeclarationList node) {
1529 visitDeclarationMetadata(node.metadata); 1680 visitMetadata(node.metadata);
1530 1681
1531 // Allow but try to avoid splitting between the type and name. 1682 // Allow but try to avoid splitting between the type and name.
1532 builder.startSpan(); 1683 builder.startSpan();
1533 1684
1534 modifier(node.keyword); 1685 modifier(node.keyword);
1535 visit(node.type, after: soloSplit); 1686 visit(node.type, after: soloSplit);
1536 1687
1537 builder.endSpan(); 1688 builder.endSpan();
1538 1689
1539 // Use a single rule for all of the variables. If there are multiple 1690 // Use a single rule for all of the variables. If there are multiple
(...skipping 12 matching lines...) Expand all
1552 } 1703 }
1553 1704
1554 visitWhileStatement(WhileStatement node) { 1705 visitWhileStatement(WhileStatement node) {
1555 builder.nestExpression(); 1706 builder.nestExpression();
1556 token(node.whileKeyword); 1707 token(node.whileKeyword);
1557 space(); 1708 space();
1558 token(node.leftParenthesis); 1709 token(node.leftParenthesis);
1559 soloZeroSplit(); 1710 soloZeroSplit();
1560 visit(node.condition); 1711 visit(node.condition);
1561 token(node.rightParenthesis); 1712 token(node.rightParenthesis);
1562 builder.unnest(now: false); 1713 builder.unnest();
1563 1714
1564 _visitLoopBody(node.body); 1715 _visitLoopBody(node.body);
1565 } 1716 }
1566 1717
1567 visitWithClause(WithClause node) { 1718 visitWithClause(WithClause node) {
1568 _visitCombinator(node.withKeyword, node.mixinTypes); 1719 _visitCombinator(node.withKeyword, node.mixinTypes);
1569 } 1720 }
1570 1721
1571 visitYieldStatement(YieldStatement node) { 1722 visitYieldStatement(YieldStatement node) {
1572 _simpleStatement(node, () { 1723 _simpleStatement(node, () {
1573 token(node.yieldKeyword); 1724 token(node.yieldKeyword);
1574 token(node.star); 1725 token(node.star);
1575 space(); 1726 space();
1576 visit(node.expression); 1727 visit(node.expression);
1577 }); 1728 });
1578 } 1729 }
1579 1730
1580 /// Visit a [node], and if not null, optionally preceded or followed by the 1731 /// Visit a [node], and if not null, optionally preceded or followed by the
1581 /// specified functions. 1732 /// specified functions.
1582 void visit(AstNode node, {void before(), void after()}) { 1733 void visit(AstNode node, {void before(), void after()}) {
1583 if (node == null) return; 1734 if (node == null) return;
1584 1735
1585 if (before != null) before(); 1736 if (before != null) before();
1586 1737
1587 node.accept(this); 1738 node.accept(this);
1588 1739
1589 if (after != null) after(); 1740 if (after != null) after();
1590 } 1741 }
1591 1742
1592 /// Visit metadata annotations on directives and declarations. 1743 /// Visit metadata annotations on directives, declarations, and members.
1593 /// 1744 ///
1594 /// These always force the annotations to be on the previous line. 1745 /// These always force the annotations to be on the previous line.
1595 void visitDeclarationMetadata(NodeList<Annotation> metadata) { 1746 void visitMetadata(NodeList<Annotation> metadata) {
1596 // If there are multiple annotations, they are always on their own lines, 1747 visitNodes(metadata, between: newline, after: newline);
1597 // even the last.
1598 if (metadata.length > 1) {
1599 visitNodes(metadata, between: newline, after: newline);
1600 } else {
1601 visitNodes(metadata, between: space, after: newline);
1602 }
1603 }
1604
1605 /// Visit metadata annotations on members.
1606 ///
1607 /// These may be on the same line as the member, or on the previous.
1608 void visitMemberMetadata(NodeList<Annotation> metadata) {
1609 // If there are multiple annotations, they are always on their own lines,
1610 // even the last.
1611 if (metadata.length > 1) {
1612 visitNodes(metadata, between: newline, after: newline);
1613 } else {
1614 visitNodes(metadata, between: space, after: spaceOrNewline);
1615 }
1616 } 1748 }
1617 1749
1618 /// Visits metadata annotations on parameters and type parameters. 1750 /// Visits metadata annotations on parameters and type parameters.
1619 /// 1751 ///
1620 /// These are always on the same line as the parameter. 1752 /// Unlike other annotations, these are allowed to stay on the same line as
1753 /// the parameter.
1621 void visitParameterMetadata( 1754 void visitParameterMetadata(
1622 NodeList<Annotation> metadata, void visitParameter()) { 1755 NodeList<Annotation> metadata, void visitParameter()) {
1623 if (metadata == null || metadata.isEmpty) { 1756 if (metadata == null || metadata.isEmpty) {
1624 visitParameter(); 1757 visitParameter();
1625 return; 1758 return;
1626 } 1759 }
1627 1760
1628 // Split before all of the annotations or none. 1761 // Split before all of the annotations or none.
1629 builder.startLazyRule(_metadataRules.last); 1762 builder.startLazyRule(_metadataRules.last);
1630 1763
(...skipping 10 matching lines...) Expand all
1641 }); 1774 });
1642 visitParameter(); 1775 visitParameter();
1643 1776
1644 builder.unnest(); 1777 builder.unnest();
1645 1778
1646 // Wrap the rule around the parameter too. If it splits, we want to force 1779 // Wrap the rule around the parameter too. If it splits, we want to force
1647 // the annotations to split as well. 1780 // the annotations to split as well.
1648 builder.endRule(); 1781 builder.endRule();
1649 } 1782 }
1650 1783
1784 /// Visits [node], which may be in an argument list controlled by [rule].
1785 ///
1786 /// This is called directly by [ArgumentListVisitor] so that it can pass in
1787 /// the surrounding named argument rule. That way, this can ensure that a
1788 /// split between the name and argument forces the argument list to split
1789 /// too.
1790 void visitNamedArgument(NamedExpression node, [NamedRule rule]) {
1791 builder.nestExpression();
1792 builder.startSpan();
1793 visit(node.name);
1794
1795 // Don't allow a split between a name and a collection. Instead, we want
1796 // the collection itself to split, or to split before the argument.
1797 if (node.expression is ListLiteral || node.expression is MapLiteral) {
1798 space();
1799 } else {
1800 var split = soloSplit();
1801 if (rule != null) split.imply(rule);
1802 }
1803
1804 visit(node.expression);
1805 builder.endSpan();
1806 builder.unnest();
1807 }
1808
1651 /// Visits the `=` and the following expression in any place where an `=` 1809 /// Visits the `=` and the following expression in any place where an `=`
1652 /// appears: 1810 /// appears:
1653 /// 1811 ///
1654 /// * Assignment 1812 /// * Assignment
1655 /// * Variable declaration 1813 /// * Variable declaration
1656 /// * Constructor initialization 1814 /// * Constructor initialization
1657 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { 1815 ///
1816 /// If [nest] is true, an extra level of expression nesting is added after
1817 /// the "=".
1818 void _visitAssignment(Token equalsOperator, Expression rightHandSide,
1819 {bool nest: false}) {
1658 space(); 1820 space();
1659 token(equalsOperator); 1821 token(equalsOperator);
1822
1823 if (nest) builder.nestExpression(now: true);
1824
1660 soloSplit(_assignmentCost(rightHandSide)); 1825 soloSplit(_assignmentCost(rightHandSide));
1661 builder.startSpan(); 1826 builder.startSpan();
1662 visit(rightHandSide); 1827 visit(rightHandSide);
1663 builder.endSpan(); 1828 builder.endSpan();
1829
1830 if (nest) builder.unnest();
1664 } 1831 }
1665 1832
1666 /// Visits a type parameter or type argument list. 1833 /// Visits a type parameter or type argument list.
1667 void _visitGenericList( 1834 void _visitGenericList(
1668 Token leftBracket, Token rightBracket, List<AstNode> nodes) { 1835 Token leftBracket, Token rightBracket, List<AstNode> nodes) {
1669 var rule = new TypeArgumentRule(); 1836 var rule = new TypeArgumentRule();
1670 builder.startRule(rule); 1837 builder.startRule(rule);
1671 builder.startSpan(); 1838 builder.startSpan();
1672 builder.nestExpression(); 1839 builder.nestExpression();
1673 1840
(...skipping 10 matching lines...) Expand all
1684 } 1851 }
1685 } 1852 }
1686 1853
1687 token(rightBracket); 1854 token(rightBracket);
1688 1855
1689 builder.unnest(); 1856 builder.unnest();
1690 builder.endSpan(); 1857 builder.endSpan();
1691 builder.endRule(); 1858 builder.endRule();
1692 } 1859 }
1693 1860
1861 /// Visits a sequence of labels before a statement or switch case.
1862 void _visitLabels(NodeList<Label> labels) {
1863 visitNodes(labels, between: newline, after: newline);
1864 }
1865
1694 /// Visits a top-level function or method declaration. 1866 /// Visits a top-level function or method declaration.
1695 /// 1867 ///
1696 /// The two AST node types are very similar but, alas, share no common 1868 /// The two AST node types are very similar but, alas, share no common
1697 /// interface type in analyzer, hence the dynamic typing. 1869 /// interface type in analyzer, hence the dynamic typing.
1698 void _visitMemberDeclaration( 1870 void _visitMemberDeclaration(
1699 /* FunctionDeclaration|MethodDeclaration */ node, 1871 /* FunctionDeclaration|MethodDeclaration */ node,
1700 /* FunctionExpression|MethodDeclaration */ function) { 1872 /* FunctionExpression|MethodDeclaration */ function) {
1701 visitMemberMetadata(node.metadata); 1873 visitMetadata(node.metadata as NodeList<Annotation>);
1702 1874
1703 // Nest the signature in case we have to split between the return type and 1875 // Nest the signature in case we have to split between the return type and
1704 // name. 1876 // name.
1705 builder.nestExpression(); 1877 builder.nestExpression();
1706 builder.startSpan(); 1878 builder.startSpan();
1707 modifier(node.externalKeyword); 1879 modifier(node.externalKeyword);
1708 if (node is MethodDeclaration) modifier(node.modifierKeyword); 1880 if (node is MethodDeclaration) modifier(node.modifierKeyword);
1709 visit(node.returnType, after: soloSplit); 1881 visit(node.returnType, after: soloSplit);
1710 modifier(node.propertyKeyword); 1882 modifier(node.propertyKeyword);
1711 if (node is MethodDeclaration) modifier(node.operatorKeyword); 1883 if (node is MethodDeclaration) modifier(node.operatorKeyword);
1712 visit(node.name); 1884 visit(node.name);
1713 builder.endSpan(); 1885 builder.endSpan();
1714 1886
1715 // If the body is a block, we need to exit any nesting first. If it's an 1887 TypeParameterList typeParameters;
1716 // expression, we want to wrap the nesting around that so that the body 1888 if (node is FunctionDeclaration) {
1717 // gets nested farther. 1889 typeParameters = node.functionExpression.typeParameters;
1718 if (function.body is! ExpressionFunctionBody) builder.unnest(); 1890 } else {
1891 typeParameters = (node as MethodDeclaration).typeParameters;
1892 }
1719 1893
1720 _visitBody(function.parameters, function.body); 1894 _visitBody(typeParameters, function.parameters, function.body, () {
1895 // If the body is a block, we need to exit nesting before we hit the body
1896 // indentation, but we do want to wrap it around the parameters.
1897 if (function.body is! ExpressionFunctionBody) builder.unnest();
1898 });
1721 1899
1900 // If it's an expression, we want to wrap the nesting around that so that
1901 // the body gets nested farther.
1722 if (function.body is ExpressionFunctionBody) builder.unnest(); 1902 if (function.body is ExpressionFunctionBody) builder.unnest();
1723 } 1903 }
1724 1904
1725 /// Visit the given function [parameters] followed by its [body], printing a 1905 /// Visit the given function [parameters] followed by its [body], printing a
1726 /// space before it if it's not empty. 1906 /// space before it if it's not empty.
1727 /// 1907 ///
1728 /// If [afterParameters] is provided, it is invoked between the parameters 1908 /// If [beforeBody] is provided, it is invoked before the body is visited.
1729 /// and body. (It's used for constructor initialization lists.) 1909 void _visitBody(TypeParameterList typeParameters,
1730 void _visitBody(FormalParameterList parameters, FunctionBody body, 1910 FormalParameterList parameters, FunctionBody body,
1731 [afterParameters()]) { 1911 [beforeBody()]) {
1732 // If the body is "=>", add an extra level of indentation around the 1912 // If the body is "=>", add an extra level of indentation around the
1733 // parameters and a rule that spans the parameters and the "=>". This 1913 // parameters and a rule that spans the parameters and the "=>". This
1734 // ensures that if the parameters wrap, they wrap more deeply than the "=>" 1914 // ensures that if the parameters wrap, they wrap more deeply than the "=>"
1735 // does, as in: 1915 // does, as in:
1736 // 1916 //
1737 // someFunction(parameter, 1917 // someFunction(parameter,
1738 // parameter, parameter) => 1918 // parameter, parameter) =>
1739 // "the body"; 1919 // "the body";
1740 // 1920 //
1741 // Also, it ensures that if the parameters wrap, we split at the "=>" too 1921 // Also, it ensures that if the parameters wrap, we split at the "=>" too
(...skipping 10 matching lines...) Expand all
1752 // parameter) => 1932 // parameter) =>
1753 // function( 1933 // function(
1754 // argument); 1934 // argument);
1755 if (body is ExpressionFunctionBody) { 1935 if (body is ExpressionFunctionBody) {
1756 builder.nestExpression(); 1936 builder.nestExpression();
1757 1937
1758 // This rule is ended by visitExpressionFunctionBody(). 1938 // This rule is ended by visitExpressionFunctionBody().
1759 builder.startLazyRule(new Rule(Cost.arrow)); 1939 builder.startLazyRule(new Rule(Cost.arrow));
1760 } 1940 }
1761 1941
1942 // Start the nesting for the parameters here, so they wrap around the
1943 // type parameters too, if any.
1944 builder.nestExpression();
1945
1946 visit(typeParameters);
1762 if (parameters != null) { 1947 if (parameters != null) {
1763 builder.nestExpression(); 1948 visitFormalParameterList(parameters, nestExpression: false);
1764 visit(parameters);
1765 builder.unnest();
1766
1767 if (afterParameters != null) afterParameters();
1768 } 1949 }
1769 1950
1951 builder.unnest();
1952
1953 if (beforeBody != null) beforeBody();
1770 visit(body); 1954 visit(body);
1771 1955
1772 if (body is ExpressionFunctionBody) builder.unnest(); 1956 if (body is ExpressionFunctionBody) builder.unnest();
1773 } 1957 }
1774 1958
1775 /// Visits the body statement of a `for` or `for in` loop. 1959 /// Visits the body statement of a `for`, `for in`, or `while` loop.
1776 void _visitLoopBody(Statement body) { 1960 void _visitLoopBody(Statement body) {
1777 if (body is EmptyStatement) { 1961 if (body is EmptyStatement) {
1778 // No space before the ";". 1962 // No space before the ";".
1779 visit(body); 1963 visit(body);
1780 } else if (body is Block) { 1964 } else if (body is Block) {
1781 space(); 1965 space();
1782 visit(body); 1966 visit(body);
1783 } else { 1967 } else {
1784 // Allow splitting in an expression-bodied for even though it's against 1968 // Allow splitting in a statement-bodied loop even though it's against
1785 // the style guide. Since we can't fix the code itself to follow the 1969 // the style guide. Since we can't fix the code itself to follow the
1786 // style guide, we should at least format it as well as we can. 1970 // style guide, we should at least format it as well as we can.
1787 builder.nestExpression(indent: 2, now: true); 1971 builder.indent();
1788 builder.startRule(); 1972 builder.startRule();
1789 1973
1790 split(); 1974 builder.split(nest: false, space: true);
1791 visit(body); 1975 visit(body);
1792 1976
1793 builder.endRule(); 1977 builder.endRule();
1794 builder.unnest(); 1978 builder.unindent();
1795 } 1979 }
1796 } 1980 }
1797 1981
1798 /// Visit a list of [nodes] if not null, optionally separated and/or preceded 1982 /// Visit a list of [nodes] if not null, optionally separated and/or preceded
1799 /// and followed by the given functions. 1983 /// and followed by the given functions.
1800 void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) { 1984 void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) {
1801 if (nodes == null || nodes.isEmpty) return; 1985 if (nodes == null || nodes.isEmpty) return;
1802 1986
1803 if (before != null) before(); 1987 if (before != null) before();
1804 1988
(...skipping 19 matching lines...) Expand all
1824 2008
1825 visit(node); 2009 visit(node);
1826 2010
1827 // The comma after the node. 2011 // The comma after the node.
1828 if (node.endToken.next.lexeme == ",") token(node.endToken.next); 2012 if (node.endToken.next.lexeme == ",") token(node.endToken.next);
1829 } 2013 }
1830 } 2014 }
1831 2015
1832 /// Visits the collection literal [node] whose body starts with [leftBracket], 2016 /// Visits the collection literal [node] whose body starts with [leftBracket],
1833 /// ends with [rightBracket] and contains [elements]. 2017 /// ends with [rightBracket] and contains [elements].
2018 ///
2019 /// This is also used for argument lists with a trailing comma which are
2020 /// considered "collection-like". In that case, [node] is `null`.
1834 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, 2021 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket,
1835 Iterable<AstNode> elements, Token rightBracket, 2022 Iterable<AstNode> elements, Token rightBracket,
1836 [int cost]) { 2023 [int cost]) {
1837 modifier(node.constKeyword); 2024 if (node != null) {
1838 visit(node.typeArguments); 2025 modifier(node.constKeyword);
2026 visit(node.typeArguments);
2027 }
1839 2028
1840 // Don't allow splitting in an empty collection. 2029 // Don't allow splitting in an empty collection.
1841 if (elements.isEmpty && rightBracket.precedingComments == null) { 2030 if (elements.isEmpty && rightBracket.precedingComments == null) {
1842 token(leftBracket); 2031 token(leftBracket);
1843 token(rightBracket); 2032 token(rightBracket);
1844 return; 2033 return;
1845 } 2034 }
1846 2035
1847 // Force all of the surrounding collections to split. 2036 // Force all of the surrounding collections to split.
1848 for (var i = 0; i < _collectionSplits.length; i++) { 2037 for (var i = 0; i < _collectionSplits.length; i++) {
1849 _collectionSplits[i] = true; 2038 _collectionSplits[i] = true;
1850 } 2039 }
1851 2040
1852 // Add this collection to the stack. 2041 // Add this collection to the stack.
1853 _collectionSplits.add(false); 2042 _collectionSplits.add(false);
1854 2043
1855 _startLiteralBody(leftBracket); 2044 _startLiteralBody(leftBracket);
1856 2045
1857 // Always use a hard rule to split the elements. The parent chunk of
1858 // the collection will handle the unsplit case, so this only comes
1859 // into play when the collection is split.
1860 var rule = new Rule.hard();
1861 builder.startRule(rule);
1862
1863 // If a collection contains a line comment, we assume it's a big complex 2046 // If a collection contains a line comment, we assume it's a big complex
1864 // blob of data with some documented structure. In that case, the user 2047 // blob of data with some documented structure. In that case, the user
1865 // probably broke the elements into lines deliberately, so preserve those. 2048 // probably broke the elements into lines deliberately, so preserve those.
1866 var preserveNewlines = _containsLineComments(elements, rightBracket); 2049 var preserveNewlines = _containsLineComments(elements, rightBracket);
1867 2050
2051 var rule;
2052 var lineRule;
2053 if (preserveNewlines) {
2054 // Newlines are significant, so we'll explicitly write those. Elements
2055 // on the same line all share an argument-list-like rule that allows
2056 // splitting between zero, one, or all of them. This is faster in long
2057 // lists than using individual splits after each element.
2058 lineRule = new TypeArgumentRule();
2059 builder.startLazyRule(lineRule);
2060 } else {
2061 // Newlines aren't significant, so use a hard rule to split the elements.
2062 // The parent chunk of the collection will handle the unsplit case, so
2063 // this only comes into play when the collection is split.
2064 rule = new Rule.hard();
2065 builder.startRule(rule);
2066 }
2067
1868 for (var element in elements) { 2068 for (var element in elements) {
1869 if (element != elements.first) { 2069 if (element != elements.first) {
1870 if (preserveNewlines) { 2070 if (preserveNewlines) {
2071 // See if the next element is on the next line.
1871 if (_endLine(element.beginToken.previous) != 2072 if (_endLine(element.beginToken.previous) !=
1872 _startLine(element.beginToken)) { 2073 _startLine(element.beginToken)) {
1873 oneOrTwoNewlines(); 2074 oneOrTwoNewlines();
2075
2076 // Start a new rule for the new line.
2077 builder.endRule();
2078 lineRule = new TypeArgumentRule();
2079 builder.startLazyRule(lineRule);
1874 } else { 2080 } else {
1875 soloSplit(); 2081 lineRule.beforeArgument(split());
1876 } 2082 }
1877 } else { 2083 } else {
1878 builder.split(nest: false, space: true); 2084 builder.split(nest: false, space: true);
1879 } 2085 }
1880 } 2086 }
1881 2087
1882 builder.nestExpression(); 2088 builder.nestExpression();
1883 visit(element); 2089 visit(element);
1884 2090
1885 // The comma after the element. 2091 // The comma after the element.
1886 if (element.endToken.next.lexeme == ",") token(element.endToken.next); 2092 if (element.endToken.next.type == TokenType.COMMA) {
2093 token(element.endToken.next);
2094 }
1887 2095
1888 builder.unnest(); 2096 builder.unnest();
1889 } 2097 }
1890 2098
1891 builder.endRule(); 2099 builder.endRule();
1892 2100
1893 // If there is a collection inside this one, it forces this one to split. 2101 // If there is a collection inside this one, it forces this one to split.
1894 var force = _collectionSplits.removeLast(); 2102 var force = _collectionSplits.removeLast();
1895 2103
2104 // If the collection has a trailing comma, the user must want it to split.
2105 if (elements.isNotEmpty &&
2106 elements.last.endToken.next.type == TokenType.COMMA) {
2107 force = true;
2108 }
2109
1896 _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force); 2110 _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force);
1897 } 2111 }
1898 2112
2113 /// Writes [parameters], which is assumed to have a trailing comma after the
2114 /// last parameter.
2115 ///
2116 /// Parameter lists with trailing commas are formatted differently from
2117 /// regular parameter lists. They are treated more like collection literals.
2118 ///
2119 /// We don't reuse [_visitCollectionLiteral] here because there are enough
2120 /// weird differences around optional parameters that it's easiest just to
2121 /// give them their own method.
2122 void _visitTrailingCommaParameterList(FormalParameterList parameters) {
2123 // Can't have a trailing comma if there are no parameters.
2124 assert(parameters.parameters.isNotEmpty);
2125
2126 _metadataRules.add(new MetadataRule());
2127
2128 // Always split the parameters.
2129 builder.startRule(new Rule.hard());
2130
2131 token(parameters.leftParenthesis);
2132
2133 // Find the parameter immediately preceding the optional parameters (if
2134 // there are any).
2135 FormalParameter lastRequired;
2136 for (var i = 0; i < parameters.parameters.length; i++) {
2137 if (parameters.parameters[i] is DefaultFormalParameter) {
2138 if (i > 0) lastRequired = parameters.parameters[i - 1];
2139 break;
2140 }
2141 }
2142
2143 // If all parameters are optional, put the "[" or "{" right after "(".
2144 if (parameters.parameters.first is DefaultFormalParameter) {
2145 token(parameters.leftDelimiter);
2146 }
2147
2148 // Process the parameters as a separate set of chunks.
2149 builder = builder.startBlock(null);
2150
2151 for (var parameter in parameters.parameters) {
2152 visit(parameter);
2153
2154 // The comma after the parameter.
2155 if (parameter.endToken.next.type == TokenType.COMMA) {
2156 token(parameter.endToken.next);
2157 }
2158
2159 // If the optional parameters start after this one, put the delimiter
2160 // at the end of its line.
2161 if (parameter == lastRequired) {
2162 space();
2163 token(parameters.leftDelimiter);
2164 lastRequired = null;
2165 }
2166
2167 newline();
2168 }
2169
2170 // Put comments before the closing ")", "]", or "}" inside the block.
2171 var firstDelimiter =
2172 parameters.rightDelimiter ?? parameters.rightParenthesis;
2173 writePrecedingCommentsAndNewlines(firstDelimiter);
2174 builder = builder.endBlock(null, forceSplit: true);
2175 builder.endRule();
2176
2177 _metadataRules.removeLast();
2178
2179 // Now write the delimiter itself.
2180 _writeText(firstDelimiter.lexeme, firstDelimiter.offset);
2181 if (firstDelimiter != parameters.rightParenthesis) {
2182 token(parameters.rightParenthesis);
2183 }
2184 }
2185
1899 /// Gets the cost to split at an assignment (or `:` in the case of a named 2186 /// Gets the cost to split at an assignment (or `:` in the case of a named
1900 /// default value) with the given [rightHandSide]. 2187 /// default value) with the given [rightHandSide].
1901 /// 2188 ///
1902 /// "Block-like" expressions (collections and cascades) bind a bit tighter 2189 /// "Block-like" expressions (collections and cascades) bind a bit tighter
1903 /// because it looks better to have code like: 2190 /// because it looks better to have code like:
1904 /// 2191 ///
1905 /// var list = [ 2192 /// var list = [
1906 /// element, 2193 /// element,
1907 /// element, 2194 /// element,
1908 /// element 2195 /// element
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
1990 2277
1991 builder = builder.endBlock(ignoredRule, 2278 builder = builder.endBlock(ignoredRule,
1992 forceSplit: hasLeadingNewline || forceSplit); 2279 forceSplit: hasLeadingNewline || forceSplit);
1993 2280
1994 builder.endRule(); 2281 builder.endRule();
1995 2282
1996 // Now write the delimiter itself. 2283 // Now write the delimiter itself.
1997 _writeText(rightBracket.lexeme, rightBracket.offset); 2284 _writeText(rightBracket.lexeme, rightBracket.offset);
1998 } 2285 }
1999 2286
2287 /// Visits a list of configurations in an import or export directive.
2288 void _visitConfigurations(NodeList<Configuration> configurations) {
2289 if (configurations.isEmpty) return;
2290
2291 builder.startRule();
2292
2293 for (var configuration in configurations) {
2294 split();
2295 visit(configuration);
2296 }
2297
2298 builder.endRule();
2299 }
2300
2000 /// Visits a "combinator". 2301 /// Visits a "combinator".
2001 /// 2302 ///
2002 /// This is a [keyword] followed by a list of [nodes], with specific line 2303 /// This is a [keyword] followed by a list of [nodes], with specific line
2003 /// splitting rules. As the name implies, this is used for [HideCombinator] 2304 /// splitting rules. As the name implies, this is used for [HideCombinator]
2004 /// and [ShowCombinator], but it also used for "with" and "implements" 2305 /// and [ShowCombinator], but it also used for "with" and "implements"
2005 /// clauses in class declarations, which are formatted the same way. 2306 /// clauses in class declarations, which are formatted the same way.
2006 /// 2307 ///
2007 /// This assumes the current rule is a [CombinatorRule]. 2308 /// This assumes the current rule is a [CombinatorRule].
2008 void _visitCombinator(Token keyword, Iterable<AstNode> nodes) { 2309 void _visitCombinator(Token keyword, Iterable<AstNode> nodes) {
2009 // Allow splitting before the keyword. 2310 // Allow splitting before the keyword.
(...skipping 25 matching lines...) Expand all
2035 2336
2036 /// Marks the collection literal that starts with [leftBracket] as being 2337 /// Marks the collection literal that starts with [leftBracket] as being
2037 /// controlled by [argumentList]. 2338 /// controlled by [argumentList].
2038 /// 2339 ///
2039 /// When the collection is visited, [argumentList] will determine the 2340 /// When the collection is visited, [argumentList] will determine the
2040 /// indentation and splitting rule for the collection. 2341 /// indentation and splitting rule for the collection.
2041 void beforeCollection(Token leftBracket, ArgumentSublist argumentList) { 2342 void beforeCollection(Token leftBracket, ArgumentSublist argumentList) {
2042 _collectionArgumentLists[leftBracket] = argumentList; 2343 _collectionArgumentLists[leftBracket] = argumentList;
2043 } 2344 }
2044 2345
2045 /// Writes an bracket-delimited body and handles indenting and starting the 2346 /// Writes the beginning of a brace-delimited body and handles indenting and
2046 /// rule used to split the contents. 2347 /// starting the rule used to split the contents.
2047 /// 2348 void _beginBody(Token leftBracket, {bool space: false}) {
2048 /// If [space] is `true`, then the contents and delimiters will have a space
2049 /// between then when unsplit.
2050 void _writeBody(Token leftBracket, Token rightBracket,
2051 {bool space: false, body()}) {
2052 token(leftBracket); 2349 token(leftBracket);
2053 2350
2054 // Indent the body. 2351 // Indent the body.
2055 builder.indent(); 2352 builder.indent();
2056 2353
2057 // Split after the bracket. 2354 // Split after the bracket.
2058 builder.startRule(); 2355 builder.startRule();
2059 builder.split(isDouble: false, nest: false, space: space); 2356 builder.split(isDouble: false, nest: false, space: space);
2357 }
2060 2358
2061 body(); 2359 /// Finishes the body started by a call to [_beginBody].
2062 2360 void _endBody(Token rightBracket, {bool space: false}) {
2063 token(rightBracket, before: () { 2361 token(rightBracket, before: () {
2064 // Split before the closing bracket character. 2362 // Split before the closing bracket character.
2065 builder.unindent(); 2363 builder.unindent();
2066 builder.split(nest: false, space: space); 2364 builder.split(nest: false, space: space);
2067 }); 2365 });
2068 2366
2069 builder.endRule(); 2367 builder.endRule();
2070 } 2368 }
2071 2369
2072 /// Returns `true` if [node] is immediately contained within an anonymous 2370 /// Returns `true` if [node] is immediately contained within an anonymous
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
2108 /// Emit a single mandatory newline. 2406 /// Emit a single mandatory newline.
2109 void newline() { 2407 void newline() {
2110 builder.writeWhitespace(Whitespace.newline); 2408 builder.writeWhitespace(Whitespace.newline);
2111 } 2409 }
2112 2410
2113 /// Emit a two mandatory newlines. 2411 /// Emit a two mandatory newlines.
2114 void twoNewlines() { 2412 void twoNewlines() {
2115 builder.writeWhitespace(Whitespace.twoNewlines); 2413 builder.writeWhitespace(Whitespace.twoNewlines);
2116 } 2414 }
2117 2415
2118 /// Allow either a single space or newline to be emitted before the next
2119 /// non-whitespace token based on whether a newline exists in the source
2120 /// between the last token and the next one.
2121 void spaceOrNewline() {
2122 builder.writeWhitespace(Whitespace.spaceOrNewline);
2123 }
2124
2125 /// Allow either a single split or newline to be emitted before the next 2416 /// Allow either a single split or newline to be emitted before the next
2126 /// non-whitespace token based on whether a newline exists in the source 2417 /// non-whitespace token based on whether a newline exists in the source
2127 /// between the last token and the next one. 2418 /// between the last token and the next one.
2128 void splitOrNewline() { 2419 void splitOrNewline() {
2129 builder.writeWhitespace(Whitespace.splitOrNewline); 2420 builder.writeWhitespace(Whitespace.splitOrNewline);
2130 } 2421 }
2131 2422
2132 /// Allow either one or two newlines to be emitted before the next 2423 /// Allow either one or two newlines to be emitted before the next
2133 /// non-whitespace token based on whether more than one newline exists in the 2424 /// non-whitespace token based on whether more than one newline exists in the
2134 /// source between the last token and the next one. 2425 /// source between the last token and the next one.
2135 void oneOrTwoNewlines() { 2426 void oneOrTwoNewlines() {
2136 builder.writeWhitespace(Whitespace.oneOrTwoNewlines); 2427 builder.writeWhitespace(Whitespace.oneOrTwoNewlines);
2137 } 2428 }
2138 2429
2139 /// Writes a single space split owned by the current rule. 2430 /// Writes a single space split owned by the current rule.
2140 /// 2431 ///
2141 /// Returns the chunk the split was applied to. 2432 /// Returns the chunk the split was applied to.
2142 Chunk split() => builder.split(space: true); 2433 Chunk split() => builder.split(space: true);
2143 2434
2144 /// Writes a zero-space split owned by the current rule. 2435 /// Writes a zero-space split owned by the current rule.
2145 /// 2436 ///
2146 /// Returns the chunk the split was applied to. 2437 /// Returns the chunk the split was applied to.
2147 Chunk zeroSplit() => builder.split(); 2438 Chunk zeroSplit() => builder.split();
2148 2439
2149 /// Writes a single space split with its own rule. 2440 /// Writes a single space split with its own rule.
2150 void soloSplit([int cost]) { 2441 Rule soloSplit([int cost]) {
2151 builder.startRule(new Rule(cost)); 2442 var rule = new Rule(cost);
2443 builder.startRule(rule);
2152 split(); 2444 split();
2153 builder.endRule(); 2445 builder.endRule();
2446 return rule;
2154 } 2447 }
2155 2448
2156 /// Writes a zero-space split with its own rule. 2449 /// Writes a zero-space split with its own rule.
2157 void soloZeroSplit() { 2450 void soloZeroSplit() {
2158 builder.startRule(); 2451 builder.startRule();
2159 builder.split(); 2452 builder.split();
2160 builder.endRule(); 2453 builder.endRule();
2161 } 2454 }
2162 2455
2163 /// Emit [token], along with any comments and formatted whitespace that comes 2456 /// Emit [token], along with any comments and formatted whitespace that comes
(...skipping 22 matching lines...) Expand all
2186 // actually needed. 2479 // actually needed.
2187 if (comment == null) { 2480 if (comment == null) {
2188 if (builder.needsToPreserveNewlines) { 2481 if (builder.needsToPreserveNewlines) {
2189 builder.preserveNewlines(_startLine(token) - _endLine(token.previous)); 2482 builder.preserveNewlines(_startLine(token) - _endLine(token.previous));
2190 } 2483 }
2191 2484
2192 return false; 2485 return false;
2193 } 2486 }
2194 2487
2195 var previousLine = _endLine(token.previous); 2488 var previousLine = _endLine(token.previous);
2196
2197 // Corner case! The analyzer includes the "\n" in the script tag's lexeme,
2198 // which means it appears to be one line later than it is. That causes a
2199 // comment following it to appear to be on the same line. Fix that here by
2200 // correcting the script tag's line.
2201 if (token.previous.type == TokenType.SCRIPT_TAG) previousLine--;
2202
2203 var tokenLine = _startLine(token); 2489 var tokenLine = _startLine(token);
2204 2490
2205 var comments = []; 2491 // Edge case: The analyzer includes the "\n" in the script tag's lexeme,
2492 // which confuses some of these calculations. We don't want to allow a
2493 // blank line between the script tag and a following comment anyway, so
2494 // just override the script tag's line.
2495 if (token.previous.type == TokenType.SCRIPT_TAG) previousLine = tokenLine;
2496
2497 var comments = <SourceComment>[];
2206 while (comment != null) { 2498 while (comment != null) {
2207 var commentLine = _startLine(comment); 2499 var commentLine = _startLine(comment);
2208 2500
2209 // Don't preserve newlines at the top of the file. 2501 // Don't preserve newlines at the top of the file.
2210 if (comment == token.precedingComments && 2502 if (comment == token.precedingComments &&
2211 token.previous.type == TokenType.EOF) { 2503 token.previous.type == TokenType.EOF) {
2212 previousLine = commentLine; 2504 previousLine = commentLine;
2213 } 2505 }
2214 2506
2215 var text = comment.toString().trim(); 2507 var text = comment.toString().trim();
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after
2362 /// Gets the 1-based line number that the beginning of [token] lies on. 2654 /// Gets the 1-based line number that the beginning of [token] lies on.
2363 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; 2655 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber;
2364 2656
2365 /// Gets the 1-based line number that the end of [token] lies on. 2657 /// Gets the 1-based line number that the end of [token] lies on.
2366 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; 2658 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber;
2367 2659
2368 /// Gets the 1-based column number that the beginning of [token] lies on. 2660 /// Gets the 1-based column number that the beginning of [token] lies on.
2369 int _startColumn(Token token) => 2661 int _startColumn(Token token) =>
2370 _lineInfo.getLocation(token.offset).columnNumber; 2662 _lineInfo.getLocation(token.offset).columnNumber;
2371 } 2663 }
OLDNEW
« no previous file with comments | « packages/dart_style/lib/src/rule/rule.dart ('k') | packages/dart_style/lib/src/whitespace.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698