Chromium Code Reviews| 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 |