Skip to content

Commit 0a83b0f

Browse files
authored
Allow references to generic type aliases (#2584)
* clean up element types and add display aliases test * Everything except the actual change I want to make * Fix tests and update templates * dartfmt * remove scaffolding * begin extraction * Exclude InterfaceType. Hacky. * refactor continuing * dartfmt, finish modelType extraction * todo:ignore and no dynamic * fix it all * cleanup * start splitting test apart * update analyzer * Implement AliasedElementType * update todo * Add some comments * dartfmt and review comments
1 parent 7022b7f commit 0a83b0f

File tree

5 files changed

+131
-18
lines changed

5 files changed

+131
-18
lines changed

lib/src/element_type.dart

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,16 @@ abstract class ElementType extends Privacy {
3333
return UndefinedElementType(f, library, packageGraph, returnedFrom);
3434
} else {
3535
var element = ModelElement.fromElement(f.element, packageGraph);
36+
// [TypeAliasElement.aliasElement] has different implications.
37+
// In that case it is an actual type alias of some kind (generic
38+
// or otherwise. Here however aliasElement signals that this is a
39+
// type referring to an alias.
40+
if (f is! TypeAliasElement && f.aliasElement != null) {
41+
return AliasedElementType(
42+
f, library, packageGraph, element, returnedFrom);
43+
}
3644
assert(f is ParameterizedType || f is TypeParameterType);
37-
// TODO(jcollins-g): after analyzer 1.2.0 implement InterfaceType
38-
// alias references and strip out all the cruft that's accumulated
45+
// TODO(jcollins-g): strip out all the cruft that's accumulated
3946
// here for non-generic type aliases.
4047
var isGenericTypeAlias = f.aliasElement != null && f is! InterfaceType;
4148
if (f is FunctionType) {
@@ -211,10 +218,32 @@ class ParameterizedElementType extends DefinedElementType {
211218
return _nameWithGenerics;
212219
}
213220

214-
ElementTypeRenderer<ElementType> get _renderer =>
221+
ElementTypeRenderer<ParameterizedElementType> get _renderer =>
215222
packageGraph.rendererFactory.parameterizedElementTypeRenderer;
216223
}
217224

225+
class AliasedElementType extends ParameterizedElementType {
226+
AliasedElementType(ParameterizedType type, Library library,
227+
PackageGraph packageGraph, ModelElement element, ElementType returnedFrom)
228+
: super(type, library, packageGraph, element, returnedFrom) {
229+
assert(type.aliasElement != null);
230+
}
231+
232+
ModelElement _aliasElement;
233+
ModelElement get aliasElement => _aliasElement ??=
234+
ModelElement.fromElement(type.aliasElement, packageGraph);
235+
236+
Iterable<ElementType> _aliasArguments;
237+
Iterable<ElementType> get aliasArguments =>
238+
_aliasArguments ??= type.aliasArguments
239+
.map((f) => ElementType.from(f, library, packageGraph))
240+
.toList(growable: false);
241+
242+
@override
243+
ElementTypeRenderer<AliasedElementType> get _renderer =>
244+
packageGraph.rendererFactory.aliasedElementTypeRenderer;
245+
}
246+
218247
class TypeParameterElementType extends DefinedElementType {
219248
TypeParameterElementType(TypeParameterType type, Library library,
220249
PackageGraph packageGraph, ModelElement element, ElementType returnedFrom)

lib/src/render/element_type_renderer.dart

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,39 @@ class ParameterizedElementTypeRendererHtml
8383
}
8484
}
8585

86+
class AliasedElementTypeRendererHtml
87+
extends ElementTypeRenderer<AliasedElementType> {
88+
@override
89+
String renderLinkedName(AliasedElementType elementType) {
90+
var buf = StringBuffer();
91+
buf.write(elementType.aliasElement.linkedName);
92+
if (elementType.aliasArguments.isNotEmpty &&
93+
!elementType.aliasArguments.every((t) => t.name == 'dynamic')) {
94+
buf.write('<span class="signature">');
95+
buf.write('&lt;<wbr><span class="type-parameter">');
96+
buf.writeAll(elementType.aliasArguments.map((t) => t.linkedName),
97+
'</span>, <span class="type-parameter">');
98+
buf.write('</span>&gt;');
99+
buf.write('</span>');
100+
}
101+
return wrapNullability(elementType, buf.toString());
102+
}
103+
104+
@override
105+
String renderNameWithGenerics(AliasedElementType elementType) {
106+
var buf = StringBuffer();
107+
buf.write(elementType.aliasElement.name);
108+
if (elementType.aliasArguments.isNotEmpty &&
109+
!elementType.aliasArguments.every((t) => t.name == 'dynamic')) {
110+
buf.write('&lt;<wbr><span class="type-parameter">');
111+
buf.writeAll(elementType.aliasArguments.map((t) => t.nameWithGenerics),
112+
'</span>, <span class="type-parameter">');
113+
buf.write('</span>&gt;');
114+
}
115+
return wrapNullability(elementType, buf.toString());
116+
}
117+
}
118+
86119
class CallableElementTypeRendererHtml
87120
extends ElementTypeRenderer<CallableElementType> {
88121
@override
@@ -160,6 +193,37 @@ class ParameterizedElementTypeRendererMd
160193
}
161194
}
162195

196+
class AliasedElementTypeRendererMd
197+
extends ElementTypeRenderer<AliasedElementType> {
198+
@override
199+
String renderLinkedName(AliasedElementType elementType) {
200+
var buf = StringBuffer();
201+
buf.write(elementType.aliasElement.linkedName);
202+
if (elementType.aliasArguments.isNotEmpty &&
203+
!elementType.aliasArguments.every((t) => t.name == 'dynamic')) {
204+
buf.write('&lt;');
205+
buf.writeAll(elementType.aliasArguments.map((t) => t.linkedName), ', ');
206+
buf.write('>');
207+
}
208+
return wrapNullability(elementType, buf.toString());
209+
}
210+
211+
@override
212+
String renderNameWithGenerics(AliasedElementType elementType) {
213+
var buf = StringBuffer();
214+
buf.write(elementType.aliasElement.name);
215+
if (elementType.aliasArguments.isNotEmpty &&
216+
!elementType.aliasArguments.every((t) => t.name == 'dynamic')) {
217+
buf.write('&lt;');
218+
buf.writeAll(
219+
elementType.aliasArguments.map((t) => t.nameWithGenerics), ', ');
220+
buf.write('>');
221+
}
222+
buf.write(elementType.nullabilitySuffix);
223+
return wrapNullability(elementType, buf.toString());
224+
}
225+
}
226+
163227
class CallableElementTypeRendererMd
164228
extends ElementTypeRenderer<CallableElementType> {
165229
@override

lib/src/render/renderer_factory.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ abstract class RendererFactory {
4646
ElementTypeRenderer<ParameterizedElementType>
4747
get parameterizedElementTypeRenderer;
4848

49+
ElementTypeRenderer<AliasedElementType> get aliasedElementTypeRenderer;
50+
4951
ElementTypeRenderer<CallableElementType> get callableElementTypeRenderer;
5052

5153
EnumFieldRenderer get enumFieldRenderer;
@@ -90,6 +92,10 @@ class HtmlRenderFactory extends RendererFactory {
9092
get parameterizedElementTypeRenderer =>
9193
ParameterizedElementTypeRendererHtml();
9294

95+
@override
96+
ElementTypeRenderer<AliasedElementType> get aliasedElementTypeRenderer =>
97+
AliasedElementTypeRendererHtml();
98+
9399
@override
94100
EnumFieldRenderer get enumFieldRenderer => EnumFieldRendererHtml();
95101

@@ -146,6 +152,10 @@ class MdRenderFactory extends RendererFactory {
146152
get parameterizedElementTypeRenderer =>
147153
ParameterizedElementTypeRendererMd();
148154

155+
@override
156+
ElementTypeRenderer<AliasedElementType> get aliasedElementTypeRenderer =>
157+
AliasedElementTypeRendererMd();
158+
149159
@override
150160
EnumFieldRenderer get enumFieldRenderer => EnumFieldRendererMd();
151161

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ environment:
77
sdk: '>=2.11.99 <3.0.0'
88

99
dependencies:
10-
analyzer: ^1.1.0
10+
analyzer: ^1.2.0
1111
args: ^2.0.0
1212
charcode: ^1.2.0
1313
collection: ^1.2.0

test/end2end/model_special_cases_test.dart

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -107,25 +107,35 @@ void main() {
107107
orderedEquals(genericParameters));
108108
}
109109

110+
void expectAliasedTypeName(AliasedElementType n, expected) {
111+
expect(n.aliasElement.name, expected);
112+
}
113+
110114
test('typedef references display aliases', () {
111-
var f = C.allFields.firstWhere((f) => f.name == 'f');
112115
var g = C.instanceMethods.firstWhere((m) => m.name == 'g');
113-
var a = generalizedTypedefs.properties.firstWhere((p) => p.name == 'a');
114-
var b = C2.allFields.firstWhere((f) => f.name == 'b');
116+
115117
var c = C2.allFields.firstWhere((f) => f.name == 'c');
116118
var d = C2.instanceMethods.firstWhere((f) => f.name == 'd');
117119

118-
expect(a.modelType.name, equals('T0'));
119-
expect(b.modelType.name, equals('T0'));
120-
expect(c.modelType.name, equals('T1'));
121-
expect(d.modelType.returnType.name, equals('T2'));
122-
expect(d.parameters.first.modelType.name, equals('T3'));
123-
expect(d.parameters.last.modelType.name, equals('T4'));
124-
125-
expect(f.modelType.name, equals('T0'));
126-
expect(g.modelType.returnType.name, equals('T1'));
127-
expect(g.modelType.parameters.first.modelType.name, equals('T2'));
128-
expect(g.modelType.parameters.last.modelType.name, equals('T3'));
120+
expectAliasedTypeName(c.modelType, equals('T1'));
121+
expectAliasedTypeName(d.modelType.returnType, equals('T2'));
122+
expectAliasedTypeName(d.parameters.first.modelType, equals('T3'));
123+
expectAliasedTypeName(d.parameters.last.modelType, equals('T4'));
124+
125+
expectAliasedTypeName(g.modelType.returnType, equals('T1'));
126+
expectAliasedTypeName(
127+
g.modelType.parameters.first.modelType, equals('T2'));
128+
expectAliasedTypeName(
129+
g.modelType.parameters.last.modelType, equals('T3'));
130+
});
131+
132+
test('typedef references to special types work', () {
133+
var a = generalizedTypedefs.properties.firstWhere((p) => p.name == 'a');
134+
var b = C2.allFields.firstWhere((f) => f.name == 'b');
135+
var f = C.allFields.firstWhere((f) => f.name == 'f');
136+
expectAliasedTypeName(a.modelType, equals('T0'));
137+
expectAliasedTypeName(b.modelType, equals('T0'));
138+
expectAliasedTypeName(f.modelType, equals('T0'));
129139
}, skip: 'dart-lang/sdk#45921');
130140

131141
test('basic non-function typedefs work', () {

0 commit comments

Comments
 (0)