Skip to content

Commit cf1c1c2

Browse files
authored
Format mixin declarations. (#1315)
Format mixin declarations. Almost nothing interesting here. The clauses are all handled the same way we handle clauses in a class declaration. We treat the `on` clause like the `extends` clause in a class, which means the other clauses can split while allowing the on clause to stay on the top line if it fits. Mixin classes (and their various modifiers) were already handled because those are class declarations with a mixin modifier. Now there are tests for them.
1 parent e860fda commit cf1c1c2

File tree

4 files changed

+195
-4
lines changed

4 files changed

+195
-4
lines changed

lib/src/front_end/ast_node_visitor.dart

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,15 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
829829

830830
@override
831831
void visitMixinDeclaration(MixinDeclaration node) {
832-
throw UnimplementedError();
832+
createType(node.metadata, [node.baseKeyword], node.mixinKeyword, node.name,
833+
typeParameters: node.typeParameters,
834+
onClause: node.onClause,
835+
implementsClause: node.implementsClause,
836+
body: (
837+
leftBracket: node.leftBracket,
838+
members: node.members,
839+
rightBracket: node.rightBracket
840+
));
833841
}
834842

835843
@override
@@ -885,7 +893,7 @@ class AstNodeVisitor extends ThrowingAstVisitor<void>
885893

886894
@override
887895
void visitOnClause(OnClause node) {
888-
throw UnimplementedError();
896+
assert(false, 'This node is handled by PieceFactory.createType().');
889897
}
890898

891899
@override

lib/src/front_end/piece_factory.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,7 @@ mixin PieceFactory implements CommentWriter {
456456
Token? equals,
457457
NamedType? superclass,
458458
ExtendsClause? extendsClause,
459+
OnClause? onClause,
459460
WithClause? withClause,
460461
ImplementsClause? implementsClause,
461462
NativeClause? nativeClause,
@@ -500,6 +501,10 @@ mixin PieceFactory implements CommentWriter {
500501
typeClause(extendsClause.extendsKeyword, [extendsClause.superclass]);
501502
}
502503

504+
if (onClause != null) {
505+
typeClause(onClause.onKeyword, onClause.superclassConstraints);
506+
}
507+
503508
if (withClause != null) {
504509
typeClause(withClause.withKeyword, withClause.mixinTypes);
505510
}
@@ -511,8 +516,8 @@ mixin PieceFactory implements CommentWriter {
511516

512517
ClausesPiece? clausesPiece;
513518
if (clauses.isNotEmpty) {
514-
clausesPiece =
515-
ClausesPiece(clauses, allowLeadingClause: extendsClause != null);
519+
clausesPiece = ClausesPiece(clauses,
520+
allowLeadingClause: extendsClause != null || onClause != null);
516521
}
517522

518523
visit(nativeClause);

test/declaration/mixin.unit

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
40 columns |
2+
>>> Empty body.
3+
mixin M { }
4+
<<<
5+
mixin M {}
6+
>>> Members.
7+
### These are formatted the same as classes, so most of the member tests are
8+
### covered there. This just ensures that the formatter handles all members in
9+
### a mixin declaration.
10+
mixin M {
11+
static const int c = 1;
12+
static final int f = 1;
13+
static late final int l;
14+
static var v;
15+
static int get g => c;
16+
static set g(int i) {}
17+
static int m<X>(X x) => c;
18+
int x;
19+
int get pr => 0;
20+
set pr(int x) {}
21+
int me(int x) => x;
22+
int operator+(int x) => x;
23+
}
24+
<<<
25+
mixin M {
26+
static const int c = 1;
27+
static final int f = 1;
28+
static late final int l;
29+
static var v;
30+
static int get g => c;
31+
static set g(int i) {}
32+
static int m<X>(X x) => c;
33+
int x;
34+
int get pr => 0;
35+
set pr(int x) {}
36+
int me(int x) => x;
37+
int operator +(int x) => x;
38+
}
39+
>>> Modifiers.
40+
mixin class M1 { }
41+
base mixin class M2 { }
42+
abstract mixin class M3 { }
43+
abstract base mixin class M4 { }
44+
base mixin M5 { }
45+
<<<
46+
mixin class M1 {}
47+
48+
base mixin class M2 {}
49+
50+
abstract mixin class M3 {}
51+
52+
abstract base mixin class M4 {}
53+
54+
base mixin M5 {}

test/declaration/mixin_clause.unit

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
40 columns |
2+
>>> Unsplit on clause.
3+
mixin A on B {}
4+
<<<
5+
mixin A on B {}
6+
>>> Multiple unsplit types in on clause.
7+
mixin M2 on A , B , C { }
8+
<<<
9+
mixin M2 on A, B, C {}
10+
>>> Split at `on`.
11+
mixin SomeLongMixin on VeryLongBaseMixin {}
12+
<<<
13+
mixin SomeLongMixin
14+
on VeryLongBaseMixin {}
15+
>>> Split multiple at `on`.
16+
mixin LongMixin on SupertypeA , SupertypeB { }
17+
<<<
18+
mixin LongMixin
19+
on SupertypeA, SupertypeB {}
20+
>>> Split multiple on clause.
21+
mixin M2 on SupertypeA , SupertypeB , SupertypeC { }
22+
<<<
23+
mixin M2
24+
on
25+
SupertypeA,
26+
SupertypeB,
27+
SupertypeC {}
28+
>>> Unsplit implements clause.
29+
mixin A implements B {}
30+
<<<
31+
mixin A implements B {}
32+
>>> Unsplit multiple clauses.
33+
mixin A on B implements D {}
34+
<<<
35+
mixin A on B implements D {}
36+
>>> Split at `implements`.
37+
mixin SomeMixin implements VeryLongBaseMixin {}
38+
<<<
39+
mixin SomeMixin
40+
implements VeryLongBaseMixin {}
41+
>>> Split at `implements` but not between interfaces.
42+
mixin SomeMixin implements Interface, AnotherOne {}
43+
<<<
44+
mixin SomeMixin
45+
implements Interface, AnotherOne {}
46+
>>> Split at `implements` and interfaces.
47+
mixin SomeMixin implements Interface, Another, Third {}
48+
<<<
49+
mixin SomeMixin
50+
implements
51+
Interface,
52+
Another,
53+
Third {}
54+
>>> Split at `on` splits `implements` too.
55+
mixin AVeryLongSomeMixin on LongBaseMixin implements I {}
56+
<<<
57+
mixin AVeryLongSomeMixin
58+
on LongBaseMixin
59+
implements I {}
60+
>>>
61+
mixin AVeryLongSomeMixin on LongBaseMixin implements Interface {}
62+
<<<
63+
mixin AVeryLongSomeMixin
64+
on LongBaseMixin
65+
implements Interface {}
66+
>>> Can split `implements` clause without splitting `on`.
67+
mixin SomeMixin on A implements Type, Another {}
68+
<<<
69+
mixin SomeMixin on A
70+
implements Type, Another {}
71+
>>>
72+
mixin SomeMixin on A implements Type, Another, Third, Fourth {}
73+
<<<
74+
mixin SomeMixin on A
75+
implements
76+
Type,
77+
Another,
78+
Third,
79+
Fourth {}
80+
>>> Unsplit generic supermixin.
81+
mixin SomeMixin on C<int> {}
82+
<<<
83+
mixin SomeMixin on C<int> {}
84+
>>> Split before `on` on generic supermixin.
85+
mixin SomeMixin on Superclass<SomeLongmixin> {}
86+
<<<
87+
mixin SomeMixin
88+
on Superclass<SomeLongmixin> {}
89+
>>> Split in generic supermixin.
90+
mixin SomeMixin on C<VeryLongType, AnotherLongType> {}
91+
<<<
92+
mixin SomeMixin
93+
on
94+
C<
95+
VeryLongType,
96+
AnotherLongType
97+
> {}
98+
>>> Unsplit generic superinterface.
99+
mixin SomeMixin implements C<int> {}
100+
<<<
101+
mixin SomeMixin implements C<int> {}
102+
>>> Split before `implements` on generic superinterface.
103+
mixin SomeMixin implements C<SomeLongmixin> {}
104+
<<<
105+
mixin SomeMixin
106+
implements C<SomeLongmixin> {}
107+
>>> Split in generic superinterface.
108+
mixin SomeMixin implements C<VeryLongType, AnotherLongType> {}
109+
<<<
110+
mixin SomeMixin
111+
implements
112+
C<
113+
VeryLongType,
114+
AnotherLongType
115+
> {}
116+
>>> Split in generic `implements` clause does not force `on` clause to split.
117+
mixin C on A implements B<LongTypeArgument, AnotherLongType> {}
118+
<<<
119+
mixin C on A
120+
implements
121+
B<
122+
LongTypeArgument,
123+
AnotherLongType
124+
> {}

0 commit comments

Comments
 (0)