Skip to content

Commit a72fbfc

Browse files
authored
Format fields and methods. (#1313)
Format fields and methods. Almost all of the real work was already done to handle variables and functions, so this just extends that to fields and methods defined in classes and covers a few loose ends: - External declarations in their various forms. - The covariant modifier on parameters and fields. - Operator declarations (which apparently were never tested on the old style!). - Getters and setters. - The `static`, `abstract`, and `late` modifiers. I also tweaked the cost heuristics around splitting between return types, parameter lists, and `=>` expression bodies. It looks pretty weird to split after a return type, so I made that more costly than splitting at the body or parameter list. I also decided to put the tests for member declarations inside declaration/ instead of member/. My impression is that there won't be a huge number of separate files in declaration/ and member/, so it's easier to just merge them together.
1 parent f1580e3 commit a72fbfc

File tree

17 files changed

+524
-42
lines changed

17 files changed

+524
-42
lines changed

lib/src/back_end/code_writer.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,11 @@ class CodeWriter {
261261
_overflow += _column - _pageWidth;
262262
}
263263

264+
// If we found a problematic line, and there is a piece on the line that
265+
// we can try to split, then remember that piece so that the solution will
266+
// expand it next.
264267
if (!_foundExpandLine &&
268+
_nextPieceToExpand != null &&
265269
(_column > _pageWidth || _containsInvalidNewline)) {
266270
// We found a problematic line, so remember it and the piece on it.
267271
_foundExpandLine = true;

lib/src/front_end/ast_node_visitor.dart

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,12 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
434434

435435
@override
436436
void visitFieldDeclaration(FieldDeclaration node) {
437-
throw UnimplementedError();
437+
modifier(node.externalKeyword);
438+
modifier(node.staticKeyword);
439+
modifier(node.abstractKeyword);
440+
modifier(node.covariantKeyword);
441+
visit(node.fields);
442+
token(node.semicolon);
438443
}
439444

440445
@override
@@ -575,19 +580,14 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
575580

576581
@override
577582
void visitFunctionDeclaration(FunctionDeclaration node) {
578-
modifier(node.externalKeyword);
579-
580-
Piece? returnType;
581-
if (node.returnType case var returnTypeNode?) {
582-
visit(returnTypeNode);
583-
returnType = pieces.split();
584-
}
585-
586-
// TODO(tall): Get or set keywords for getters and setters.
587-
if (node.propertyKeyword != null) throw UnimplementedError();
588-
token(node.name);
589-
590-
finishFunction(returnType, node.functionExpression);
583+
createFunction(
584+
externalKeyword: node.externalKeyword,
585+
returnType: node.returnType,
586+
propertyKeyword: node.propertyKeyword,
587+
name: node.name,
588+
typeParameters: node.functionExpression.typeParameters,
589+
parameters: node.functionExpression.parameters,
590+
body: node.functionExpression.body);
591591
}
592592

593593
@override
@@ -597,7 +597,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
597597

598598
@override
599599
void visitFunctionExpression(FunctionExpression node) {
600-
finishFunction(null, node);
600+
finishFunction(null, node.typeParameters, node.parameters, node.body);
601601
}
602602

603603
@override
@@ -805,7 +805,16 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
805805

806806
@override
807807
void visitMethodDeclaration(MethodDeclaration node) {
808-
throw UnimplementedError();
808+
createFunction(
809+
externalKeyword: node.externalKeyword,
810+
modifierKeyword: node.modifierKeyword,
811+
returnType: node.returnType,
812+
operatorKeyword: node.operatorKeyword,
813+
propertyKeyword: node.propertyKeyword,
814+
name: node.name,
815+
typeParameters: node.typeParameters,
816+
parameters: node.parameters,
817+
body: node.body);
809818
}
810819

811820
@override
@@ -1228,6 +1237,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
12281237

12291238
@override
12301239
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
1240+
modifier(node.externalKeyword);
12311241
visit(node.variables);
12321242
token(node.semicolon);
12331243
}

lib/src/front_end/piece_factory.dart

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,39 @@ mixin PieceFactory implements CommentWriter {
158158
}
159159
}
160160

161+
/// Creates a function, method, getter, or setter declaration.
162+
///
163+
/// If [modifierKeyword] is given, it should be the `static` or `abstract`
164+
/// modifier on a method declaration. If [operatorKeyword] is given, it
165+
/// should be the `operator` keyword on an operator declaration. If
166+
/// [propertyKeyword] is given, it should be the `get` or `set` keyword on a
167+
/// getter or setter declaration.
168+
void createFunction(
169+
{Token? externalKeyword,
170+
Token? modifierKeyword,
171+
AstNode? returnType,
172+
Token? operatorKeyword,
173+
Token? propertyKeyword,
174+
required Token name,
175+
TypeParameterList? typeParameters,
176+
FormalParameterList? parameters,
177+
required FunctionBody body}) {
178+
modifier(externalKeyword);
179+
modifier(modifierKeyword);
180+
181+
Piece? returnTypePiece;
182+
if (returnType != null) {
183+
visit(returnType);
184+
returnTypePiece = pieces.split();
185+
}
186+
187+
modifier(operatorKeyword);
188+
modifier(propertyKeyword);
189+
token(name);
190+
191+
finishFunction(returnTypePiece, typeParameters, parameters, body);
192+
}
193+
161194
/// Creates a function type or function-typed formal.
162195
void createFunctionType(
163196
TypeAnnotation? returnType,
@@ -429,9 +462,6 @@ mixin PieceFactory implements CommentWriter {
429462
({Token leftBracket, List<AstNode> members, Token rightBracket})? body,
430463
Token? semicolon}) {
431464
if (metadata.isNotEmpty) throw UnimplementedError('Type metadata.');
432-
if (body != null && body.members.isNotEmpty) {
433-
throw UnimplementedError('Type members.');
434-
}
435465

436466
modifiers.forEach(modifier);
437467
token(keyword);
@@ -506,7 +536,7 @@ mixin PieceFactory implements CommentWriter {
506536
leftBracket: leftBracket,
507537
elements,
508538
rightBracket: rightBracket,
509-
style: const ListStyle(commas: Commas.nonTrailing, splitCost: 2));
539+
style: const ListStyle(commas: Commas.nonTrailing, splitCost: 3));
510540
}
511541

512542
/// Writes the parts of a formal parameter shared by all formal parameter
@@ -515,7 +545,7 @@ mixin PieceFactory implements CommentWriter {
515545
if (parameter.metadata.isNotEmpty) throw UnimplementedError();
516546

517547
modifier(parameter.requiredKeyword);
518-
if (parameter.covariantKeyword != null) throw UnimplementedError();
548+
modifier(parameter.covariantKeyword);
519549
}
520550

521551
/// Handles the `async`, `sync*`, or `async*` modifiers on a function body.
@@ -588,24 +618,25 @@ mixin PieceFactory implements CommentWriter {
588618
/// Finishes writing a named function declaration or anonymous function
589619
/// expression after the return type (if any) and name (if any) has been
590620
/// written.
591-
void finishFunction(Piece? returnType, FunctionExpression function) {
592-
visit(function.typeParameters);
593-
visit(function.parameters);
621+
void finishFunction(Piece? returnType, TypeParameterList? typeParameters,
622+
FormalParameterList? parameters, FunctionBody body) {
623+
visit(typeParameters);
624+
visit(parameters);
594625

595-
Piece parameters;
596-
Piece? body;
597-
if (function.body case EmptyFunctionBody body) {
626+
Piece parametersPiece;
627+
Piece? bodyPiece;
628+
if (body is EmptyFunctionBody) {
598629
// If the body is just `;`, then don't allow a space or split before the
599630
// semicolon by making it part of the parameters piece.
600631
token(body.semicolon);
601-
parameters = pieces.split();
632+
parametersPiece = pieces.split();
602633
} else {
603-
parameters = pieces.split();
604-
visit(function.body);
605-
body = pieces.take();
634+
parametersPiece = pieces.split();
635+
visit(body);
636+
bodyPiece = pieces.take();
606637
}
607638

608-
pieces.give(FunctionPiece(returnType, parameters, body));
639+
pieces.give(FunctionPiece(returnType, parametersPiece, bodyPiece));
609640
}
610641

611642
/// Writes an optional modifier that precedes other code.

lib/src/piece/function.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import 'piece.dart';
99
///
1010
/// Handles splitting between the return type and the rest of the function.
1111
class FunctionPiece extends Piece {
12+
static const _splitAfterReturnType = State(1, cost: 2);
13+
1214
/// The return type annotation, if any.
1315
final Piece? _returnType;
1416

@@ -22,20 +24,21 @@ class FunctionPiece extends Piece {
2224
FunctionPiece(this._returnType, this._signature, [this._body]);
2325

2426
@override
25-
List<State> get additionalStates => [if (_returnType != null) State.split];
27+
List<State> get additionalStates =>
28+
[if (_returnType != null) _splitAfterReturnType];
2629

2730
@override
2831
void format(CodeWriter writer, State state) {
2932
if (_returnType case var returnType?) {
3033
// A split inside the return type forces splitting after the return type.
31-
writer.setAllowNewlines(state == State.split);
34+
writer.setAllowNewlines(state == _splitAfterReturnType);
3235

3336
writer.format(returnType);
3437

3538
// A split in the type parameters or parameters does not force splitting
3639
// after the return type.
3740
writer.setAllowNewlines(true);
38-
writer.splitIf(state == State.split);
41+
writer.splitIf(state == _splitAfterReturnType);
3942
}
4043

4144
writer.format(_signature);

test/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,12 @@ These tests are all run by `short_format_test.dart`.
6363
The newer tall style tests are:
6464

6565
```
66-
declaration/ - Typedef, class, enum, and extension declarations.
66+
declaration/ - Typedef, class, enum, extension, mixin, and member declarations.
67+
Includes constructors, getters, setters, methods, and fields,
68+
but not functions and variables, which are in their own
69+
directories below.
6770
expression/ - Expressions.
6871
invocation/ - Function and member invocations.
69-
member/ - Constructor, method, field, getter, and setter declarations.
7072
selection/ - Test preserving selection information.
7173
statement/ - Statements.
7274
top_level/ - Top-level directives.

test/declaration/external.unit

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
40 columns |
2+
>>> Top-level variable.
3+
external final a , b ;
4+
external final Set < int > a , b ;
5+
external var a ;
6+
external List < int > a ;
7+
<<<
8+
external final a, b;
9+
external final Set<int> a, b;
10+
external var a;
11+
external List<int> a;
12+
>>> Static field.
13+
class C {
14+
external static final a , b ;
15+
external static final Set < int > a , b ;
16+
external static var a ;
17+
external static List < int > a ;
18+
}
19+
<<<
20+
class C {
21+
external static final a, b;
22+
external static final Set<int> a, b;
23+
external static var a;
24+
external static List<int> a;
25+
}
26+
>>> Instance field.
27+
class C {
28+
external final a , b ;
29+
external final Set < String > a , b ;
30+
external var a ;
31+
external List < int > a ;
32+
}
33+
<<<
34+
class C {
35+
external final a, b;
36+
external final Set<String> a, b;
37+
external var a;
38+
external List<int> a;
39+
}
40+
>>> Top-level function.
41+
external int function();
42+
external int get getter;
43+
external void set setter(int value);
44+
<<<
45+
external int function();
46+
external int get getter;
47+
external void set setter(int value);
48+
>>> Instance member.
49+
class A {
50+
external int function();
51+
external int get getter;
52+
external void set setter(int value);
53+
}
54+
<<<
55+
class A {
56+
external int function();
57+
external int get getter;
58+
external void set setter(int value);
59+
}
60+
>>> Static member.
61+
class A {
62+
external static int function();
63+
external static int get getter;
64+
external static void set setter(int value);
65+
}
66+
<<<
67+
class A {
68+
external static int function();
69+
external static int get getter;
70+
external static void set setter(
71+
int value,
72+
);
73+
}
74+
>>> Don't split after `external`.
75+
class Foo {
76+
external var soMuchSoVeryLongFieldNameHere;
77+
external SuperLongTypeAnnotation field;
78+
}
79+
<<<
80+
class Foo {
81+
external var soMuchSoVeryLongFieldNameHere;
82+
external SuperLongTypeAnnotation
83+
field;
84+
}

0 commit comments

Comments
 (0)