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 24 matching lines...) Expand all Loading... | |
52 /// Each entry corresponds to a collection currently being visited and the | 53 /// Each entry corresponds to a collection currently being visited and the |
53 /// 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 |
54 /// 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` |
55 /// then it pushes `false` for itself. | 56 /// then it pushes `false` for itself. |
56 /// | 57 /// |
57 /// 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 |
58 /// `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 |
59 /// split. | 60 /// split. |
60 final List<bool> _collectionSplits = []; | 61 final List<bool> _collectionSplits = []; |
61 | 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 | |
62 /// The mapping for collection literals that are managed by the argument | 71 /// The mapping for collection literals that are managed by the argument |
63 /// list that contains them. | 72 /// list that contains them. |
64 /// | 73 /// |
65 /// When a collection literal appears inside an [ArgumentSublist], the | 74 /// When a collection literal appears inside an [ArgumentSublist], the |
66 /// argument list provides a rule for the body to split to ensure that all | 75 /// argument list provides a rule for the body to split to ensure that all |
67 /// collections split in unison. It also tracks the chunk before the | 76 /// collections split in unison. It also tracks the chunk before the |
68 /// argument that determines whether or not the collection body is indented | 77 /// argument that determines whether or not the collection body is indented |
69 /// like an expression or a statement. | 78 /// like an expression or a statement. |
70 /// | 79 /// |
71 /// Before a collection literal argument is visited, [ArgumentSublist] binds | 80 /// Before a collection literal argument is visited, [ArgumentSublist] binds |
(...skipping 710 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
782 var requiredParams = node.parameters | 791 var requiredParams = node.parameters |
783 .where((param) => param is! DefaultFormalParameter) | 792 .where((param) => param is! DefaultFormalParameter) |
784 .toList(); | 793 .toList(); |
785 var optionalParams = node.parameters | 794 var optionalParams = node.parameters |
786 .where((param) => param is DefaultFormalParameter) | 795 .where((param) => param is DefaultFormalParameter) |
787 .toList(); | 796 .toList(); |
788 | 797 |
789 builder.nestExpression(); | 798 builder.nestExpression(); |
790 token(node.leftParenthesis); | 799 token(node.leftParenthesis); |
791 | 800 |
801 _metadataRules.add(new MetadataRule()); | |
802 | |
792 var rule; | 803 var rule; |
793 if (requiredParams.isNotEmpty) { | 804 if (requiredParams.isNotEmpty) { |
794 if (requiredParams.length > 1) { | 805 if (requiredParams.length > 1) { |
795 rule = new MultiplePositionalRule(null, 0, 0); | 806 rule = new MultiplePositionalRule(null, 0, 0); |
796 } else { | 807 } else { |
797 rule = new SinglePositionalRule(null); | 808 rule = new SinglePositionalRule(null); |
798 } | 809 } |
799 | 810 |
811 _metadataRules.last.bindPositionalRule(rule); | |
812 | |
800 builder.startRule(rule); | 813 builder.startRule(rule); |
801 if (_isInLambda(node)) { | 814 if (_isInLambda(node)) { |
802 // Don't allow splitting before the first argument (i.e. right after | 815 // Don't allow splitting before the first argument (i.e. right after |
803 // the bare "(" in a lambda. Instead, just stuff a null chunk in there | 816 // the bare "(" in a lambda. Instead, just stuff a null chunk in there |
804 // to avoid confusing the arg rule. | 817 // to avoid confusing the arg rule. |
805 rule.beforeArgument(null); | 818 rule.beforeArgument(null); |
806 } else { | 819 } else { |
807 // Split before the first argument. | 820 // Split before the first argument. |
808 rule.beforeArgument(zeroSplit()); | 821 rule.beforeArgument(zeroSplit()); |
809 } | 822 } |
(...skipping 10 matching lines...) Expand all Loading... | |
820 } | 833 } |
821 | 834 |
822 builder.endSpan(); | 835 builder.endSpan(); |
823 builder.endRule(); | 836 builder.endRule(); |
824 } | 837 } |
825 | 838 |
826 if (optionalParams.isNotEmpty) { | 839 if (optionalParams.isNotEmpty) { |
827 var namedRule = new NamedRule(); | 840 var namedRule = new NamedRule(); |
828 if (rule != null) rule.setNamedArgsRule(namedRule); | 841 if (rule != null) rule.setNamedArgsRule(namedRule); |
829 | 842 |
843 _metadataRules.last.bindNamedRule(namedRule); | |
844 | |
830 builder.startRule(namedRule); | 845 builder.startRule(namedRule); |
831 | 846 |
832 // Make sure multi-line default values are indented. | 847 // Make sure multi-line default values are indented. |
833 builder.startBlockArgumentNesting(); | 848 builder.startBlockArgumentNesting(); |
834 | 849 |
835 namedRule | 850 namedRule |
836 .beforeArguments(builder.split(space: requiredParams.isNotEmpty)); | 851 .beforeArguments(builder.split(space: requiredParams.isNotEmpty)); |
837 | 852 |
838 // "[" or "{" for optional parameters. | 853 // "[" or "{" for optional parameters. |
839 token(node.leftDelimiter); | 854 token(node.leftDelimiter); |
840 | 855 |
841 for (var param in optionalParams) { | 856 for (var param in optionalParams) { |
842 visit(param); | 857 visit(param); |
843 | 858 |
844 // Write the trailing comma. | 859 // Write the trailing comma. |
845 if (param != node.parameters.last) token(param.endToken.next); | 860 if (param != node.parameters.last) token(param.endToken.next); |
846 if (param != optionalParams.last) split(); | 861 if (param != optionalParams.last) split(); |
847 } | 862 } |
848 | 863 |
849 builder.endBlockArgumentNesting(); | 864 builder.endBlockArgumentNesting(); |
850 builder.endRule(); | 865 builder.endRule(); |
851 | 866 |
852 // "]" or "}" for optional parameters. | 867 // "]" or "}" for optional parameters. |
853 token(node.rightDelimiter); | 868 token(node.rightDelimiter); |
854 } | 869 } |
855 | 870 |
871 _metadataRules.removeLast(); | |
872 | |
856 token(node.rightParenthesis); | 873 token(node.rightParenthesis); |
857 builder.unnest(); | 874 builder.unnest(); |
858 } | 875 } |
859 | 876 |
860 visitForStatement(ForStatement node) { | 877 visitForStatement(ForStatement node) { |
861 builder.nestExpression(); | 878 builder.nestExpression(); |
862 token(node.forKeyword); | 879 token(node.forKeyword); |
863 space(); | 880 space(); |
864 token(node.leftParenthesis); | 881 token(node.leftParenthesis); |
865 | 882 |
(...skipping 592 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1458 | 1475 |
1459 visitTypeParameter(TypeParameter node) { | 1476 visitTypeParameter(TypeParameter node) { |
1460 visitParameterMetadata(node.metadata, () { | 1477 visitParameterMetadata(node.metadata, () { |
1461 visit(node.name); | 1478 visit(node.name); |
1462 token(node.extendsKeyword, before: space, after: space); | 1479 token(node.extendsKeyword, before: space, after: space); |
1463 visit(node.bound); | 1480 visit(node.bound); |
1464 }); | 1481 }); |
1465 } | 1482 } |
1466 | 1483 |
1467 visitTypeParameterList(TypeParameterList node) { | 1484 visitTypeParameterList(TypeParameterList node) { |
1485 _metadataRules.add(new MetadataRule()); | |
1486 | |
1468 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); | 1487 _visitGenericList(node.leftBracket, node.rightBracket, node.typeParameters); |
1488 | |
1489 _metadataRules.removeLast(); | |
1469 } | 1490 } |
1470 | 1491 |
1471 visitVariableDeclaration(VariableDeclaration node) { | 1492 visitVariableDeclaration(VariableDeclaration node) { |
1472 visit(node.name); | 1493 visit(node.name); |
1473 if (node.initializer == null) return; | 1494 if (node.initializer == null) return; |
1474 | 1495 |
1475 _visitAssignment(node.equals, node.initializer); | 1496 _visitAssignment(node.equals, node.initializer); |
1476 } | 1497 } |
1477 | 1498 |
1478 visitVariableDeclarationList(VariableDeclarationList node) { | 1499 visitVariableDeclarationList(VariableDeclarationList node) { |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1563 } else { | 1584 } else { |
1564 visitNodes(metadata, between: space, after: spaceOrNewline); | 1585 visitNodes(metadata, between: space, after: spaceOrNewline); |
1565 } | 1586 } |
1566 } | 1587 } |
1567 | 1588 |
1568 /// Visits metadata annotations on parameters and type parameters. | 1589 /// Visits metadata annotations on parameters and type parameters. |
1569 /// | 1590 /// |
1570 /// These are always on the same line as the parameter. | 1591 /// These are always on the same line as the parameter. |
1571 void visitParameterMetadata( | 1592 void visitParameterMetadata( |
1572 NodeList<Annotation> metadata, void visitParameter()) { | 1593 NodeList<Annotation> metadata, void visitParameter()) { |
1594 if (metadata == null || metadata.isEmpty) { | |
1595 visitParameter(); | |
1596 return; | |
1597 } | |
1598 | |
1573 // Split before all of the annotations or none. | 1599 // Split before all of the annotations or none. |
1574 builder.startRule(); | 1600 builder.startLazyRule(_metadataRules.last); |
1575 visitNodes(metadata, between: split, after: split); | 1601 |
1602 visitNodes(metadata, between: split, after: () { | |
1603 // Don't nest until right before the last metadata. Ensures we only | |
1604 // indent the parameter and not any of the metadata: | |
1605 // | |
1606 // function( | |
1607 // @LongAnnotation | |
1608 // @LongAnnotation | |
1609 // indentedParameter) {} | |
1610 builder.nestExpression(now: true); | |
1611 split(); | |
1612 }); | |
1576 visitParameter(); | 1613 visitParameter(); |
1577 | 1614 |
1615 builder.unnest(); | |
1616 | |
1578 // Wrap the rule around the parameter too. If it splits, we want to force | 1617 // Wrap the rule around the parameter too. If it splits, we want to force |
1579 // the annotations to split as well. | 1618 // the annotations to split as well. |
1580 builder.endRule(); | 1619 builder.endRule(); |
1581 } | 1620 } |
1582 | 1621 |
1583 /// Visits the `=` and the following expression in any place where an `=` | 1622 /// Visits the `=` and the following expression in any place where an `=` |
1584 /// appears: | 1623 /// appears: |
1585 /// | 1624 /// |
1586 /// * Assignment | 1625 /// * Assignment |
1587 /// * Variable declaration | 1626 /// * Variable declaration |
1588 /// * Constructor initialization | 1627 /// * Constructor initialization |
1589 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { | 1628 void _visitAssignment(Token equalsOperator, Expression rightHandSide) { |
1590 space(); | 1629 space(); |
1591 token(equalsOperator); | 1630 token(equalsOperator); |
1592 soloSplit(_assignmentCost(rightHandSide)); | 1631 soloSplit(_assignmentCost(rightHandSide)); |
1593 builder.startSpan(); | 1632 builder.startSpan(); |
1594 visit(rightHandSide); | 1633 visit(rightHandSide); |
1595 builder.endSpan(); | 1634 builder.endSpan(); |
1596 } | 1635 } |
1597 | 1636 |
1598 /// Visits a type parameter or type argument list. | 1637 /// Visits a type parameter or type argument list. |
1599 void _visitGenericList( | 1638 void _visitGenericList( |
1600 Token leftBracket, Token rightBracket, List<AstNode> nodes) { | 1639 Token leftBracket, Token rightBracket, List<AstNode> nodes) { |
1601 var rule = new TypeArgumentRule(); | 1640 var rule = new TypeArgumentRule(); |
1602 builder.startRule(rule); | 1641 builder.startRule(rule); |
1603 builder.startSpan(); | 1642 builder.startSpan(); |
1604 builder.nestExpression(); | 1643 builder.nestExpression(); |
1605 | 1644 |
1645 // TODO(rnystrom): Should the MetadataRule constrain a TypeArgumentRule | |
1646 // as well? | |
nweiz
2015/11/30 19:17:01
The doc comment for MetadataRule implies that it d
Bob Nystrom
2015/11/30 21:36:14
Done.
| |
1647 | |
1606 token(leftBracket); | 1648 token(leftBracket); |
1607 rule.beforeArgument(zeroSplit()); | 1649 rule.beforeArgument(zeroSplit()); |
1608 | 1650 |
1609 for (var node in nodes) { | 1651 for (var node in nodes) { |
1610 visit(node); | 1652 visit(node); |
1611 | 1653 |
1612 // Write the trailing comma. | 1654 // Write the trailing comma. |
1613 if (node != nodes.last) { | 1655 if (node != nodes.last) { |
1614 token(node.endToken.next); | 1656 token(node.endToken.next); |
1615 rule.beforeArgument(split()); | 1657 rule.beforeArgument(split()); |
(...skipping 677 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2293 /// Gets the 1-based line number that the beginning of [token] lies on. | 2335 /// Gets the 1-based line number that the beginning of [token] lies on. |
2294 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; | 2336 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; |
2295 | 2337 |
2296 /// Gets the 1-based line number that the end of [token] lies on. | 2338 /// Gets the 1-based line number that the end of [token] lies on. |
2297 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; | 2339 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; |
2298 | 2340 |
2299 /// Gets the 1-based column number that the beginning of [token] lies on. | 2341 /// Gets the 1-based column number that the beginning of [token] lies on. |
2300 int _startColumn(Token token) => | 2342 int _startColumn(Token token) => |
2301 _lineInfo.getLocation(token.offset).columnNumber; | 2343 _lineInfo.getLocation(token.offset).columnNumber; |
2302 } | 2344 } |
OLD | NEW |