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 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 | 246 |
247 visitBlock(Block node) { | 247 visitBlock(Block node) { |
248 // Don't allow splitting in an empty block. | 248 // Don't allow splitting in an empty block. |
249 if (node.statements.isEmpty && | 249 if (node.statements.isEmpty && |
250 node.rightBracket.precedingComments == null) { | 250 node.rightBracket.precedingComments == null) { |
251 token(node.leftBracket); | 251 token(node.leftBracket); |
252 token(node.rightBracket); | 252 token(node.rightBracket); |
253 return; | 253 return; |
254 } | 254 } |
255 | 255 |
256 // For a block that is not a function body, just bump the indentation and | 256 // If the block is a function body, it may get expression-level indentation, |
257 // keep it in the current block. | 257 // so handle it specially. Otherwise, just bump the indentation and keep it |
258 if (node.parent is! BlockFunctionBody) { | 258 // in the current block. |
259 _writeBody(node.leftBracket, node.rightBracket, body: () { | 259 if (node.parent is BlockFunctionBody) { |
260 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); | 260 _startLiteralBody(node.leftBracket); |
261 }); | 261 } else { |
262 return; | 262 _beginBody(node.leftBracket); |
263 } | 263 } |
264 | 264 |
265 _startLiteralBody(node.leftBracket); | 265 var needsDouble = true; |
266 visitNodes(node.statements, between: oneOrTwoNewlines, after: newline); | 266 for (var statement in node.statements) { |
267 _endLiteralBody(node.rightBracket, forceSplit: node.statements.isNotEmpty); | 267 if (needsDouble) { |
| 268 twoNewlines(); |
| 269 } else { |
| 270 oneOrTwoNewlines(); |
| 271 } |
| 272 |
| 273 visit(statement); |
| 274 |
| 275 needsDouble = false; |
| 276 if (statement is FunctionDeclarationStatement) { |
| 277 // Add a blank line after non-empty block functions. |
| 278 var body = statement.functionDeclaration.functionExpression.body; |
| 279 if (body is BlockFunctionBody) { |
| 280 needsDouble = body.block.statements.isNotEmpty; |
| 281 } |
| 282 } |
| 283 } |
| 284 |
| 285 if (node.statements.isNotEmpty) newline(); |
| 286 |
| 287 if (node.parent is BlockFunctionBody) { |
| 288 _endLiteralBody(node.rightBracket, |
| 289 forceSplit: node.statements.isNotEmpty); |
| 290 } else { |
| 291 _endBody(node.rightBracket); |
| 292 } |
268 } | 293 } |
269 | 294 |
270 visitBlockFunctionBody(BlockFunctionBody node) { | 295 visitBlockFunctionBody(BlockFunctionBody node) { |
271 // Space after the parameter list. | 296 // Space after the parameter list. |
272 space(); | 297 space(); |
273 | 298 |
274 // The "async" or "sync" keyword. | 299 // The "async" or "sync" keyword. |
275 token(node.keyword); | 300 token(node.keyword); |
276 | 301 |
277 // The "*" in "async*" or "sync*". | 302 // The "*" in "async*" or "sync*". |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 | 424 |
400 builder.startRule(new CombinatorRule()); | 425 builder.startRule(new CombinatorRule()); |
401 visit(node.withClause); | 426 visit(node.withClause); |
402 visit(node.implementsClause); | 427 visit(node.implementsClause); |
403 builder.endRule(); | 428 builder.endRule(); |
404 | 429 |
405 visit(node.nativeClause, before: space); | 430 visit(node.nativeClause, before: space); |
406 space(); | 431 space(); |
407 | 432 |
408 builder.unnest(); | 433 builder.unnest(); |
409 _writeBody(node.leftBracket, node.rightBracket, body: () { | 434 _beginBody(node.leftBracket); |
410 if (node.members.isNotEmpty) { | |
411 for (var member in node.members) { | |
412 visit(member); | |
413 | 435 |
414 if (member == node.members.last) { | 436 if (node.members.isNotEmpty) { |
415 newline(); | 437 for (var member in node.members) { |
416 break; | 438 visit(member); |
417 } | |
418 | 439 |
419 var needsDouble = false; | 440 if (member == node.members.last) { |
420 if (member is ClassDeclaration) { | 441 newline(); |
421 // Add a blank line after classes. | 442 break; |
422 twoNewlines(); | 443 } |
423 } else if (member is MethodDeclaration) { | |
424 // Add a blank line after non-empty block methods. | |
425 if (member.body is BlockFunctionBody) { | |
426 var body = member.body as BlockFunctionBody; | |
427 needsDouble = body.block.statements.isNotEmpty; | |
428 } | |
429 } | |
430 | 444 |
431 if (needsDouble) { | 445 var needsDouble = false; |
432 twoNewlines(); | 446 if (member is ClassDeclaration) { |
433 } else { | 447 // Add a blank line after classes. |
434 // Variables and arrow-bodied members can be more tightly packed if | 448 twoNewlines(); |
435 // the user wants to group things together. | 449 } else if (member is MethodDeclaration) { |
436 oneOrTwoNewlines(); | 450 // Add a blank line after non-empty block methods. |
| 451 if (member.body is BlockFunctionBody) { |
| 452 var body = member.body as BlockFunctionBody; |
| 453 needsDouble = body.block.statements.isNotEmpty; |
437 } | 454 } |
438 } | 455 } |
| 456 |
| 457 if (needsDouble) { |
| 458 twoNewlines(); |
| 459 } else { |
| 460 // Variables and arrow-bodied members can be more tightly packed if |
| 461 // the user wants to group things together. |
| 462 oneOrTwoNewlines(); |
| 463 } |
439 } | 464 } |
440 }); | 465 } |
| 466 |
| 467 _endBody(node.rightBracket); |
441 } | 468 } |
442 | 469 |
443 visitClassTypeAlias(ClassTypeAlias node) { | 470 visitClassTypeAlias(ClassTypeAlias node) { |
444 visitMetadata(node.metadata); | 471 visitMetadata(node.metadata); |
445 | 472 |
446 _simpleStatement(node, () { | 473 _simpleStatement(node, () { |
447 modifier(node.abstractKeyword); | 474 modifier(node.abstractKeyword); |
448 token(node.typedefKeyword); | 475 token(node.typedefKeyword); |
449 space(); | 476 space(); |
450 visit(node.name); | 477 visit(node.name); |
(...skipping 22 matching lines...) Expand all Loading... |
473 var directives = node.directives; | 500 var directives = node.directives; |
474 if (directives.isNotEmpty && directives.first is LibraryDirective) { | 501 if (directives.isNotEmpty && directives.first is LibraryDirective) { |
475 visit(directives.first); | 502 visit(directives.first); |
476 twoNewlines(); | 503 twoNewlines(); |
477 | 504 |
478 directives = directives.skip(1); | 505 directives = directives.skip(1); |
479 } | 506 } |
480 | 507 |
481 visitNodes(directives, between: oneOrTwoNewlines); | 508 visitNodes(directives, between: oneOrTwoNewlines); |
482 | 509 |
483 if (node.declarations.isNotEmpty) { | 510 var needsDouble = true; |
484 var needsDouble = true; | 511 for (var declaration in node.declarations) { |
| 512 // Add a blank line before classes. |
| 513 if (declaration is ClassDeclaration) needsDouble = true; |
485 | 514 |
486 for (var declaration in node.declarations) { | 515 if (needsDouble) { |
487 // Add a blank line before classes. | 516 twoNewlines(); |
488 if (declaration is ClassDeclaration) needsDouble = true; | 517 } else { |
| 518 // Variables and arrow-bodied members can be more tightly packed if |
| 519 // the user wants to group things together. |
| 520 oneOrTwoNewlines(); |
| 521 } |
489 | 522 |
490 if (needsDouble) { | 523 visit(declaration); |
491 twoNewlines(); | |
492 } else { | |
493 // Variables and arrow-bodied members can be more tightly packed if | |
494 // the user wants to group things together. | |
495 oneOrTwoNewlines(); | |
496 } | |
497 | 524 |
498 visit(declaration); | 525 needsDouble = false; |
499 | 526 if (declaration is ClassDeclaration) { |
500 needsDouble = false; | 527 // Add a blank line after classes. |
501 if (declaration is ClassDeclaration) { | 528 needsDouble = true; |
502 // Add a blank line after classes. | 529 } else if (declaration is FunctionDeclaration) { |
503 needsDouble = true; | 530 // Add a blank line after non-empty block functions. |
504 } else if (declaration is FunctionDeclaration) { | 531 var body = declaration.functionExpression.body; |
505 // Add a blank line after non-empty block functions. | 532 if (body is BlockFunctionBody) { |
506 if (declaration.functionExpression.body is BlockFunctionBody) { | 533 needsDouble = body.block.statements.isNotEmpty; |
507 var body = declaration.functionExpression.body as BlockFunctionBody; | |
508 needsDouble = body.block.statements.isNotEmpty; | |
509 } | |
510 } | 534 } |
511 } | 535 } |
512 } | 536 } |
513 } | 537 } |
514 | 538 |
515 visitConditionalExpression(ConditionalExpression node) { | 539 visitConditionalExpression(ConditionalExpression node) { |
516 builder.nestExpression(); | 540 builder.nestExpression(); |
517 | 541 |
518 // Start lazily so we don't force the operator to split if a line comment | 542 // Start lazily so we don't force the operator to split if a line comment |
519 // appears before the first operand. If we split after one clause in a | 543 // appears before the first operand. If we split after one clause in a |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 } | 751 } |
728 | 752 |
729 visitEnumDeclaration(EnumDeclaration node) { | 753 visitEnumDeclaration(EnumDeclaration node) { |
730 visitMetadata(node.metadata); | 754 visitMetadata(node.metadata); |
731 | 755 |
732 token(node.enumKeyword); | 756 token(node.enumKeyword); |
733 space(); | 757 space(); |
734 visit(node.name); | 758 visit(node.name); |
735 space(); | 759 space(); |
736 | 760 |
737 _writeBody(node.leftBracket, node.rightBracket, space: true, body: () { | 761 _beginBody(node.leftBracket, space: true); |
738 visitCommaSeparatedNodes(node.constants, between: split); | 762 visitCommaSeparatedNodes(node.constants, between: split); |
739 }); | 763 _endBody(node.rightBracket, space: true); |
740 } | 764 } |
741 | 765 |
742 visitExportDirective(ExportDirective node) { | 766 visitExportDirective(ExportDirective node) { |
743 visitMetadata(node.metadata); | 767 visitMetadata(node.metadata); |
744 | 768 |
745 _simpleStatement(node, () { | 769 _simpleStatement(node, () { |
746 token(node.keyword); | 770 token(node.keyword); |
747 space(); | 771 space(); |
748 visit(node.uri); | 772 visit(node.uri); |
749 | 773 |
(...skipping 1399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2149 | 2173 |
2150 /// Marks the collection literal that starts with [leftBracket] as being | 2174 /// Marks the collection literal that starts with [leftBracket] as being |
2151 /// controlled by [argumentList]. | 2175 /// controlled by [argumentList]. |
2152 /// | 2176 /// |
2153 /// When the collection is visited, [argumentList] will determine the | 2177 /// When the collection is visited, [argumentList] will determine the |
2154 /// indentation and splitting rule for the collection. | 2178 /// indentation and splitting rule for the collection. |
2155 void beforeCollection(Token leftBracket, ArgumentSublist argumentList) { | 2179 void beforeCollection(Token leftBracket, ArgumentSublist argumentList) { |
2156 _collectionArgumentLists[leftBracket] = argumentList; | 2180 _collectionArgumentLists[leftBracket] = argumentList; |
2157 } | 2181 } |
2158 | 2182 |
2159 /// Writes an bracket-delimited body and handles indenting and starting the | 2183 /// Writes the beginning of a brace-delimited body and handles indenting and |
2160 /// rule used to split the contents. | 2184 /// starting the rule used to split the contents. |
2161 /// | 2185 void _beginBody(Token leftBracket, {bool space: false}) { |
2162 /// If [space] is `true`, then the contents and delimiters will have a space | |
2163 /// between then when unsplit. | |
2164 void _writeBody(Token leftBracket, Token rightBracket, | |
2165 {bool space: false, body()}) { | |
2166 token(leftBracket); | 2186 token(leftBracket); |
2167 | 2187 |
2168 // Indent the body. | 2188 // Indent the body. |
2169 builder.indent(); | 2189 builder.indent(); |
2170 | 2190 |
2171 // Split after the bracket. | 2191 // Split after the bracket. |
2172 builder.startRule(); | 2192 builder.startRule(); |
2173 builder.split(isDouble: false, nest: false, space: space); | 2193 builder.split(isDouble: false, nest: false, space: space); |
| 2194 } |
2174 | 2195 |
2175 body(); | 2196 /// Finishes the body started by a call to [_beginBody]. |
2176 | 2197 void _endBody(Token rightBracket, {bool space: false}) { |
2177 token(rightBracket, before: () { | 2198 token(rightBracket, before: () { |
2178 // Split before the closing bracket character. | 2199 // Split before the closing bracket character. |
2179 builder.unindent(); | 2200 builder.unindent(); |
2180 builder.split(nest: false, space: space); | 2201 builder.split(nest: false, space: space); |
2181 }); | 2202 }); |
2182 | 2203 |
2183 builder.endRule(); | 2204 builder.endRule(); |
2184 } | 2205 } |
2185 | 2206 |
2186 /// Returns `true` if [node] is immediately contained within an anonymous | 2207 /// Returns `true` if [node] is immediately contained within an anonymous |
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2470 /// Gets the 1-based line number that the beginning of [token] lies on. | 2491 /// Gets the 1-based line number that the beginning of [token] lies on. |
2471 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; | 2492 int _startLine(Token token) => _lineInfo.getLocation(token.offset).lineNumber; |
2472 | 2493 |
2473 /// Gets the 1-based line number that the end of [token] lies on. | 2494 /// Gets the 1-based line number that the end of [token] lies on. |
2474 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; | 2495 int _endLine(Token token) => _lineInfo.getLocation(token.end).lineNumber; |
2475 | 2496 |
2476 /// Gets the 1-based column number that the beginning of [token] lies on. | 2497 /// Gets the 1-based column number that the beginning of [token] lies on. |
2477 int _startColumn(Token token) => | 2498 int _startColumn(Token token) => |
2478 _lineInfo.getLocation(token.offset).columnNumber; | 2499 _lineInfo.getLocation(token.offset).columnNumber; |
2479 } | 2500 } |
OLD | NEW |