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/dart/ast/token.dart'; | 8 import 'package:analyzer/dart/ast/token.dart'; |
9 import 'package:analyzer/src/generated/source.dart'; | 9 import 'package:analyzer/src/generated/source.dart'; |
10 | 10 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 /// | 126 /// |
127 /// This is a bit complex to handle the rules for formatting positional and | 127 /// This is a bit complex to handle the rules for formatting positional and |
128 /// named arguments. The goals, in rough order of descending priority are: | 128 /// named arguments. The goals, in rough order of descending priority are: |
129 /// | 129 /// |
130 /// 1. Keep everything on the first line. | 130 /// 1. Keep everything on the first line. |
131 /// 2. Keep the named arguments together on the next line. | 131 /// 2. Keep the named arguments together on the next line. |
132 /// 3. Keep everything together on the second line. | 132 /// 3. Keep everything together on the second line. |
133 /// 4. Split between one or more positional arguments, trying to keep as many | 133 /// 4. Split between one or more positional arguments, trying to keep as many |
134 /// on earlier lines as possible. | 134 /// on earlier lines as possible. |
135 /// 5. Split the named arguments each onto their own line. | 135 /// 5. Split the named arguments each onto their own line. |
136 visitArgumentList(ArgumentList node) { | 136 visitArgumentList(ArgumentList node, {bool nestExpression: true}) { |
137 // Corner case: handle empty argument lists. | 137 // Corner case: handle empty argument lists. |
138 if (node.arguments.isEmpty) { | 138 if (node.arguments.isEmpty) { |
139 token(node.leftParenthesis); | 139 token(node.leftParenthesis); |
140 | 140 |
141 // If there is a comment inside the parens, do allow splitting before it. | 141 // If there is a comment inside the parens, do allow splitting before it. |
142 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); | 142 if (node.rightParenthesis.precedingComments != null) soloZeroSplit(); |
143 | 143 |
144 token(node.rightParenthesis); | 144 token(node.rightParenthesis); |
145 return; | 145 return; |
146 } | 146 } |
147 | 147 |
148 // If the argument list has a trailing comma, format it like a collection | 148 // If the argument list has a trailing comma, format it like a collection |
149 // literal where each argument goes on its own line, they are indented +2, | 149 // literal where each argument goes on its own line, they are indented +2, |
150 // and the ")" ends up on its own line. | 150 // and the ")" ends up on its own line. |
151 if (node.arguments.last.endToken.next.type == TokenType.COMMA) { | 151 if (node.arguments.last.endToken.next.type == TokenType.COMMA) { |
152 _visitCollectionLiteral( | 152 _visitCollectionLiteral( |
153 null, node.leftParenthesis, node.arguments, node.rightParenthesis); | 153 null, node.leftParenthesis, node.arguments, node.rightParenthesis); |
154 return; | 154 return; |
155 } | 155 } |
156 | 156 |
| 157 if (nestExpression) builder.nestExpression(); |
157 new ArgumentListVisitor(this, node).visit(); | 158 new ArgumentListVisitor(this, node).visit(); |
| 159 if (nestExpression) builder.unnest(); |
158 } | 160 } |
159 | 161 |
160 visitAsExpression(AsExpression node) { | 162 visitAsExpression(AsExpression node) { |
161 builder.startSpan(); | 163 builder.startSpan(); |
162 builder.nestExpression(); | 164 builder.nestExpression(); |
163 visit(node.expression); | 165 visit(node.expression); |
164 soloSplit(); | 166 soloSplit(); |
165 token(node.asOperator); | 167 token(node.asOperator); |
166 space(); | 168 space(); |
167 visit(node.type); | 169 visit(node.type); |
168 builder.unnest(); | 170 builder.unnest(); |
169 builder.endSpan(); | 171 builder.endSpan(); |
170 } | 172 } |
171 | 173 |
172 // TODO(rnystrom): Type annotate once analyzer publishes a version with the | 174 // TODO(rnystrom): Type annotate once analyzer publishes a version with the |
173 // new AST type. | 175 // new AST type. |
174 // TODO(rnystrom): Test. | 176 // TODO(rnystrom): Test. |
175 visitAssertInitializer(node) { | 177 visitAssertInitializer(node) { |
176 _simpleStatement(node, () { | 178 _simpleStatement(node, () { |
177 token(node.assertKeyword); | 179 token(node.assertKeyword); |
178 | 180 |
179 var arguments = <Expression>[node.condition]; | 181 var arguments = <Expression>[node.condition]; |
180 if (node.message != null) arguments.add(node.message); | 182 if (node.message != null) arguments.add(node.message); |
181 | 183 |
| 184 builder.nestExpression(); |
182 var visitor = new ArgumentListVisitor.forArguments( | 185 var visitor = new ArgumentListVisitor.forArguments( |
183 this, node.leftParenthesis, node.rightParenthesis, arguments); | 186 this, node.leftParenthesis, node.rightParenthesis, arguments); |
184 visitor.visit(); | 187 visitor.visit(); |
| 188 builder.unnest(); |
185 }); | 189 }); |
186 } | 190 } |
187 | 191 |
188 visitAssertStatement(AssertStatement node) { | 192 visitAssertStatement(AssertStatement node) { |
189 _simpleStatement(node, () { | 193 _simpleStatement(node, () { |
190 token(node.assertKeyword); | 194 token(node.assertKeyword); |
191 | 195 |
192 var arguments = [node.condition]; | 196 var arguments = [node.condition]; |
193 if (node.message != null) arguments.add(node.message); | 197 if (node.message != null) arguments.add(node.message); |
194 | 198 |
(...skipping 1018 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1213 visit(node.index); | 1217 visit(node.index); |
1214 token(node.rightBracket); | 1218 token(node.rightBracket); |
1215 builder.endSpan(); | 1219 builder.endSpan(); |
1216 } | 1220 } |
1217 | 1221 |
1218 visitInstanceCreationExpression(InstanceCreationExpression node) { | 1222 visitInstanceCreationExpression(InstanceCreationExpression node) { |
1219 builder.startSpan(); | 1223 builder.startSpan(); |
1220 token(node.keyword); | 1224 token(node.keyword); |
1221 space(); | 1225 space(); |
1222 builder.startSpan(Cost.constructorName); | 1226 builder.startSpan(Cost.constructorName); |
| 1227 |
| 1228 // Start the expression nesting for the argument list here, in case this |
| 1229 // is a generic constructor with type arguments. If it is, we need the type |
| 1230 // arguments to be nested too so they get indented past the arguments. |
| 1231 builder.nestExpression(); |
1223 visit(node.constructorName); | 1232 visit(node.constructorName); |
| 1233 |
1224 builder.endSpan(); | 1234 builder.endSpan(); |
1225 visit(node.argumentList); | 1235 visitArgumentList(node.argumentList, nestExpression: false); |
1226 builder.endSpan(); | 1236 builder.endSpan(); |
| 1237 |
| 1238 builder.unnest(); |
1227 } | 1239 } |
1228 | 1240 |
1229 visitIntegerLiteral(IntegerLiteral node) { | 1241 visitIntegerLiteral(IntegerLiteral node) { |
1230 token(node.literal); | 1242 token(node.literal); |
1231 } | 1243 } |
1232 | 1244 |
1233 visitInterpolationExpression(InterpolationExpression node) { | 1245 visitInterpolationExpression(InterpolationExpression node) { |
1234 token(node.leftBracket); | 1246 token(node.leftBracket); |
1235 visit(node.expression); | 1247 visit(node.expression); |
1236 token(node.rightBracket); | 1248 token(node.rightBracket); |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1308 visitMethodInvocation(MethodInvocation node) { | 1320 visitMethodInvocation(MethodInvocation node) { |
1309 // If there's no target, this is a "bare" function call like "foo(1, 2)", | 1321 // If there's no target, this is a "bare" function call like "foo(1, 2)", |
1310 // or a section in a cascade. Handle this case specially. | 1322 // or a section in a cascade. Handle this case specially. |
1311 if (node.target == null) { | 1323 if (node.target == null) { |
1312 // Try to keep the entire method invocation one line. | 1324 // Try to keep the entire method invocation one line. |
1313 builder.startSpan(); | 1325 builder.startSpan(); |
1314 builder.nestExpression(); | 1326 builder.nestExpression(); |
1315 | 1327 |
1316 // This will be non-null for cascade sections. | 1328 // This will be non-null for cascade sections. |
1317 token(node.operator); | 1329 token(node.operator); |
1318 token(node.methodName.token); | 1330 visit(node.methodName); |
1319 visit(node.argumentList); | 1331 |
| 1332 // TODO(rnystrom): Currently, there are no constraints between a generic |
| 1333 // method's type arguments and arguments. That can lead to some funny |
| 1334 // splitting like: |
| 1335 // |
| 1336 // method<VeryLongType, |
| 1337 // AnotherTypeArgument>(argument, |
| 1338 // argument, argument, argument); |
| 1339 // |
| 1340 // The indentation is fine, but splitting in the middle of each argument |
| 1341 // list looks kind of strange. If this ends up happening in real world |
| 1342 // code, consider putting a constraint between them. |
| 1343 |
| 1344 visit(node.typeArguments); |
| 1345 visitArgumentList(node.argumentList, nestExpression: false); |
1320 | 1346 |
1321 builder.unnest(); | 1347 builder.unnest(); |
1322 builder.endSpan(); | 1348 builder.endSpan(); |
1323 return; | 1349 return; |
1324 } | 1350 } |
1325 | 1351 |
1326 new CallChainVisitor(this, node).visit(); | 1352 new CallChainVisitor(this, node).visit(); |
1327 } | 1353 } |
1328 | 1354 |
1329 visitNamedExpression(NamedExpression node) { | 1355 visitNamedExpression(NamedExpression node) { |
(...skipping 1264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2594 /// Gets the 1-based line number that the beginning of [token] lies on. | 2620 /// Gets the 1-based line number that the beginning of [token] lies on. |
2595 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; | 2621 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; |
2596 | 2622 |
2597 /// Gets the 1-based line number that the end of [token] lies on. | 2623 /// Gets the 1-based line number that the end of [token] lies on. |
2598 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; | 2624 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; |
2599 | 2625 |
2600 /// Gets the 1-based column number that the beginning of [token] lies on. | 2626 /// Gets the 1-based column number that the beginning of [token] lies on. |
2601 int _startColumn(Token token) => | 2627 int _startColumn(Token token) => |
2602 _lineInfo.getLocation(token.offset).columnNumber; | 2628 _lineInfo.getLocation(token.offset).columnNumber; |
2603 } | 2629 } |
OLD | NEW |