| Index: pkg/analyzer/lib/src/services/formatter_impl.dart
|
| diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
|
| index f0f946f4892b364b62fd3429efbcbe6c0acbe144..e0512f9d2e277126ed4904831b8de6531351732f 100644
|
| --- a/pkg/analyzer/lib/src/services/formatter_impl.dart
|
| +++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
|
| @@ -18,12 +18,8 @@ class FormatterOptions {
|
| /// Create formatter options with defaults derived (where defined) from
|
| /// the style guide: <http://www.dartlang.org/articles/style-guide/>.
|
| const FormatterOptions({this.initialIndentationLevel: 0,
|
| - this.spacesPerIndent: 2,
|
| - this.lineSeparator: NEW_LINE,
|
| - this.pageWidth: 80,
|
| - this.tabsForIndent: false,
|
| - this.tabSize: 2,
|
| - this.codeTransforms: false});
|
| + this.spacesPerIndent: 2, this.lineSeparator: NEW_LINE, this.pageWidth: 80,
|
| + this.tabsForIndent: false, this.tabSize: 2, this.codeTransforms: false});
|
|
|
| final String lineSeparator;
|
| final int initialIndentationLevel;
|
| @@ -34,7 +30,6 @@ class FormatterOptions {
|
| final bool codeTransforms;
|
| }
|
|
|
| -
|
| /// Thrown when an error occurs in formatting.
|
| class FormatterException implements Exception {
|
|
|
| @@ -44,8 +39,8 @@ class FormatterException implements Exception {
|
| /// Creates a new FormatterException with an optional error [message].
|
| const FormatterException([this.message = 'FormatterException']);
|
|
|
| - FormatterException.forError(List<AnalysisError> errors, [LineInfo line]) :
|
| - message = _createMessage(errors);
|
| + FormatterException.forError(List<AnalysisError> errors, [LineInfo line])
|
| + : message = _createMessage(errors);
|
|
|
| static String _createMessage(errors) {
|
| //TODO(pquitslund): consider a verbosity flag to add/suppress details
|
| @@ -68,20 +63,18 @@ class CodeKind {
|
|
|
| /// A statement snippet.
|
| static const STATEMENT = const CodeKind._(1);
|
| -
|
| }
|
|
|
| /// Dart source code formatter.
|
| abstract class CodeFormatter {
|
| -
|
| - factory CodeFormatter([FormatterOptions options = const FormatterOptions()])
|
| - => new CodeFormatterImpl(options);
|
| + factory CodeFormatter(
|
| + [FormatterOptions options = const FormatterOptions()]) =>
|
| + new CodeFormatterImpl(options);
|
|
|
| /// Format the specified portion (from [offset] with [length]) of the given
|
| /// [source] string, optionally providing an [indentationLevel].
|
| FormattedSource format(CodeKind kind, String source, {int offset, int end,
|
| - int indentationLevel: 0, Selection selection: null});
|
| -
|
| + int indentationLevel: 0, Selection selection: null});
|
| }
|
|
|
| /// Source selection state information.
|
| @@ -111,9 +104,7 @@ class FormattedSource {
|
| FormattedSource(this.source, [this.selection = null]);
|
| }
|
|
|
| -
|
| class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener {
|
| -
|
| final FormatterOptions options;
|
| final errors = <AnalysisError>[];
|
| final whitespace = new RegExp(r'[\s]+');
|
| @@ -124,7 +115,6 @@ class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener {
|
|
|
| FormattedSource format(CodeKind kind, String source, {int offset, int end,
|
| int indentationLevel: 0, Selection selection: null}) {
|
| -
|
| var startToken = tokenize(source);
|
| checkForErrors();
|
|
|
| @@ -137,17 +127,16 @@ class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener {
|
| var formattedSource = formatter.writer.toString();
|
|
|
| checkTokenStreams(startToken, tokenize(formattedSource),
|
| - allowTransforms: options.codeTransforms);
|
| + allowTransforms: options.codeTransforms);
|
|
|
| return new FormattedSource(formattedSource, formatter.selection);
|
| }
|
|
|
| checkTokenStreams(Token t1, Token t2, {allowTransforms: false}) =>
|
| - new TokenStreamComparator(lineInfo, t1, t2, transforms: allowTransforms).
|
| - verifyEquals();
|
| + new TokenStreamComparator(lineInfo, t1, t2, transforms: allowTransforms)
|
| + .verifyEquals();
|
|
|
| AstNode parse(CodeKind kind, Token start) {
|
| -
|
| var parser = new Parser(null, this);
|
|
|
| switch (kind) {
|
| @@ -177,19 +166,17 @@ class CodeFormatterImpl implements CodeFormatter, AnalysisErrorListener {
|
| lineInfo = new LineInfo(scanner.lineStarts);
|
| return token;
|
| }
|
| -
|
| }
|
|
|
| -
|
| // Compares two token streams. Used for sanity checking formatted results.
|
| class TokenStreamComparator {
|
| -
|
| final LineInfo lineInfo;
|
| Token token1, token2;
|
| bool allowTransforms;
|
|
|
| TokenStreamComparator(this.lineInfo, this.token1, this.token2,
|
| - {transforms: false}) : this.allowTransforms = transforms;
|
| + {transforms: false})
|
| + : this.allowTransforms = transforms;
|
|
|
| /// Verify that these two token streams are equal.
|
| verifyEquals() {
|
| @@ -199,13 +186,11 @@ class TokenStreamComparator {
|
| throwNotEqualException(token1, token2);
|
| }
|
| advance();
|
| -
|
| }
|
| // TODO(pquitslund): consider a better way to notice trailing synthetics
|
| if (!isEOF(token2) &&
|
| !(isCLOSE_CURLY_BRACKET(token2) && isEOF(token2.next))) {
|
| - throw new FormatterException(
|
| - 'Expected "EOF" but got "$token2".');
|
| + throw new FormatterException('Expected "EOF" but got "$token2".');
|
| }
|
| }
|
|
|
| @@ -238,8 +223,9 @@ class TokenStreamComparator {
|
| 'Expected "$t1" but got "$t2", at ${describeLocation(t1)}.');
|
| }
|
|
|
| - String describeLocation(Token token) => lineInfo == null ? '<unknown>' :
|
| - 'Line: ${lineInfo.getLocation(token.offset).lineNumber}, '
|
| + String describeLocation(Token token) => lineInfo == null
|
| + ? '<unknown>'
|
| + : 'Line: ${lineInfo.getLocation(token.offset).lineNumber}, '
|
| 'Column: ${lineInfo.getLocation(token.offset).columnNumber}';
|
|
|
| advance() {
|
| @@ -293,12 +279,10 @@ class TokenStreamComparator {
|
| token2 = token2.next;
|
| return checkTokens();
|
| }
|
| -
|
| }
|
|
|
| return false;
|
| }
|
| -
|
| }
|
|
|
| /// Test for token type.
|
| @@ -334,13 +318,10 @@ bool isCLOSE_SQUARE_BRACKET(Token token) =>
|
| tokenIs(token, TokenType.CLOSE_SQUARE_BRACKET);
|
|
|
| /// Test if this token is a SEMICOLON token.
|
| -bool isSEMICOLON(Token token) =>
|
| - tokenIs(token, TokenType.SEMICOLON);
|
| -
|
| +bool isSEMICOLON(Token token) => tokenIs(token, TokenType.SEMICOLON);
|
|
|
| /// An AST visitor that drives formatting heuristics.
|
| class SourceVisitor implements AstVisitor {
|
| -
|
| static final OPEN_CURLY = syntheticToken(TokenType.OPEN_CURLY_BRACKET, '{');
|
| static final CLOSE_CURLY = syntheticToken(TokenType.CLOSE_CURLY_BRACKET, '}');
|
| static final SEMI_COLON = syntheticToken(TokenType.SEMICOLON, ';');
|
| @@ -392,24 +373,23 @@ class SourceVisitor implements AstVisitor {
|
|
|
| final bool codeTransforms;
|
|
|
| -
|
| /// The source being formatted (used in interpolation handling)
|
| final String source;
|
|
|
| /// Post format selection information.
|
| Selection selection;
|
|
|
| -
|
| /// Initialize a newly created visitor to write source code representing
|
| /// the visited nodes to the given [writer].
|
| - SourceVisitor(FormatterOptions options, this.lineInfo, this.source,
|
| - this.preSelection)
|
| - : writer = new SourceWriter(indentCount: options.initialIndentationLevel,
|
| - lineSeparator: options.lineSeparator,
|
| - maxLineLength: options.pageWidth,
|
| - useTabs: options.tabsForIndent,
|
| - spacesPerIndent: options.spacesPerIndent),
|
| - codeTransforms = options.codeTransforms;
|
| + SourceVisitor(
|
| + FormatterOptions options, this.lineInfo, this.source, this.preSelection)
|
| + : writer = new SourceWriter(
|
| + indentCount: options.initialIndentationLevel,
|
| + lineSeparator: options.lineSeparator,
|
| + maxLineLength: options.pageWidth,
|
| + useTabs: options.tabsForIndent,
|
| + spacesPerIndent: options.spacesPerIndent),
|
| + codeTransforms = options.codeTransforms;
|
|
|
| visitAdjacentStrings(AdjacentStrings node) {
|
| visitNodes(node.strings, separatedBy: space);
|
| @@ -428,8 +408,7 @@ class SourceVisitor implements AstVisitor {
|
| if (node.arguments.isNotEmpty) {
|
| int weight = lastSpaceWeight++;
|
| levelSpace(weight, 0);
|
| - visitCommaSeparatedNodes(
|
| - node.arguments,
|
| + visitCommaSeparatedNodes(node.arguments,
|
| followedBy: () => levelSpace(weight));
|
| }
|
| token(node.rightParenthesis);
|
| @@ -455,7 +434,7 @@ class SourceVisitor implements AstVisitor {
|
| visit(node.leftHandSide);
|
| space();
|
| token(node.operator);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| levelSpace(SINGLE_SPACE_WEIGHT);
|
| visit(node.rightHandSide);
|
| });
|
| @@ -539,7 +518,6 @@ class SourceVisitor implements AstVisitor {
|
| }
|
|
|
| visitCatchClause(CatchClause node) {
|
| -
|
| token(node.onKeyword, followedBy: space);
|
| visit(node.exceptionType);
|
|
|
| @@ -568,7 +546,7 @@ class SourceVisitor implements AstVisitor {
|
| token(node.classKeyword);
|
| space();
|
| visit(node.name);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| visit(node.typeParameters);
|
| visitNode(node.extendsClause, precededBy: space);
|
| visitNode(node.withClause, precededBy: space);
|
| @@ -638,7 +616,7 @@ class SourceVisitor implements AstVisitor {
|
| visit(node.condition);
|
| space();
|
| token(node.question);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| levelSpace(weight);
|
| visit(node.thenExpression);
|
| space();
|
| @@ -755,7 +733,7 @@ class SourceVisitor implements AstVisitor {
|
| token(node.whileKeyword);
|
| space();
|
| token(node.leftParenthesis);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| visit(node.condition);
|
| token(node.rightParenthesis);
|
| });
|
| @@ -776,11 +754,11 @@ class SourceVisitor implements AstVisitor {
|
| }
|
| }
|
|
|
| - visitEnumConstantDeclaration(EnumConstantDeclaration node){
|
| + visitEnumConstantDeclaration(EnumConstantDeclaration node) {
|
| visit(node.name);
|
| }
|
|
|
| - visitEnumDeclaration(EnumDeclaration node){
|
| + visitEnumDeclaration(EnumDeclaration node) {
|
| visitMemberMetadata(node.metadata);
|
| token(node.enumKeyword);
|
| space();
|
| @@ -799,7 +777,7 @@ class SourceVisitor implements AstVisitor {
|
| token(node.keyword);
|
| space();
|
| visit(node.uri);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| visitNodes(node.combinators, precededBy: space, separatedBy: space);
|
| });
|
| token(node.semicolon);
|
| @@ -969,7 +947,7 @@ class SourceVisitor implements AstVisitor {
|
| visitIfStatement(IfStatement node) {
|
| var hasElse = node.elseStatement != null;
|
| token(node.ifKeyword);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| space();
|
| token(node.leftParenthesis);
|
| visit(node.condition);
|
| @@ -1004,7 +982,7 @@ class SourceVisitor implements AstVisitor {
|
| visit(node.uri);
|
| token(node.deferredKeyword, precededBy: space);
|
| token(node.asKeyword, precededBy: space, followedBy: space);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| visit(node.prefix);
|
| visitNodes(node.combinators, precededBy: space, separatedBy: space);
|
| });
|
| @@ -1086,8 +1064,7 @@ class SourceVisitor implements AstVisitor {
|
| token(node.leftBracket);
|
| indent();
|
| levelSpace(weight, 0);
|
| - visitCommaSeparatedNodes(
|
| - node.elements,
|
| + visitCommaSeparatedNodes(node.elements,
|
| followedBy: () => levelSpace(weight));
|
| optionalTrailingComma(node.rightBracket);
|
| token(node.rightBracket, precededBy: unindent);
|
| @@ -1224,7 +1201,7 @@ class SourceVisitor implements AstVisitor {
|
| token(node.semicolon);
|
| } else {
|
| token(node.returnKeyword);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| space();
|
| expression.accept(this);
|
| token(node.semicolon);
|
| @@ -1314,7 +1291,6 @@ class SourceVisitor implements AstVisitor {
|
| newlines();
|
| visitNodes(node.members, separatedBy: newlines, followedBy: newlines);
|
| token(node.rightBracket, precededBy: unindent);
|
| -
|
| }
|
|
|
| visitSymbolLiteral(SymbolLiteral node) {
|
| @@ -1441,7 +1417,7 @@ class SourceVisitor implements AstVisitor {
|
| token(node.whileKeyword);
|
| space();
|
| token(node.leftParenthesis);
|
| - allowContinuedLines((){
|
| + allowContinuedLines(() {
|
| visit(node.condition);
|
| token(node.rightParenthesis);
|
| });
|
| @@ -1475,12 +1451,10 @@ class SourceVisitor implements AstVisitor {
|
|
|
| /// Visit member metadata
|
| visitMemberMetadata(NodeList<Annotation> metadata) {
|
| - visitNodes(metadata,
|
| - separatedBy: () {
|
| - space();
|
| - preserveLeadingNewlines();
|
| - },
|
| - followedBy: space);
|
| + visitNodes(metadata, separatedBy: () {
|
| + space();
|
| + preserveLeadingNewlines();
|
| + }, followedBy: space);
|
| if (metadata != null && metadata.length > 0) {
|
| preserveLeadingNewlines();
|
| }
|
| @@ -1502,8 +1476,8 @@ class SourceVisitor implements AstVisitor {
|
|
|
| /// Visit a list of [nodes] if not null, optionally separated and/or preceded
|
| /// and followed by the given functions.
|
| - visitNodes(NodeList<AstNode> nodes, {precededBy(): null,
|
| - separatedBy() : null, followedBy(): null}) {
|
| + visitNodes(NodeList<AstNode> nodes,
|
| + {precededBy(): null, separatedBy(): null, followedBy(): null}) {
|
| if (nodes != null) {
|
| var size = nodes.length;
|
| if (size > 0) {
|
| @@ -1546,7 +1520,6 @@ class SourceVisitor implements AstVisitor {
|
| }
|
| }
|
|
|
| -
|
| /// Visit a [node], and if not null, optionally preceded or followed by the
|
| /// specified functions.
|
| visitNode(AstNode node, {precededBy(): null, followedBy(): null}) {
|
| @@ -1593,8 +1566,8 @@ class SourceVisitor implements AstVisitor {
|
| preserveNewlines = true;
|
| }
|
|
|
| - token(Token token, {precededBy(), followedBy(), printToken(tok),
|
| - int minNewlines: 0}) {
|
| + token(Token token,
|
| + {precededBy(), followedBy(), printToken(tok), int minNewlines: 0}) {
|
| if (token != null) {
|
| if (needsNewline) {
|
| minNewlines = max(1, minNewlines);
|
| @@ -1638,9 +1611,9 @@ class SourceVisitor implements AstVisitor {
|
| var overshot = token.offset - preSelection.offset;
|
| if (overshot >= 0) {
|
| //TODO(pquitslund): update length (may need truncating)
|
| - selection = new Selection(
|
| - writer.toString().length + leadingSpaces - overshot,
|
| - preSelection.length);
|
| + selection = new Selection(writer.toString().length +
|
| + leadingSpaces -
|
| + overshot, preSelection.length);
|
| }
|
| }
|
| }
|
| @@ -1711,7 +1684,6 @@ class SourceVisitor implements AstVisitor {
|
| /// Emit any detected comments and newlines or a minimum as specified
|
| /// by [min].
|
| int emitPrecedingCommentsAndNewlines(Token token, {min: 0}) {
|
| -
|
| var comment = token.precedingComments;
|
| var currentToken = comment != null ? comment : token;
|
|
|
| @@ -1736,7 +1708,6 @@ class SourceVisitor implements AstVisitor {
|
| currentToken.previous != null ? currentToken.previous : token.previous;
|
|
|
| while (comment != null) {
|
| -
|
| emitComment(comment, previousToken);
|
|
|
| var nextToken = comment.next != null ? comment.next : token;
|
| @@ -1769,14 +1740,13 @@ class SourceVisitor implements AstVisitor {
|
| }
|
| }
|
|
|
| -
|
| /// Test if this EOL [comment] is at the beginning of a line.
|
| bool isAtBOL(Token comment) =>
|
| lineInfo.getLocation(comment.offset).columnNumber == 1;
|
|
|
| /// Test if this [comment] is at the end of a line.
|
| - bool isAtEOL(Token comment) =>
|
| - comment != null && comment.toString().trim().startsWith(twoSlashes) &&
|
| + bool isAtEOL(Token comment) => comment != null &&
|
| + comment.toString().trim().startsWith(twoSlashes) &&
|
| sameLine(comment, previousToken);
|
|
|
| /// Emit this [comment], inserting leading whitespace if appropriate.
|
| @@ -1810,8 +1780,9 @@ class SourceVisitor implements AstVisitor {
|
| countNewlinesBetween(node.beginToken.previous, node.beginToken);
|
|
|
| /// Count newlines succeeding this [node].
|
| - int countSucceedingNewlines(AstNode node) => node == null ? 0 :
|
| - countNewlinesBetween(node.endToken, node.endToken.next);
|
| + int countSucceedingNewlines(AstNode node) => node == null
|
| + ? 0
|
| + : countNewlinesBetween(node.endToken, node.endToken.next);
|
|
|
| /// Count the blanks between these two tokens.
|
| int countNewlinesBetween(Token last, Token current) {
|
| @@ -1858,10 +1829,8 @@ class SourceVisitor implements AstVisitor {
|
|
|
| /// Count the lines between two offsets.
|
| int linesBetween(int lastOffset, int currentOffset) {
|
| - var lastLine =
|
| - lineInfo.getLocation(lastOffset).lineNumber;
|
| - var currentLine =
|
| - lineInfo.getLocation(currentOffset).lineNumber;
|
| + var lastLine = lineInfo.getLocation(lastOffset).lineNumber;
|
| + var currentLine = lineInfo.getLocation(currentOffset).lineNumber;
|
| return currentLine - lastLine;
|
| }
|
|
|
|
|