| 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 |