OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart_style.src.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/src/generated/scanner.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/rule.dart'; | 19 import 'rule/rule.dart'; |
19 import 'rule/type_argument.dart'; | 20 import 'rule/type_argument.dart'; |
20 import 'source_code.dart'; | 21 import 'source_code.dart'; |
21 import 'whitespace.dart'; | 22 import 'whitespace.dart'; |
22 | 23 |
23 /// 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 |
24 /// [ChunkBuilder]. | 25 /// [ChunkBuilder]. |
25 class SourceVisitor implements AstVisitor { | 26 class SourceVisitor implements AstVisitor { |
26 /// The builder for the block that is currently being visited. | 27 /// The builder for the block that is currently being visited. |
27 ChunkBuilder builder; | 28 ChunkBuilder builder; |
(...skipping 12 matching lines...) Expand all Loading... |
40 | 41 |
41 /// `true` if the visitor has written past the end of the selection in the | 42 /// `true` if the visitor has written past the end of the selection in the |
42 /// original source text. | 43 /// original source text. |
43 bool _passedSelectionEnd = false; | 44 bool _passedSelectionEnd = false; |
44 | 45 |
45 /// The character offset of the end of the selection, if there is a selection. | 46 /// The character offset of the end of the selection, if there is a selection. |
46 /// | 47 /// |
47 /// This is calculated and cached by [_findSelectionEnd]. | 48 /// This is calculated and cached by [_findSelectionEnd]. |
48 int _selectionEnd; | 49 int _selectionEnd; |
49 | 50 |
50 /// The rule that should be used for the contents of a literal body that are | |
51 /// about to be written. | |
52 /// | |
53 /// This is set by [visitArgumentList] to ensure that all block arguments | |
54 /// share a rule. | |
55 /// | |
56 /// If `null`, a literal body creates its own rule. | |
57 Rule _nextLiteralBodyRule; | |
58 | |
59 /// A stack that tracks forcing nested collections to split. | 51 /// A stack that tracks forcing nested collections to split. |
60 /// | 52 /// |
61 /// Each entry corresponds to a collection currently being visited and the | 53 /// Each entry corresponds to a collection currently being visited and the |
62 /// value is whether or not it should be forced to split. Every time a | 54 /// value is whether or not it should be forced to split. Every time a |
63 /// collection is entered, it sets all of the existing elements to `true` | 55 /// collection is entered, it sets all of the existing elements to `true` |
64 /// then it pushes `false` for itself. | 56 /// then it pushes `false` for itself. |
65 /// | 57 /// |
66 /// When done visiting the elements, it removes its value. If it was set to | 58 /// When done visiting the elements, it removes its value. If it was set to |
67 /// `true`, we know we visited a nested collection so we force this one to | 59 /// `true`, we know we visited a nested collection so we force this one to |
68 /// split. | 60 /// split. |
69 final List<bool> _collectionSplits = []; | 61 final List<bool> _collectionSplits = []; |
70 | 62 |
| 63 /// The stack of current rules for handling parameter metadata. |
| 64 /// |
| 65 /// Each time a parameter (or type parameter) list is begun, a single rule |
| 66 /// for all of the metadata annotations on parameters in that list is pushed |
| 67 /// onto this stack. We reuse this rule for all annotations so that they split |
| 68 /// in unison. |
| 69 final List<MetadataRule> _metadataRules = []; |
| 70 |
| 71 /// The mapping for collection literals that are managed by the argument |
| 72 /// list that contains them. |
| 73 /// |
| 74 /// When a collection literal appears inside an [ArgumentSublist], the |
| 75 /// argument list provides a rule for the body to split to ensure that all |
| 76 /// collections split in unison. It also tracks the chunk before the |
| 77 /// argument that determines whether or not the collection body is indented |
| 78 /// like an expression or a statement. |
| 79 /// |
| 80 /// Before a collection literal argument is visited, [ArgumentSublist] binds |
| 81 /// itself to the left bracket token of each collection literal it controls. |
| 82 /// When we later visit that literal, we use the token to find that |
| 83 /// association. |
| 84 final Map<Token, ArgumentSublist> _collectionArgumentLists = {}; |
| 85 |
71 /// Initialize a newly created visitor to write source code representing | 86 /// Initialize a newly created visitor to write source code representing |
72 /// the visited nodes to the given [writer]. | 87 /// the visited nodes to the given [writer]. |
73 SourceVisitor(this._formatter, this._lineInfo, this._source) { | 88 SourceVisitor(this._formatter, this._lineInfo, this._source) { |
74 builder = new ChunkBuilder(_formatter, _source); | 89 builder = new ChunkBuilder(_formatter, _source); |
75 } | 90 } |
76 | 91 |
77 /// Runs the visitor on [node], formatting its contents. | 92 /// Runs the visitor on [node], formatting its contents. |
78 /// | 93 /// |
79 /// Returns a [SourceCode] containing the resulting formatted source and | 94 /// Returns a [SourceCode] containing the resulting formatted source and |
80 /// updated selection, if any. | 95 /// updated selection, if any. |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
163 } | 178 } |
164 | 179 |
165 visitAwaitExpression(AwaitExpression node) { | 180 visitAwaitExpression(AwaitExpression node) { |
166 token(node.awaitKeyword); | 181 token(node.awaitKeyword); |
167 space(); | 182 space(); |
168 visit(node.expression); | 183 visit(node.expression); |
169 } | 184 } |
170 | 185 |
171 visitBinaryExpression(BinaryExpression node) { | 186 visitBinaryExpression(BinaryExpression node) { |
172 builder.startSpan(); | 187 builder.startSpan(); |
173 builder.nestExpression(); | 188 |
| 189 // If a binary operator sequence appears immediately after a `=>`, don't |
| 190 // add an extra level of nesting. Instead, let the subsequent operands line |
| 191 // up with the first, as in: |
| 192 // |
| 193 // method() => |
| 194 // argument && |
| 195 // argument && |
| 196 // argument; |
| 197 var isArrowBody = node.parent is ExpressionFunctionBody; |
| 198 if (!isArrowBody) builder.nestExpression(); |
174 | 199 |
175 // Start lazily so we don't force the operator to split if a line comment | 200 // Start lazily so we don't force the operator to split if a line comment |
176 // appears before the first operand. | 201 // appears before the first operand. |
177 builder.startLazyRule(); | 202 builder.startLazyRule(); |
178 | 203 |
179 // Flatten out a tree/chain of the same precedence. If we split on this | 204 // Flatten out a tree/chain of the same precedence. If we split on this |
180 // precedence level, we will break all of them. | 205 // precedence level, we will break all of them. |
181 var precedence = node.operator.type.precedence; | 206 var precedence = node.operator.type.precedence; |
182 | 207 |
183 traverse(Expression e) { | 208 traverse(Expression e) { |
(...skipping 11 matching lines...) Expand all Loading... |
195 } | 220 } |
196 | 221 |
197 // Blocks as operands to infix operators should always nest like regular | 222 // Blocks as operands to infix operators should always nest like regular |
198 // operands. (Granted, this case is exceedingly rare in real code.) | 223 // operands. (Granted, this case is exceedingly rare in real code.) |
199 builder.startBlockArgumentNesting(); | 224 builder.startBlockArgumentNesting(); |
200 | 225 |
201 traverse(node); | 226 traverse(node); |
202 | 227 |
203 builder.endBlockArgumentNesting(); | 228 builder.endBlockArgumentNesting(); |
204 | 229 |
205 builder.unnest(); | 230 if (!isArrowBody) builder.unnest(); |
206 builder.endSpan(); | 231 builder.endSpan(); |
207 builder.endRule(); | 232 builder.endRule(); |
208 } | 233 } |
209 | 234 |
210 visitBlock(Block node) { | 235 visitBlock(Block node) { |
| 236 // Don't allow splitting in an empty block. |
| 237 if (node.statements.isEmpty && |
| 238 node.rightBracket.precedingComments == null) { |
| 239 token(node.leftBracket); |
| 240 token(node.rightBracket); |
| 241 return; |
| 242 } |
| 243 |
211 // For a block that is not a function body, just bump the indentation and | 244 // For a block that is not a function body, just bump the indentation and |
212 // keep it in the current block. | 245 // keep it in the current block. |
213 if (node.parent is! BlockFunctionBody) { | 246 if (node.parent is! BlockFunctionBody) { |
214 _writeBody(node.leftBracket, node.rightBracket, body: () { | 247 _writeBody(node.leftBracket, node.rightBracket, body: () { |
215 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); | 248 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); |
216 }); | 249 }); |
217 return; | 250 return; |
218 } | 251 } |
219 | 252 |
220 _startLiteralBody(node.leftBracket); | 253 _startLiteralBody(node.leftBracket); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 builder.startBlockArgumentNesting(); | 310 builder.startBlockArgumentNesting(); |
278 | 311 |
279 // If the cascade sections have consistent names they can be broken | 312 // If the cascade sections have consistent names they can be broken |
280 // normally otherwise they always get their own line. | 313 // normally otherwise they always get their own line. |
281 if (_allowInlineCascade(node.cascadeSections)) { | 314 if (_allowInlineCascade(node.cascadeSections)) { |
282 builder.startRule(); | 315 builder.startRule(); |
283 zeroSplit(); | 316 zeroSplit(); |
284 visitNodes(node.cascadeSections, between: zeroSplit); | 317 visitNodes(node.cascadeSections, between: zeroSplit); |
285 builder.endRule(); | 318 builder.endRule(); |
286 } else { | 319 } else { |
287 builder.startRule(new HardSplitRule()); | 320 builder.startRule(new Rule.hard()); |
288 zeroSplit(); | 321 zeroSplit(); |
289 visitNodes(node.cascadeSections, between: zeroSplit); | 322 visitNodes(node.cascadeSections, between: zeroSplit); |
290 builder.endRule(); | 323 builder.endRule(); |
291 } | 324 } |
292 | 325 |
293 builder.endBlockArgumentNesting(); | 326 builder.endBlockArgumentNesting(); |
294 builder.unnest(); | 327 builder.unnest(); |
295 | 328 |
296 if (node.target is MethodInvocation) builder.unnest(); | 329 if (node.target is MethodInvocation) builder.unnest(); |
297 } | 330 } |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 modifier(node.factoryKeyword); | 541 modifier(node.factoryKeyword); |
509 visit(node.returnType); | 542 visit(node.returnType); |
510 token(node.period); | 543 token(node.period); |
511 visit(node.name); | 544 visit(node.name); |
512 | 545 |
513 // Make the rule for the ":" span both the preceding parameter list and | 546 // Make the rule for the ":" span both the preceding parameter list and |
514 // the entire initialization list. This ensures that we split before the | 547 // the entire initialization list. This ensures that we split before the |
515 // ":" if the parameters and initialization list don't all fit on one line. | 548 // ":" if the parameters and initialization list don't all fit on one line. |
516 builder.startRule(); | 549 builder.startRule(); |
517 | 550 |
| 551 // If the redirecting constructor happens to wrap, we want to make sure |
| 552 // the parameter list gets more deeply indented. |
| 553 if (node.redirectedConstructor != null) builder.nestExpression(); |
| 554 |
518 _visitBody(node.parameters, node.body, () { | 555 _visitBody(node.parameters, node.body, () { |
519 // Check for redirects or initializer lists. | 556 // Check for redirects or initializer lists. |
520 if (node.redirectedConstructor != null) { | 557 if (node.redirectedConstructor != null) { |
521 _visitConstructorRedirects(node); | 558 _visitConstructorRedirects(node); |
| 559 builder.unnest(); |
522 } else if (node.initializers.isNotEmpty) { | 560 } else if (node.initializers.isNotEmpty) { |
523 _visitConstructorInitializers(node); | 561 _visitConstructorInitializers(node); |
524 } | 562 } |
525 }); | 563 }); |
526 } | 564 } |
527 | 565 |
528 void _visitConstructorRedirects(ConstructorDeclaration node) { | 566 void _visitConstructorRedirects(ConstructorDeclaration node) { |
529 token(node.separator /* = */, before: space, after: space); | 567 token(node.separator /* = */, before: space); |
| 568 soloSplit(); |
530 visitCommaSeparatedNodes(node.initializers); | 569 visitCommaSeparatedNodes(node.initializers); |
531 visit(node.redirectedConstructor); | 570 visit(node.redirectedConstructor); |
532 } | 571 } |
533 | 572 |
534 void _visitConstructorInitializers(ConstructorDeclaration node) { | 573 void _visitConstructorInitializers(ConstructorDeclaration node) { |
535 // Shift the ":" forward. | 574 // Shift the ":" forward. |
536 builder.indent(Indent.constructorInitializer); | 575 builder.indent(Indent.constructorInitializer); |
537 | 576 |
538 split(); | 577 split(); |
539 token(node.separator); // ":". | 578 token(node.separator); // ":". |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
593 visitDefaultFormalParameter(DefaultFormalParameter node) { | 632 visitDefaultFormalParameter(DefaultFormalParameter node) { |
594 visit(node.parameter); | 633 visit(node.parameter); |
595 if (node.separator != null) { | 634 if (node.separator != null) { |
596 builder.startSpan(); | 635 builder.startSpan(); |
597 builder.nestExpression(); | 636 builder.nestExpression(); |
598 | 637 |
599 // The '=' separator is preceded by a space, ":" is not. | 638 // The '=' separator is preceded by a space, ":" is not. |
600 if (node.separator.type == TokenType.EQ) space(); | 639 if (node.separator.type == TokenType.EQ) space(); |
601 token(node.separator); | 640 token(node.separator); |
602 | 641 |
603 soloSplit(Cost.assignment); | 642 soloSplit(_assignmentCost(node.defaultValue)); |
604 visit(node.defaultValue); | 643 visit(node.defaultValue); |
605 | 644 |
606 builder.unnest(); | 645 builder.unnest(); |
607 builder.endSpan(); | 646 builder.endSpan(); |
608 } | 647 } |
609 } | 648 } |
610 | 649 |
611 visitDoStatement(DoStatement node) { | 650 visitDoStatement(DoStatement node) { |
612 _simpleStatement(node, () { | 651 builder.nestExpression(); |
613 token(node.doKeyword); | 652 token(node.doKeyword); |
614 space(); | 653 space(); |
615 visit(node.body); | 654 builder.unnest(now: false); |
616 space(); | 655 visit(node.body); |
617 token(node.whileKeyword); | 656 |
618 space(); | 657 builder.nestExpression(); |
619 token(node.leftParenthesis); | 658 space(); |
620 soloZeroSplit(); | 659 token(node.whileKeyword); |
621 visit(node.condition); | 660 space(); |
622 token(node.rightParenthesis); | 661 token(node.leftParenthesis); |
623 }); | 662 soloZeroSplit(); |
| 663 visit(node.condition); |
| 664 token(node.rightParenthesis); |
| 665 token(node.semicolon); |
| 666 builder.unnest(); |
624 } | 667 } |
625 | 668 |
626 visitDoubleLiteral(DoubleLiteral node) { | 669 visitDoubleLiteral(DoubleLiteral node) { |
627 token(node.literal); | 670 token(node.literal); |
628 } | 671 } |
629 | 672 |
630 visitEmptyFunctionBody(EmptyFunctionBody node) { | 673 visitEmptyFunctionBody(EmptyFunctionBody node) { |
631 token(node.semicolon); | 674 token(node.semicolon); |
632 } | 675 } |
633 | 676 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
675 | 718 |
676 // Try to keep the "(...) => " with the start of the body for anonymous | 719 // Try to keep the "(...) => " with the start of the body for anonymous |
677 // functions. | 720 // functions. |
678 if (_isInLambda(node)) builder.startSpan(); | 721 if (_isInLambda(node)) builder.startSpan(); |
679 | 722 |
680 token(node.functionDefinition); // "=>". | 723 token(node.functionDefinition); // "=>". |
681 | 724 |
682 // Split after the "=>", using the rule created before the parameters | 725 // Split after the "=>", using the rule created before the parameters |
683 // by _visitBody(). | 726 // by _visitBody(). |
684 split(); | 727 split(); |
685 builder.endRule(); | 728 |
| 729 // If the body is a binary operator expression, then we want to force the |
| 730 // split at `=>` if the operators split. See visitBinaryExpression(). |
| 731 if (node.expression is! BinaryExpression) builder.endRule(); |
686 | 732 |
687 if (_isInLambda(node)) builder.endSpan(); | 733 if (_isInLambda(node)) builder.endSpan(); |
688 | 734 |
689 builder.startBlockArgumentNesting(); | 735 builder.startBlockArgumentNesting(); |
690 builder.startSpan(); | 736 builder.startSpan(); |
691 visit(node.expression); | 737 visit(node.expression); |
692 builder.endSpan(); | 738 builder.endSpan(); |
693 builder.endBlockArgumentNesting(); | 739 builder.endBlockArgumentNesting(); |
694 | 740 |
| 741 if (node.expression is BinaryExpression) builder.endRule(); |
| 742 |
695 token(node.semicolon); | 743 token(node.semicolon); |
696 } | 744 } |
697 | 745 |
698 visitExpressionStatement(ExpressionStatement node) { | 746 visitExpressionStatement(ExpressionStatement node) { |
699 _simpleStatement(node, () { | 747 _simpleStatement(node, () { |
700 visit(node.expression); | 748 visit(node.expression); |
701 }); | 749 }); |
702 } | 750 } |
703 | 751 |
704 visitExtendsClause(ExtendsClause node) { | 752 visitExtendsClause(ExtendsClause node) { |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
737 if (node.loopVariable != null) { | 785 if (node.loopVariable != null) { |
738 visit(node.loopVariable); | 786 visit(node.loopVariable); |
739 } else { | 787 } else { |
740 visit(node.identifier); | 788 visit(node.identifier); |
741 } | 789 } |
742 soloSplit(); | 790 soloSplit(); |
743 token(node.inKeyword); | 791 token(node.inKeyword); |
744 space(); | 792 space(); |
745 visit(node.iterable); | 793 visit(node.iterable); |
746 token(node.rightParenthesis); | 794 token(node.rightParenthesis); |
747 space(); | 795 builder.unnest(now: false); |
748 visit(node.body); | 796 |
749 builder.unnest(); | 797 _visitLoopBody(node.body); |
750 } | 798 } |
751 | 799 |
752 visitFormalParameterList(FormalParameterList node) { | 800 visitFormalParameterList(FormalParameterList node) { |
753 // Corner case: empty parameter lists. | 801 // Corner case: empty parameter lists. |
754 if (node.parameters.isEmpty) { | 802 if (node.parameters.isEmpty) { |
755 token(node.leftParenthesis); | 803 token(node.leftParenthesis); |
756 | 804 |
757 // If there is a comment, do allow splitting before it. | 805 // If there is a comment, do allow splitting before it. |
758 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); | 806 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); |
759 | 807 |
760 token(node.rightParenthesis); | 808 token(node.rightParenthesis); |
761 return; | 809 return; |
762 } | 810 } |
763 | 811 |
764 var requiredParams = node.parameters | 812 var requiredParams = node.parameters |
765 .where((param) => param is! DefaultFormalParameter) | 813 .where((param) => param is! DefaultFormalParameter) |
766 .toList(); | 814 .toList(); |
767 var optionalParams = node.parameters | 815 var optionalParams = node.parameters |
768 .where((param) => param is DefaultFormalParameter) | 816 .where((param) => param is DefaultFormalParameter) |
769 .toList(); | 817 .toList(); |
770 | 818 |
771 builder.nestExpression(); | 819 builder.nestExpression(); |
772 token(node.leftParenthesis); | 820 token(node.leftParenthesis); |
773 | 821 |
| 822 _metadataRules.add(new MetadataRule()); |
| 823 |
774 var rule; | 824 var rule; |
775 if (requiredParams.isNotEmpty) { | 825 if (requiredParams.isNotEmpty) { |
776 if (requiredParams.length > 1) { | 826 if (requiredParams.length > 1) { |
777 rule = new MultiplePositionalRule(null, 0, 0); | 827 rule = new MultiplePositionalRule(null, 0, 0); |
778 } else { | 828 } else { |
779 rule = new SinglePositionalRule(null); | 829 rule = new SinglePositionalRule(null); |
780 } | 830 } |
781 | 831 |
| 832 _metadataRules.last.bindPositionalRule(rule); |
| 833 |
782 builder.startRule(rule); | 834 builder.startRule(rule); |
783 if (_isInLambda(node)) { | 835 if (_isInLambda(node)) { |
784 // Don't allow splitting before the first argument (i.e. right after | 836 // Don't allow splitting before the first argument (i.e. right after |
785 // the bare "(" in a lambda. Instead, just stuff a null chunk in there | 837 // the bare "(" in a lambda. Instead, just stuff a null chunk in there |
786 // to avoid confusing the arg rule. | 838 // to avoid confusing the arg rule. |
787 rule.beforeArgument(null); | 839 rule.beforeArgument(null); |
788 } else { | 840 } else { |
789 // Split before the first argument. | 841 // Split before the first argument. |
790 rule.beforeArgument(zeroSplit()); | 842 rule.beforeArgument(zeroSplit()); |
791 } | 843 } |
792 | 844 |
793 builder.startSpan(); | 845 builder.startSpan(); |
794 | 846 |
795 for (var param in requiredParams) { | 847 for (var param in requiredParams) { |
796 visit(param); | 848 visit(param); |
797 | 849 |
798 // Write the trailing comma. | 850 // Write the trailing comma. |
799 if (param != node.parameters.last) token(param.endToken.next); | 851 if (param != node.parameters.last) token(param.endToken.next); |
800 | 852 |
801 if (param != requiredParams.last) rule.beforeArgument(split()); | 853 if (param != requiredParams.last) rule.beforeArgument(split()); |
802 } | 854 } |
803 | 855 |
804 builder.endSpan(); | 856 builder.endSpan(); |
805 builder.endRule(); | 857 builder.endRule(); |
806 } | 858 } |
807 | 859 |
808 if (optionalParams.isNotEmpty) { | 860 if (optionalParams.isNotEmpty) { |
809 var namedRule = new NamedRule(null); | 861 var namedRule = new NamedRule(null, 0, 0); |
810 if (rule != null) rule.setNamedArgsRule(namedRule); | 862 if (rule != null) rule.setNamedArgsRule(namedRule); |
811 | 863 |
| 864 _metadataRules.last.bindNamedRule(namedRule); |
| 865 |
812 builder.startRule(namedRule); | 866 builder.startRule(namedRule); |
813 | 867 |
814 namedRule | 868 // Make sure multi-line default values are indented. |
815 .beforeArguments(builder.split(space: requiredParams.isNotEmpty)); | 869 builder.startBlockArgumentNesting(); |
| 870 |
| 871 namedRule.beforeArgument(builder.split(space: requiredParams.isNotEmpty)); |
816 | 872 |
817 // "[" or "{" for optional parameters. | 873 // "[" or "{" for optional parameters. |
818 token(node.leftDelimiter); | 874 token(node.leftDelimiter); |
819 | 875 |
820 for (var param in optionalParams) { | 876 for (var param in optionalParams) { |
821 visit(param); | 877 visit(param); |
822 | 878 |
823 // Write the trailing comma. | 879 // Write the trailing comma. |
824 if (param != node.parameters.last) token(param.endToken.next); | 880 if (param != node.parameters.last) token(param.endToken.next); |
825 if (param != optionalParams.last) split(); | 881 if (param != optionalParams.last) namedRule.beforeArgument(split()); |
826 } | 882 } |
827 | 883 |
| 884 builder.endBlockArgumentNesting(); |
828 builder.endRule(); | 885 builder.endRule(); |
829 | 886 |
830 // "]" or "}" for optional parameters. | 887 // "]" or "}" for optional parameters. |
831 token(node.rightDelimiter); | 888 token(node.rightDelimiter); |
832 } | 889 } |
833 | 890 |
| 891 _metadataRules.removeLast(); |
| 892 |
834 token(node.rightParenthesis); | 893 token(node.rightParenthesis); |
835 builder.unnest(); | 894 builder.unnest(); |
836 } | 895 } |
837 | 896 |
838 visitForStatement(ForStatement node) { | 897 visitForStatement(ForStatement node) { |
839 builder.nestExpression(); | 898 builder.nestExpression(); |
840 token(node.forKeyword); | 899 token(node.forKeyword); |
841 space(); | 900 space(); |
842 token(node.leftParenthesis); | 901 token(node.leftParenthesis); |
843 | 902 |
844 builder.startRule(); | 903 builder.startRule(); |
845 | 904 |
846 // The initialization clause. | 905 // The initialization clause. |
847 if (node.initialization != null) { | 906 if (node.initialization != null) { |
848 visit(node.initialization); | 907 visit(node.initialization); |
849 } else if (node.variables != null) { | 908 } else if (node.variables != null) { |
850 // Indent split variables more so they aren't at the same level | 909 // Nest split variables more so they aren't at the same level |
851 // as the rest of the loop clauses. | 910 // as the rest of the loop clauses. |
852 builder.indent(Indent.loopVariable); | 911 builder.nestExpression(); |
853 | 912 |
854 // Allow the variables to stay unsplit even if the clauses split. | 913 // Allow the variables to stay unsplit even if the clauses split. |
855 builder.startRule(); | 914 builder.startRule(); |
856 | 915 |
857 var declaration = node.variables; | 916 var declaration = node.variables; |
858 visitDeclarationMetadata(declaration.metadata); | 917 visitDeclarationMetadata(declaration.metadata); |
859 modifier(declaration.keyword); | 918 modifier(declaration.keyword); |
860 visit(declaration.type, after: space); | 919 visit(declaration.type, after: space); |
861 | 920 |
862 visitCommaSeparatedNodes(declaration.variables, between: () { | 921 visitCommaSeparatedNodes(declaration.variables, between: () { |
863 split(); | 922 split(); |
864 }); | 923 }); |
865 | 924 |
866 builder.endRule(); | 925 builder.endRule(); |
867 builder.unindent(); | 926 builder.unnest(); |
868 } | 927 } |
869 | 928 |
870 token(node.leftSeparator); | 929 token(node.leftSeparator); |
871 | 930 |
872 // The condition clause. | 931 // The condition clause. |
873 if (node.condition != null) split(); | 932 if (node.condition != null) split(); |
874 visit(node.condition); | 933 visit(node.condition); |
875 token(node.rightSeparator); | 934 token(node.rightSeparator); |
876 | 935 |
877 // The update clause. | 936 // The update clause. |
878 if (node.updaters.isNotEmpty) { | 937 if (node.updaters.isNotEmpty) { |
879 split(); | 938 split(); |
880 | 939 |
881 // Allow the updates to stay unsplit even if the clauses split. | 940 // Allow the updates to stay unsplit even if the clauses split. |
882 builder.startRule(); | 941 builder.startRule(); |
883 | 942 |
884 visitCommaSeparatedNodes(node.updaters, between: split); | 943 visitCommaSeparatedNodes(node.updaters, between: split); |
885 | 944 |
886 builder.endRule(); | 945 builder.endRule(); |
887 } | 946 } |
888 | 947 |
889 token(node.rightParenthesis); | 948 token(node.rightParenthesis); |
890 builder.endRule(); | 949 builder.endRule(); |
891 builder.unnest(); | 950 builder.unnest(); |
892 | 951 |
893 // The body. | 952 _visitLoopBody(node.body); |
894 if (node.body is! EmptyStatement) space(); | |
895 visit(node.body); | |
896 } | 953 } |
897 | 954 |
898 visitFunctionDeclaration(FunctionDeclaration node) { | 955 visitFunctionDeclaration(FunctionDeclaration node) { |
899 visitMemberMetadata(node.metadata); | 956 _visitMemberDeclaration(node, node.functionExpression); |
900 | |
901 builder.nestExpression(); | |
902 modifier(node.externalKeyword); | |
903 visit(node.returnType, after: space); | |
904 modifier(node.propertyKeyword); | |
905 visit(node.name); | |
906 visit(node.functionExpression); | |
907 builder.unnest(); | |
908 } | 957 } |
909 | 958 |
910 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | 959 visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
911 visit(node.functionDeclaration); | 960 visit(node.functionDeclaration); |
912 } | 961 } |
913 | 962 |
914 visitFunctionExpression(FunctionExpression node) { | 963 visitFunctionExpression(FunctionExpression node) { |
915 _visitBody(node.parameters, node.body); | 964 _visitBody(node.parameters, node.body); |
916 } | 965 } |
917 | 966 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
949 _visitCombinator(node.keyword, node.hiddenNames); | 998 _visitCombinator(node.keyword, node.hiddenNames); |
950 } | 999 } |
951 | 1000 |
952 visitIfStatement(IfStatement node) { | 1001 visitIfStatement(IfStatement node) { |
953 builder.nestExpression(); | 1002 builder.nestExpression(); |
954 token(node.ifKeyword); | 1003 token(node.ifKeyword); |
955 space(); | 1004 space(); |
956 token(node.leftParenthesis); | 1005 token(node.leftParenthesis); |
957 visit(node.condition); | 1006 visit(node.condition); |
958 token(node.rightParenthesis); | 1007 token(node.rightParenthesis); |
| 1008 builder.unnest(now: false); |
959 | 1009 |
960 space(); | 1010 visitClause(Statement clause) { |
961 visit(node.thenStatement); | 1011 if (clause is Block || clause is IfStatement) { |
962 builder.unnest(); | 1012 space(); |
| 1013 visit(clause); |
| 1014 } else { |
| 1015 // Allow splitting in an expression-bodied if even though it's against |
| 1016 // 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. |
| 1018 builder.nestExpression(indent: 2, now: true); |
| 1019 builder.startRule(); |
| 1020 |
| 1021 // If there is an else clause, always split before both the then and |
| 1022 // else statements. |
| 1023 if (node.elseStatement != null) { |
| 1024 builder.writeWhitespace(Whitespace.nestedNewline); |
| 1025 } else { |
| 1026 split(); |
| 1027 } |
| 1028 |
| 1029 visit(clause); |
| 1030 |
| 1031 builder.endRule(); |
| 1032 builder.unnest(); |
| 1033 } |
| 1034 } |
| 1035 |
| 1036 visitClause(node.thenStatement); |
963 | 1037 |
964 if (node.elseStatement != null) { | 1038 if (node.elseStatement != null) { |
965 if (node.thenStatement is Block) { | 1039 if (node.thenStatement is Block) { |
966 space(); | 1040 space(); |
967 } else { | 1041 } else { |
968 // Corner case where an else follows a single-statement then clause. | 1042 // Corner case where an else follows a single-statement then clause. |
969 // This is against the style guide, but we still need to handle it. If | 1043 // This is against the style guide, but we still need to handle it. If |
970 // it happens, put the else on the next line. | 1044 // it happens, put the else on the next line. |
971 newline(); | 1045 newline(); |
972 } | 1046 } |
973 | 1047 |
974 token(node.elseKeyword); | 1048 token(node.elseKeyword); |
975 space(); | 1049 visitClause(node.elseStatement); |
976 visit(node.elseStatement); | |
977 } | 1050 } |
978 } | 1051 } |
979 | 1052 |
980 visitImplementsClause(ImplementsClause node) { | 1053 visitImplementsClause(ImplementsClause node) { |
981 _visitCombinator(node.implementsKeyword, node.interfaces); | 1054 _visitCombinator(node.implementsKeyword, node.interfaces); |
982 } | 1055 } |
983 | 1056 |
984 visitImportDirective(ImportDirective node) { | 1057 visitImportDirective(ImportDirective node) { |
985 visitDeclarationMetadata(node.metadata); | 1058 visitDeclarationMetadata(node.metadata); |
986 | 1059 |
(...skipping 18 matching lines...) Expand all Loading... |
1005 | 1078 |
1006 visitIndexExpression(IndexExpression node) { | 1079 visitIndexExpression(IndexExpression node) { |
1007 builder.nestExpression(); | 1080 builder.nestExpression(); |
1008 | 1081 |
1009 if (node.isCascaded) { | 1082 if (node.isCascaded) { |
1010 token(node.period); | 1083 token(node.period); |
1011 } else { | 1084 } else { |
1012 visit(node.target); | 1085 visit(node.target); |
1013 } | 1086 } |
1014 | 1087 |
| 1088 finishIndexExpression(node); |
| 1089 |
| 1090 builder.unnest(); |
| 1091 } |
| 1092 |
| 1093 /// Visit the index part of [node], excluding the target. |
| 1094 /// |
| 1095 /// Called by [CallChainVisitor] to handle index expressions in the middle of |
| 1096 /// call chains. |
| 1097 void finishIndexExpression(IndexExpression node) { |
1015 if (node.target is IndexExpression) { | 1098 if (node.target is IndexExpression) { |
1016 // Corner case: On a chain of [] accesses, allow splitting between them. | 1099 // Edge case: On a chain of [] accesses, allow splitting between them. |
1017 // Produces nicer output in cases like: | 1100 // Produces nicer output in cases like: |
1018 // | 1101 // |
1019 // someJson['property']['property']['property']['property']... | 1102 // someJson['property']['property']['property']['property']... |
1020 soloZeroSplit(); | 1103 soloZeroSplit(); |
1021 } | 1104 } |
1022 | 1105 |
1023 builder.startSpan(); | 1106 builder.startSpan(); |
1024 token(node.leftBracket); | 1107 token(node.leftBracket); |
1025 soloZeroSplit(); | 1108 soloZeroSplit(); |
1026 visit(node.index); | 1109 visit(node.index); |
1027 token(node.rightBracket); | 1110 token(node.rightBracket); |
1028 builder.endSpan(); | 1111 builder.endSpan(); |
1029 builder.unnest(); | |
1030 } | 1112 } |
1031 | 1113 |
1032 visitInstanceCreationExpression(InstanceCreationExpression node) { | 1114 visitInstanceCreationExpression(InstanceCreationExpression node) { |
1033 builder.startSpan(); | 1115 builder.startSpan(); |
1034 token(node.keyword); | 1116 token(node.keyword); |
1035 space(); | 1117 space(); |
| 1118 builder.startSpan(Cost.constructorName); |
1036 visit(node.constructorName); | 1119 visit(node.constructorName); |
| 1120 builder.endSpan(); |
1037 visit(node.argumentList); | 1121 visit(node.argumentList); |
1038 builder.endSpan(); | 1122 builder.endSpan(); |
1039 } | 1123 } |
1040 | 1124 |
1041 visitIntegerLiteral(IntegerLiteral node) { | 1125 visitIntegerLiteral(IntegerLiteral node) { |
1042 token(node.literal); | 1126 token(node.literal); |
1043 } | 1127 } |
1044 | 1128 |
1045 visitInterpolationExpression(InterpolationExpression node) { | 1129 visitInterpolationExpression(InterpolationExpression node) { |
1046 token(node.leftBracket); | 1130 token(node.leftBracket); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1105 } | 1189 } |
1106 | 1190 |
1107 visitMapLiteralEntry(MapLiteralEntry node) { | 1191 visitMapLiteralEntry(MapLiteralEntry node) { |
1108 visit(node.key); | 1192 visit(node.key); |
1109 token(node.separator); | 1193 token(node.separator); |
1110 soloSplit(); | 1194 soloSplit(); |
1111 visit(node.value); | 1195 visit(node.value); |
1112 } | 1196 } |
1113 | 1197 |
1114 visitMethodDeclaration(MethodDeclaration node) { | 1198 visitMethodDeclaration(MethodDeclaration node) { |
1115 visitMemberMetadata(node.metadata); | 1199 _visitMemberDeclaration(node, node); |
1116 | |
1117 modifier(node.externalKeyword); | |
1118 modifier(node.modifierKeyword); | |
1119 visit(node.returnType, after: space); | |
1120 modifier(node.propertyKeyword); | |
1121 modifier(node.operatorKeyword); | |
1122 visit(node.name); | |
1123 | |
1124 _visitBody(node.parameters, node.body); | |
1125 } | 1200 } |
1126 | 1201 |
1127 visitMethodInvocation(MethodInvocation node) { | 1202 visitMethodInvocation(MethodInvocation node) { |
1128 // If there's no target, this is a "bare" function call like "foo(1, 2)", | 1203 // If there's no target, this is a "bare" function call like "foo(1, 2)", |
1129 // or a section in a cascade. Handle this case specially. | 1204 // or a section in a cascade. Handle this case specially. |
1130 if (node.target == null) { | 1205 if (node.target == null) { |
1131 // Try to keep the entire method invocation one line. | 1206 // Try to keep the entire method invocation one line. |
1132 builder.startSpan(); | 1207 builder.startSpan(); |
1133 builder.nestExpression(); | 1208 builder.nestExpression(); |
1134 | 1209 |
1135 // This will be non-null for cascade sections. | 1210 // This will be non-null for cascade sections. |
1136 token(node.operator); | 1211 token(node.operator); |
1137 token(node.methodName.token); | 1212 token(node.methodName.token); |
1138 visit(node.argumentList); | 1213 visit(node.argumentList); |
1139 | 1214 |
1140 builder.unnest(); | 1215 builder.unnest(); |
1141 builder.endSpan(); | 1216 builder.endSpan(); |
1142 return; | 1217 return; |
1143 } | 1218 } |
1144 | 1219 |
1145 new CallChainVisitor(this, node).visit(); | 1220 new CallChainVisitor(this, node).visit(); |
1146 } | 1221 } |
1147 | 1222 |
1148 visitNamedExpression(NamedExpression node) { | 1223 visitNamedExpression(NamedExpression node) { |
1149 builder.nestExpression(); | 1224 builder.nestExpression(); |
1150 builder.startSpan(); | 1225 builder.startSpan(); |
1151 visit(node.name); | 1226 visit(node.name); |
1152 visit(node.expression, before: soloSplit); | 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); |
1153 builder.endSpan(); | 1237 builder.endSpan(); |
1154 builder.unnest(); | 1238 builder.unnest(); |
1155 } | 1239 } |
1156 | 1240 |
1157 visitNativeClause(NativeClause node) { | 1241 visitNativeClause(NativeClause node) { |
1158 token(node.nativeKeyword); | 1242 token(node.nativeKeyword); |
1159 space(); | 1243 space(); |
1160 visit(node.name); | 1244 visit(node.name); |
1161 } | 1245 } |
1162 | 1246 |
(...skipping 14 matching lines...) Expand all Loading... |
1177 | 1261 |
1178 visitParenthesizedExpression(ParenthesizedExpression node) { | 1262 visitParenthesizedExpression(ParenthesizedExpression node) { |
1179 builder.nestExpression(); | 1263 builder.nestExpression(); |
1180 token(node.leftParenthesis); | 1264 token(node.leftParenthesis); |
1181 visit(node.expression); | 1265 visit(node.expression); |
1182 builder.unnest(); | 1266 builder.unnest(); |
1183 token(node.rightParenthesis); | 1267 token(node.rightParenthesis); |
1184 } | 1268 } |
1185 | 1269 |
1186 visitPartDirective(PartDirective node) { | 1270 visitPartDirective(PartDirective node) { |
| 1271 visitDeclarationMetadata(node.metadata); |
| 1272 |
1187 _simpleStatement(node, () { | 1273 _simpleStatement(node, () { |
1188 token(node.keyword); | 1274 token(node.keyword); |
1189 space(); | 1275 space(); |
1190 visit(node.uri); | 1276 visit(node.uri); |
1191 }); | 1277 }); |
1192 } | 1278 } |
1193 | 1279 |
1194 visitPartOfDirective(PartOfDirective node) { | 1280 visitPartOfDirective(PartOfDirective node) { |
| 1281 visitDeclarationMetadata(node.metadata); |
| 1282 |
1195 _simpleStatement(node, () { | 1283 _simpleStatement(node, () { |
1196 token(node.keyword); | 1284 token(node.keyword); |
1197 space(); | 1285 space(); |
1198 token(node.ofKeyword); | 1286 token(node.ofKeyword); |
1199 space(); | 1287 space(); |
1200 visit(node.libraryName); | 1288 visit(node.libraryName); |
1201 }); | 1289 }); |
1202 } | 1290 } |
1203 | 1291 |
1204 visitPostfixExpression(PostfixExpression node) { | 1292 visitPostfixExpression(PostfixExpression node) { |
1205 visit(node.operand); | 1293 visit(node.operand); |
1206 token(node.operator); | 1294 token(node.operator); |
1207 } | 1295 } |
1208 | 1296 |
1209 visitPrefixedIdentifier(PrefixedIdentifier node) { | 1297 visitPrefixedIdentifier(PrefixedIdentifier node) { |
1210 visit(node.prefix); | 1298 new CallChainVisitor(this, node).visit(); |
1211 token(node.period); | |
1212 visit(node.identifier); | |
1213 } | 1299 } |
1214 | 1300 |
1215 visitPrefixExpression(PrefixExpression node) { | 1301 visitPrefixExpression(PrefixExpression node) { |
1216 token(node.operator); | 1302 token(node.operator); |
1217 | 1303 |
1218 // Corner case: put a space between successive "-" operators so we don't | 1304 // Corner case: put a space between successive "-" operators so we don't |
1219 // inadvertently turn them into a "--" decrement operator. | 1305 // inadvertently turn them into a "--" decrement operator. |
1220 if (node.operand is PrefixExpression && | 1306 if (node.operand is PrefixExpression && |
1221 (node.operand as PrefixExpression).operator.lexeme == "-") { | 1307 (node.operand as PrefixExpression).operator.lexeme == "-") { |
1222 space(); | 1308 space(); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1350 visitSwitchStatement(SwitchStatement node) { | 1436 visitSwitchStatement(SwitchStatement node) { |
1351 builder.nestExpression(); | 1437 builder.nestExpression(); |
1352 token(node.switchKeyword); | 1438 token(node.switchKeyword); |
1353 space(); | 1439 space(); |
1354 token(node.leftParenthesis); | 1440 token(node.leftParenthesis); |
1355 soloZeroSplit(); | 1441 soloZeroSplit(); |
1356 visit(node.expression); | 1442 visit(node.expression); |
1357 token(node.rightParenthesis); | 1443 token(node.rightParenthesis); |
1358 space(); | 1444 space(); |
1359 token(node.leftBracket); | 1445 token(node.leftBracket); |
| 1446 builder.unnest(); |
1360 builder.indent(); | 1447 builder.indent(); |
1361 newline(); | 1448 newline(); |
1362 | 1449 |
1363 visitNodes(node.members, between: oneOrTwoNewlines, after: newline); | 1450 visitNodes(node.members, between: oneOrTwoNewlines, after: newline); |
1364 token(node.rightBracket, before: () { | 1451 token(node.rightBracket, before: () { |
1365 builder.unindent(); | 1452 builder.unindent(); |
1366 newline(); | 1453 newline(); |
1367 }); | 1454 }); |
1368 builder.unnest(); | |
1369 } | 1455 } |
1370 | 1456 |
1371 visitSymbolLiteral(SymbolLiteral node) { | 1457 visitSymbolLiteral(SymbolLiteral node) { |
1372 token(node.poundSign); | 1458 token(node.poundSign); |
1373 var components = node.components; | 1459 var components = node.components; |
1374 for (var component in components) { | 1460 for (var component in components) { |
1375 // The '.' separator | 1461 // The '.' separator |
1376 if (component.previous.lexeme == '.') { | 1462 if (component.previous.lexeme == '.') { |
1377 token(component.previous); | 1463 token(component.previous); |
1378 } | 1464 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1418 | 1504 |
1419 visitTypeParameter(TypeParameter node) { | 1505 visitTypeParameter(TypeParameter node) { |
1420 visitParameterMetadata(node.metadata, () { | 1506 visitParameterMetadata(node.metadata, () { |
1421 visit(node.name); | 1507 visit(node.name); |
1422 token(node.extendsKeyword, before: space, after: space); | 1508 token(node.extendsKeyword, before: space, after: space); |
1423 visit(node.bound); | 1509 visit(node.bound); |
1424 }); | 1510 }); |
1425 } | 1511 } |
1426 | 1512 |
1427 visitTypeParameterList(TypeParameterList node) { | 1513 visitTypeParameterList(TypeParameterList node) { |
| 1514 _metadataRules.add(new MetadataRule()); |
| 1515 |
1428 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); | 1516 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); |
| 1517 |
| 1518 _metadataRules.removeLast(); |
1429 } | 1519 } |
1430 | 1520 |
1431 visitVariableDeclaration(VariableDeclaration node) { | 1521 visitVariableDeclaration(VariableDeclaration node) { |
1432 visit(node.name); | 1522 visit(node.name); |
1433 if (node.initializer == null) return; | 1523 if (node.initializer == null) return; |
1434 | 1524 |
1435 _visitAssignment(node.equals, node.initializer); | 1525 _visitAssignment(node.equals, node.initializer); |
1436 } | 1526 } |
1437 | 1527 |
1438 visitVariableDeclarationList(VariableDeclarationList node) { | 1528 visitVariableDeclarationList(VariableDeclarationList node) { |
1439 visitDeclarationMetadata(node.metadata); | 1529 visitDeclarationMetadata(node.metadata); |
| 1530 |
| 1531 // Allow but try to avoid splitting between the type and name. |
| 1532 builder.startSpan(); |
| 1533 |
1440 modifier(node.keyword); | 1534 modifier(node.keyword); |
1441 visit(node.type, after: space); | 1535 visit(node.type, after: soloSplit); |
| 1536 |
| 1537 builder.endSpan(); |
1442 | 1538 |
1443 // Use a single rule for all of the variables. If there are multiple | 1539 // Use a single rule for all of the variables. If there are multiple |
1444 // declarations, we will try to keep them all on one line. If that isn't | 1540 // declarations, we will try to keep them all on one line. If that isn't |
1445 // possible, we split after *every* declaration so that each is on its own | 1541 // possible, we split after *every* declaration so that each is on its own |
1446 // line. | 1542 // line. |
1447 builder.startRule(); | 1543 builder.startRule(); |
1448 visitCommaSeparatedNodes(node.variables, between: split); | 1544 visitCommaSeparatedNodes(node.variables, between: split); |
1449 builder.endRule(); | 1545 builder.endRule(); |
1450 } | 1546 } |
1451 | 1547 |
1452 visitVariableDeclarationStatement(VariableDeclarationStatement node) { | 1548 visitVariableDeclarationStatement(VariableDeclarationStatement node) { |
1453 _simpleStatement(node, () { | 1549 _simpleStatement(node, () { |
1454 visit(node.variables); | 1550 visit(node.variables); |
1455 }); | 1551 }); |
1456 } | 1552 } |
1457 | 1553 |
1458 visitWhileStatement(WhileStatement node) { | 1554 visitWhileStatement(WhileStatement node) { |
1459 builder.nestExpression(); | 1555 builder.nestExpression(); |
1460 token(node.whileKeyword); | 1556 token(node.whileKeyword); |
1461 space(); | 1557 space(); |
1462 token(node.leftParenthesis); | 1558 token(node.leftParenthesis); |
1463 soloZeroSplit(); | 1559 soloZeroSplit(); |
1464 visit(node.condition); | 1560 visit(node.condition); |
1465 token(node.rightParenthesis); | 1561 token(node.rightParenthesis); |
1466 if (node.body is! EmptyStatement) space(); | 1562 builder.unnest(now: false); |
1467 visit(node.body); | 1563 |
1468 builder.unnest(); | 1564 _visitLoopBody(node.body); |
1469 } | 1565 } |
1470 | 1566 |
1471 visitWithClause(WithClause node) { | 1567 visitWithClause(WithClause node) { |
1472 _visitCombinator(node.withKeyword, node.mixinTypes); | 1568 _visitCombinator(node.withKeyword, node.mixinTypes); |
1473 } | 1569 } |
1474 | 1570 |
1475 visitYieldStatement(YieldStatement node) { | 1571 visitYieldStatement(YieldStatement node) { |
1476 _simpleStatement(node, () { | 1572 _simpleStatement(node, () { |
1477 token(node.yieldKeyword); | 1573 token(node.yieldKeyword); |
1478 token(node.star); | 1574 token(node.star); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1517 } else { | 1613 } else { |
1518 visitNodes(metadata, between: space, after: spaceOrNewline); | 1614 visitNodes(metadata, between: space, after: spaceOrNewline); |
1519 } | 1615 } |
1520 } | 1616 } |
1521 | 1617 |
1522 /// Visits metadata annotations on parameters and type parameters. | 1618 /// Visits metadata annotations on parameters and type parameters. |
1523 /// | 1619 /// |
1524 /// These are always on the same line as the parameter. | 1620 /// These are always on the same line as the parameter. |
1525 void visitParameterMetadata( | 1621 void visitParameterMetadata( |
1526 NodeList<Annotation> metadata, void visitParameter()) { | 1622 NodeList<Annotation> metadata, void visitParameter()) { |
| 1623 if (metadata == null || metadata.isEmpty) { |
| 1624 visitParameter(); |
| 1625 return; |
| 1626 } |
| 1627 |
1527 // Split before all of the annotations or none. | 1628 // Split before all of the annotations or none. |
1528 builder.startRule(); | 1629 builder.startLazyRule(_metadataRules.last); |
1529 visitNodes(metadata, between: split, after: split); | 1630 |
| 1631 visitNodes(metadata, between: split, after: () { |
| 1632 // Don't nest until right before the last metadata. Ensures we only |
| 1633 // indent the parameter and not any of the metadata: |
| 1634 // |
| 1635 // function( |
| 1636 // @LongAnnotation |
| 1637 // @LongAnnotation |
| 1638 // indentedParameter) {} |
| 1639 builder.nestExpression(now: true); |
| 1640 split(); |
| 1641 }); |
1530 visitParameter(); | 1642 visitParameter(); |
1531 | 1643 |
| 1644 builder.unnest(); |
| 1645 |
1532 // Wrap the rule around the parameter too. If it splits, we want to force | 1646 // Wrap the rule around the parameter too. If it splits, we want to force |
1533 // the annotations to split as well. | 1647 // the annotations to split as well. |
1534 builder.endRule(); | 1648 builder.endRule(); |
1535 } | 1649 } |
1536 | 1650 |
1537 /// Visits the `=` and the following expression in any place where an `=` | 1651 /// Visits the `=` and the following expression in any place where an `=` |
1538 /// appears: | 1652 /// appears: |
1539 /// | 1653 /// |
1540 /// * Assignment | 1654 /// * Assignment |
1541 /// * Variable declaration | 1655 /// * Variable declaration |
1542 /// * Constructor initialization | 1656 /// * Constructor initialization |
1543 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { | 1657 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { |
1544 space(); | 1658 space(); |
1545 token(equalsOperator); | 1659 token(equalsOperator); |
1546 soloSplit(Cost.assignment); | 1660 soloSplit(_assignmentCost(rightHandSide)); |
1547 builder.startSpan(); | 1661 builder.startSpan(); |
1548 visit(rightHandSide); | 1662 visit(rightHandSide); |
1549 builder.endSpan(); | 1663 builder.endSpan(); |
1550 } | 1664 } |
1551 | 1665 |
1552 /// Visits a type parameter or type argument list. | 1666 /// Visits a type parameter or type argument list. |
1553 void _visitGenericList( | 1667 void _visitGenericList( |
1554 Token leftBracket, Token rightBracket, List<AstNode> nodes) { | 1668 Token leftBracket, Token rightBracket, List<AstNode> nodes) { |
1555 var rule = new TypeArgumentRule(); | 1669 var rule = new TypeArgumentRule(); |
1556 builder.startRule(rule); | 1670 builder.startRule(rule); |
(...skipping 13 matching lines...) Expand all Loading... |
1570 } | 1684 } |
1571 } | 1685 } |
1572 | 1686 |
1573 token(rightBracket); | 1687 token(rightBracket); |
1574 | 1688 |
1575 builder.unnest(); | 1689 builder.unnest(); |
1576 builder.endSpan(); | 1690 builder.endSpan(); |
1577 builder.endRule(); | 1691 builder.endRule(); |
1578 } | 1692 } |
1579 | 1693 |
| 1694 /// Visits a top-level function or method declaration. |
| 1695 /// |
| 1696 /// The two AST node types are very similar but, alas, share no common |
| 1697 /// interface type in analyzer, hence the dynamic typing. |
| 1698 void _visitMemberDeclaration( |
| 1699 /* FunctionDeclaration|MethodDeclaration */ node, |
| 1700 /* FunctionExpression|MethodDeclaration */ function) { |
| 1701 visitMemberMetadata(node.metadata); |
| 1702 |
| 1703 // Nest the signature in case we have to split between the return type and |
| 1704 // name. |
| 1705 builder.nestExpression(); |
| 1706 builder.startSpan(); |
| 1707 modifier(node.externalKeyword); |
| 1708 if (node is MethodDeclaration) modifier(node.modifierKeyword); |
| 1709 visit(node.returnType, after: soloSplit); |
| 1710 modifier(node.propertyKeyword); |
| 1711 if (node is MethodDeclaration) modifier(node.operatorKeyword); |
| 1712 visit(node.name); |
| 1713 builder.endSpan(); |
| 1714 |
| 1715 // If the body is a block, we need to exit any nesting first. If it's an |
| 1716 // expression, we want to wrap the nesting around that so that the body |
| 1717 // gets nested farther. |
| 1718 if (function.body is! ExpressionFunctionBody) builder.unnest(); |
| 1719 |
| 1720 _visitBody(function.parameters, function.body); |
| 1721 |
| 1722 if (function.body is ExpressionFunctionBody) builder.unnest(); |
| 1723 } |
| 1724 |
1580 /// Visit the given function [parameters] followed by its [body], printing a | 1725 /// Visit the given function [parameters] followed by its [body], printing a |
1581 /// space before it if it's not empty. | 1726 /// space before it if it's not empty. |
1582 /// | 1727 /// |
1583 /// If [afterParameters] is provided, it is invoked between the parameters | 1728 /// If [afterParameters] is provided, it is invoked between the parameters |
1584 /// and body. (It's used for constructor initialization lists.) | 1729 /// and body. (It's used for constructor initialization lists.) |
1585 void _visitBody(FormalParameterList parameters, FunctionBody body, | 1730 void _visitBody(FormalParameterList parameters, FunctionBody body, |
1586 [afterParameters()]) { | 1731 [afterParameters()]) { |
1587 // If the body is "=>", add an extra level of indentation around the | 1732 // If the body is "=>", add an extra level of indentation around the |
1588 // parameters and a rule that spans the parameters and the "=>". This | 1733 // parameters and a rule that spans the parameters and the "=>". This |
1589 // ensures that if the parameters wrap, they wrap more deeply than the "=>" | 1734 // ensures that if the parameters wrap, they wrap more deeply than the "=>" |
(...skipping 14 matching lines...) Expand all Loading... |
1604 // level when they are actually unrelated. Splitting at "=>" forces: | 1749 // level when they are actually unrelated. Splitting at "=>" forces: |
1605 // | 1750 // |
1606 // someFunction(parameter, | 1751 // someFunction(parameter, |
1607 // parameter) => | 1752 // parameter) => |
1608 // function( | 1753 // function( |
1609 // argument); | 1754 // argument); |
1610 if (body is ExpressionFunctionBody) { | 1755 if (body is ExpressionFunctionBody) { |
1611 builder.nestExpression(); | 1756 builder.nestExpression(); |
1612 | 1757 |
1613 // This rule is ended by visitExpressionFunctionBody(). | 1758 // This rule is ended by visitExpressionFunctionBody(). |
1614 builder.startLazyRule(new SimpleRule(cost: Cost.arrow)); | 1759 builder.startLazyRule(new Rule(Cost.arrow)); |
1615 } | 1760 } |
1616 | 1761 |
1617 if (parameters != null) { | 1762 if (parameters != null) { |
1618 builder.nestExpression(); | 1763 builder.nestExpression(); |
| 1764 visit(parameters); |
| 1765 builder.unnest(); |
1619 | 1766 |
1620 visit(parameters); | |
1621 if (afterParameters != null) afterParameters(); | 1767 if (afterParameters != null) afterParameters(); |
1622 | |
1623 builder.unnest(); | |
1624 } | 1768 } |
1625 | 1769 |
1626 visit(body); | 1770 visit(body); |
1627 | 1771 |
1628 if (body is ExpressionFunctionBody) builder.unnest(); | 1772 if (body is ExpressionFunctionBody) builder.unnest(); |
1629 } | 1773 } |
1630 | 1774 |
| 1775 /// Visits the body statement of a `for` or `for in` loop. |
| 1776 void _visitLoopBody(Statement body) { |
| 1777 if (body is EmptyStatement) { |
| 1778 // No space before the ";". |
| 1779 visit(body); |
| 1780 } else if (body is Block) { |
| 1781 space(); |
| 1782 visit(body); |
| 1783 } else { |
| 1784 // Allow splitting in an expression-bodied for even though it's against |
| 1785 // 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. |
| 1787 builder.nestExpression(indent: 2, now: true); |
| 1788 builder.startRule(); |
| 1789 |
| 1790 split(); |
| 1791 visit(body); |
| 1792 |
| 1793 builder.endRule(); |
| 1794 builder.unnest(); |
| 1795 } |
| 1796 } |
| 1797 |
1631 /// Visit a list of [nodes] if not null, optionally separated and/or preceded | 1798 /// Visit a list of [nodes] if not null, optionally separated and/or preceded |
1632 /// and followed by the given functions. | 1799 /// and followed by the given functions. |
1633 void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) { | 1800 void visitNodes(Iterable<AstNode> nodes, {before(), between(), after()}) { |
1634 if (nodes == null || nodes.isEmpty) return; | 1801 if (nodes == null || nodes.isEmpty) return; |
1635 | 1802 |
1636 if (before != null) before(); | 1803 if (before != null) before(); |
1637 | 1804 |
1638 visit(nodes.first); | 1805 visit(nodes.first); |
1639 for (var node in nodes.skip(1)) { | 1806 for (var node in nodes.skip(1)) { |
1640 if (between != null) between(); | 1807 if (between != null) between(); |
(...skipping 26 matching lines...) Expand all Loading... |
1667 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, | 1834 void _visitCollectionLiteral(TypedLiteral node, Token leftBracket, |
1668 Iterable<AstNode> elements, Token rightBracket, | 1835 Iterable<AstNode> elements, Token rightBracket, |
1669 [int cost]) { | 1836 [int cost]) { |
1670 modifier(node.constKeyword); | 1837 modifier(node.constKeyword); |
1671 visit(node.typeArguments); | 1838 visit(node.typeArguments); |
1672 | 1839 |
1673 // Don't allow splitting in an empty collection. | 1840 // Don't allow splitting in an empty collection. |
1674 if (elements.isEmpty && rightBracket.precedingComments == null) { | 1841 if (elements.isEmpty && rightBracket.precedingComments == null) { |
1675 token(leftBracket); | 1842 token(leftBracket); |
1676 token(rightBracket); | 1843 token(rightBracket); |
1677 | |
1678 // Clear this out in case this empty collection is in an argument list. | |
1679 // We don't want this rule to bleed over to some other collection. | |
1680 _nextLiteralBodyRule = null; | |
1681 return; | 1844 return; |
1682 } | 1845 } |
1683 | 1846 |
1684 // Force all of the surrounding collections to split. | 1847 // Force all of the surrounding collections to split. |
1685 for (var i = 0; i < _collectionSplits.length; i++) { | 1848 for (var i = 0; i < _collectionSplits.length; i++) { |
1686 _collectionSplits[i] = true; | 1849 _collectionSplits[i] = true; |
1687 } | 1850 } |
1688 | 1851 |
1689 // Add this collection to the stack. | 1852 // Add this collection to the stack. |
1690 _collectionSplits.add(false); | 1853 _collectionSplits.add(false); |
1691 | 1854 |
1692 _startLiteralBody(leftBracket); | 1855 _startLiteralBody(leftBracket); |
1693 | 1856 |
1694 // Always use a hard rule to split the elements. The parent chunk of | 1857 // Always use a hard rule to split the elements. The parent chunk of |
1695 // the collection will handle the unsplit case, so this only comes | 1858 // the collection will handle the unsplit case, so this only comes |
1696 // into play when the collection is split. | 1859 // into play when the collection is split. |
1697 var rule = new HardSplitRule(); | 1860 var rule = new Rule.hard(); |
1698 builder.startRule(rule); | 1861 builder.startRule(rule); |
1699 | 1862 |
1700 // If a collection contains a line comment, we assume it's a big complex | 1863 // If a collection contains a line comment, we assume it's a big complex |
1701 // blob of data with some documented structure. In that case, the user | 1864 // blob of data with some documented structure. In that case, the user |
1702 // probably broke the elements into lines deliberately, so preserve those. | 1865 // probably broke the elements into lines deliberately, so preserve those. |
1703 var preserveNewlines = _containsLineComments(elements, rightBracket); | 1866 var preserveNewlines = _containsLineComments(elements, rightBracket); |
1704 | 1867 |
1705 for (var element in elements) { | 1868 for (var element in elements) { |
1706 if (element != elements.first) { | 1869 if (element != elements.first) { |
1707 if (preserveNewlines) { | 1870 if (preserveNewlines) { |
1708 if (_endLine(element.beginToken.previous) != | 1871 if (_endLine(element.beginToken.previous) != |
1709 _startLine(element.beginToken)) { | 1872 _startLine(element.beginToken)) { |
1710 oneOrTwoNewlines(); | 1873 oneOrTwoNewlines(); |
1711 } else { | 1874 } else { |
1712 soloSplit(); | 1875 soloSplit(); |
1713 } | 1876 } |
1714 } else { | 1877 } else { |
1715 builder.blockSplit(space: true); | 1878 builder.split(nest: false, space: true); |
1716 } | 1879 } |
1717 } | 1880 } |
1718 | 1881 |
1719 builder.nestExpression(); | 1882 builder.nestExpression(); |
1720 visit(element); | 1883 visit(element); |
1721 | 1884 |
1722 // The comma after the element. | 1885 // The comma after the element. |
1723 if (element.endToken.next.lexeme == ",") token(element.endToken.next); | 1886 if (element.endToken.next.lexeme == ",") token(element.endToken.next); |
1724 | 1887 |
1725 builder.unnest(); | 1888 builder.unnest(); |
1726 } | 1889 } |
1727 | 1890 |
1728 builder.endRule(); | 1891 builder.endRule(); |
1729 | 1892 |
1730 // If there is a collection inside this one, it forces this one to split. | 1893 // If there is a collection inside this one, it forces this one to split. |
1731 var force = _collectionSplits.removeLast(); | 1894 var force = _collectionSplits.removeLast(); |
1732 | 1895 |
1733 _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force); | 1896 _endLiteralBody(rightBracket, ignoredRule: rule, forceSplit: force); |
1734 } | 1897 } |
1735 | 1898 |
| 1899 /// Gets the cost to split at an assignment (or `:` in the case of a named |
| 1900 /// default value) with the given [rightHandSide]. |
| 1901 /// |
| 1902 /// "Block-like" expressions (collections and cascades) bind a bit tighter |
| 1903 /// because it looks better to have code like: |
| 1904 /// |
| 1905 /// var list = [ |
| 1906 /// element, |
| 1907 /// element, |
| 1908 /// element |
| 1909 /// ]; |
| 1910 /// |
| 1911 /// var builder = new SomeBuilderClass() |
| 1912 /// ..method() |
| 1913 /// ..method(); |
| 1914 /// |
| 1915 /// over: |
| 1916 /// |
| 1917 /// var list = |
| 1918 /// [element, element, element]; |
| 1919 /// |
| 1920 /// var builder = |
| 1921 /// new SomeBuilderClass()..method()..method(); |
| 1922 int _assignmentCost(Expression rightHandSide) { |
| 1923 if (rightHandSide is ListLiteral) return Cost.assignBlock; |
| 1924 if (rightHandSide is MapLiteral) return Cost.assignBlock; |
| 1925 if (rightHandSide is CascadeExpression) return Cost.assignBlock; |
| 1926 |
| 1927 return Cost.assign; |
| 1928 } |
| 1929 |
1736 /// Returns `true` if the collection withs [elements] delimited by | 1930 /// Returns `true` if the collection withs [elements] delimited by |
1737 /// [rightBracket] contains any line comments. | 1931 /// [rightBracket] contains any line comments. |
1738 /// | 1932 /// |
1739 /// This only looks for comments at the element boundary. Comments within an | 1933 /// This only looks for comments at the element boundary. Comments within an |
1740 /// element are ignored. | 1934 /// element are ignored. |
1741 bool _containsLineComments(Iterable<AstNode> elements, Token rightBracket) { | 1935 bool _containsLineComments(Iterable<AstNode> elements, Token rightBracket) { |
1742 hasLineCommentBefore(token) { | 1936 hasLineCommentBefore(token) { |
1743 var comment = token.precedingComments; | 1937 var comment = token.precedingComments; |
1744 for (; comment != null; comment = comment.next) { | 1938 for (; comment != null; comment = comment.next) { |
1745 if (comment.type == TokenType.SINGLE_LINE_COMMENT) return true; | 1939 if (comment.type == TokenType.SINGLE_LINE_COMMENT) return true; |
(...skipping 12 matching lines...) Expand all Loading... |
1758 } | 1952 } |
1759 | 1953 |
1760 /// Begins writing a literal body: a collection or block-bodied function | 1954 /// Begins writing a literal body: a collection or block-bodied function |
1761 /// expression. | 1955 /// expression. |
1762 /// | 1956 /// |
1763 /// Writes the delimiter and then creates the [Rule] that handles splitting | 1957 /// Writes the delimiter and then creates the [Rule] that handles splitting |
1764 /// the body. | 1958 /// the body. |
1765 void _startLiteralBody(Token leftBracket) { | 1959 void _startLiteralBody(Token leftBracket) { |
1766 token(leftBracket); | 1960 token(leftBracket); |
1767 | 1961 |
1768 // Split the literal. Use the explicitly given rule if we have one. | 1962 // See if this literal is associated with an argument list that wants to |
1769 // Otherwise, create a new rule. | 1963 // handle splitting and indenting it. If not, we'll use a default rule. |
1770 var rule = _nextLiteralBodyRule; | 1964 var rule; |
1771 _nextLiteralBodyRule = null; | 1965 var argumentChunk; |
| 1966 if (_collectionArgumentLists.containsKey(leftBracket)) { |
| 1967 var argumentList = _collectionArgumentLists[leftBracket]; |
| 1968 rule = argumentList.collectionRule; |
| 1969 argumentChunk = argumentList.previousSplit; |
| 1970 } |
1772 | 1971 |
1773 // Create a rule for whether or not to split the block contents. | 1972 // Create a rule for whether or not to split the block contents. |
1774 builder.startRule(rule); | 1973 builder.startRule(rule); |
1775 | 1974 |
1776 // Process the collection contents as a separate set of chunks. | 1975 // Process the collection contents as a separate set of chunks. |
1777 builder = builder.startBlock(); | 1976 builder = builder.startBlock(argumentChunk); |
1778 } | 1977 } |
1779 | 1978 |
1780 /// Ends the literal body started by a call to [_startLiteralBody()]. | 1979 /// Ends the literal body started by a call to [_startLiteralBody()]. |
1781 /// | 1980 /// |
1782 /// If [forceSplit] is `true`, forces the body to split. If [ignoredRule] is | 1981 /// If [forceSplit] is `true`, forces the body to split. If [ignoredRule] is |
1783 /// given, ignores that rule inside the body when determining if it should | 1982 /// given, ignores that rule inside the body when determining if it should |
1784 /// split. | 1983 /// split. |
1785 void _endLiteralBody(Token rightBracket, | 1984 void _endLiteralBody(Token rightBracket, |
1786 {Rule ignoredRule, bool forceSplit}) { | 1985 {Rule ignoredRule, bool forceSplit}) { |
1787 if (forceSplit == null) forceSplit = false; | 1986 if (forceSplit == null) forceSplit = false; |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1827 void _simpleStatement(AstNode node, body()) { | 2026 void _simpleStatement(AstNode node, body()) { |
1828 builder.nestExpression(); | 2027 builder.nestExpression(); |
1829 body(); | 2028 body(); |
1830 | 2029 |
1831 // TODO(rnystrom): Can the analyzer move "semicolon" to some shared base | 2030 // TODO(rnystrom): Can the analyzer move "semicolon" to some shared base |
1832 // type? | 2031 // type? |
1833 token((node as dynamic).semicolon); | 2032 token((node as dynamic).semicolon); |
1834 builder.unnest(); | 2033 builder.unnest(); |
1835 } | 2034 } |
1836 | 2035 |
1837 /// Makes [rule] the rule that will be used for the contents of a collection | 2036 /// Marks the collection literal that starts with [leftBracket] as being |
1838 /// or function literal body that are about to be visited. | 2037 /// controlled by [argumentList]. |
1839 void setNextLiteralBodyRule(Rule rule) { | 2038 /// |
1840 _nextLiteralBodyRule = rule; | 2039 /// When the collection is visited, [argumentList] will determine the |
| 2040 /// indentation and splitting rule for the collection. |
| 2041 void beforeCollection(Token leftBracket, ArgumentSublist argumentList) { |
| 2042 _collectionArgumentLists[leftBracket] = argumentList; |
1841 } | 2043 } |
1842 | 2044 |
1843 /// Writes an bracket-delimited body and handles indenting and starting the | 2045 /// Writes an bracket-delimited body and handles indenting and starting the |
1844 /// rule used to split the contents. | 2046 /// rule used to split the contents. |
1845 /// | 2047 /// |
1846 /// If [space] is `true`, then the contents and delimiters will have a space | 2048 /// If [space] is `true`, then the contents and delimiters will have a space |
1847 /// between then when unsplit. | 2049 /// between then when unsplit. |
1848 void _writeBody(Token leftBracket, Token rightBracket, | 2050 void _writeBody(Token leftBracket, Token rightBracket, |
1849 {bool space: false, body()}) { | 2051 {bool space: false, body()}) { |
1850 token(leftBracket); | 2052 token(leftBracket); |
1851 | 2053 |
1852 // Indent the body. | 2054 // Indent the body. |
1853 builder.indent(); | 2055 builder.indent(); |
1854 | 2056 |
1855 // Split after the bracket. | 2057 // Split after the bracket. |
1856 builder.startRule(); | 2058 builder.startRule(); |
1857 builder.blockSplit(space: space, isDouble: false); | 2059 builder.split(isDouble: false, nest: false, space: space); |
1858 | 2060 |
1859 body(); | 2061 body(); |
1860 | 2062 |
1861 token(rightBracket, before: () { | 2063 token(rightBracket, before: () { |
1862 // Split before the closing bracket character. | 2064 // Split before the closing bracket character. |
1863 builder.unindent(); | 2065 builder.unindent(); |
1864 builder.blockSplit(space: space); | 2066 builder.split(nest: false, space: space); |
1865 }); | 2067 }); |
1866 | 2068 |
1867 builder.endRule(); | 2069 builder.endRule(); |
1868 } | 2070 } |
1869 | 2071 |
1870 /// Returns `true` if [node] is immediately contained within an anonymous | 2072 /// Returns `true` if [node] is immediately contained within an anonymous |
1871 /// [FunctionExpression]. | 2073 /// [FunctionExpression]. |
1872 bool _isInLambda(AstNode node) => node.parent is FunctionExpression && | 2074 bool _isInLambda(AstNode node) => |
| 2075 node.parent is FunctionExpression && |
1873 node.parent.parent is! FunctionDeclaration; | 2076 node.parent.parent is! FunctionDeclaration; |
1874 | 2077 |
1875 /// Writes the string literal [string] to the output. | 2078 /// Writes the string literal [string] to the output. |
1876 /// | 2079 /// |
1877 /// Splits multiline strings into separate chunks so that the line splitter | 2080 /// Splits multiline strings into separate chunks so that the line splitter |
1878 /// can handle them correctly. | 2081 /// can handle them correctly. |
1879 void _writeStringLiteral(String string, int offset) { | 2082 void _writeStringLiteral(String string, int offset) { |
1880 // Split each line of a multiline string into separate chunks. | 2083 // Split each line of a multiline string into separate chunks. |
1881 var lines = string.split(_formatter.lineEnding); | 2084 var lines = string.split(_formatter.lineEnding); |
1882 | 2085 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1938 /// Returns the chunk the split was applied to. | 2141 /// Returns the chunk the split was applied to. |
1939 Chunk split() => builder.split(space: true); | 2142 Chunk split() => builder.split(space: true); |
1940 | 2143 |
1941 /// Writes a zero-space split owned by the current rule. | 2144 /// Writes a zero-space split owned by the current rule. |
1942 /// | 2145 /// |
1943 /// Returns the chunk the split was applied to. | 2146 /// Returns the chunk the split was applied to. |
1944 Chunk zeroSplit() => builder.split(); | 2147 Chunk zeroSplit() => builder.split(); |
1945 | 2148 |
1946 /// Writes a single space split with its own rule. | 2149 /// Writes a single space split with its own rule. |
1947 void soloSplit([int cost]) { | 2150 void soloSplit([int cost]) { |
1948 builder.startRule(new SimpleRule(cost: cost)); | 2151 builder.startRule(new Rule(cost)); |
1949 split(); | 2152 split(); |
1950 builder.endRule(); | 2153 builder.endRule(); |
1951 } | 2154 } |
1952 | 2155 |
1953 /// Writes a zero-space split with its own rule. | 2156 /// Writes a zero-space split with its own rule. |
1954 void soloZeroSplit() { | 2157 void soloZeroSplit() { |
1955 builder.startRule(); | 2158 builder.startRule(); |
1956 builder.split(); | 2159 builder.split(); |
1957 builder.endRule(); | 2160 builder.endRule(); |
1958 } | 2161 } |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2159 /// Gets the 1-based line number that the beginning of [token] lies on. | 2362 /// Gets the 1-based line number that the beginning of [token] lies on. |
2160 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; | 2363 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; |
2161 | 2364 |
2162 /// Gets the 1-based line number that the end of [token] lies on. | 2365 /// Gets the 1-based line number that the end of [token] lies on. |
2163 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; | 2366 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; |
2164 | 2367 |
2165 /// Gets the 1-based column number that the beginning of [token] lies on. | 2368 /// Gets the 1-based column number that the beginning of [token] lies on. |
2166 int _startColumn(Token token) => | 2369 int _startColumn(Token token) => |
2167 _lineInfo.getLocation(token.offset).columnNumber; | 2370 _lineInfo.getLocation(token.offset).columnNumber; |
2168 } | 2371 } |
OLD | NEW |