Skip to content

Commit 822504a

Browse files
authored
Generic metadata and type parameters fixup (#2649)
* incremental * intermediate * Seems to work * cleanups * obliterate some obsolete hoop jumping for type arguments * More cleanups * separate linked / normal generic parameters * dartfmt * Add markdown renderer * Move tests around for 2.13 stable * dartfmt * Fix a template... * fix merge error * allow for some fixes in analyzer * dartfmt
1 parent 6b957de commit 822504a

11 files changed

+230
-160
lines changed

Diff for: lib/src/element_type.dart

+12-56
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,10 @@ abstract class DefinedElementType extends ElementType {
383383
}
384384

385385
/// Any callable ElementType will mix-in this class, whether anonymous or not.
386-
abstract class CallableElementTypeMixin implements ElementType {
387-
Iterable<ElementType> _typeArguments;
386+
mixin CallableElementTypeMixin implements ElementType {
387+
@override
388+
// TODO(jcollins-g): remove after dart-lang/dartdoc#2648 is fixed.
389+
String get linkedName;
388390

389391
ModelElement get returnElement => returnType is DefinedElementType
390392
? (returnType as DefinedElementType).modelElement
@@ -400,50 +402,12 @@ abstract class CallableElementTypeMixin implements ElementType {
400402
@override
401403
FunctionType get type => _type;
402404

403-
// TODO(jcollins-g): Rewrite this and improve object model so this doesn't
404-
// require type checking everywhere.
405-
Iterable<ElementType> get typeArguments {
406-
if (_typeArguments == null) {
407-
Iterable<DartType> dartTypeArguments;
408-
if (returnedFrom is FunctionTypeElementType) {
409-
if (type.typeFormals.isEmpty) {
410-
dartTypeArguments = type.aliasArguments;
411-
} else {
412-
dartTypeArguments = type.typeFormals.map(_legacyTypeParameterType);
413-
}
414-
} else {
415-
if (type.typeFormals.isEmpty) {
416-
dartTypeArguments = type.aliasArguments;
417-
} else if (returnedFrom != null &&
418-
returnedFrom.type.element is GenericFunctionTypeElement) {
419-
_typeArguments = (returnedFrom as DefinedElementType).typeArguments;
420-
} else {
421-
dartTypeArguments = type.typeFormals.map(_legacyTypeParameterType);
422-
}
423-
}
424-
if (dartTypeArguments != null) {
425-
_typeArguments = dartTypeArguments
426-
.map((f) => ElementType.from(f, library, packageGraph))
427-
.toList();
428-
}
429-
}
430-
return _typeArguments;
431-
}
432-
433-
/// Return the [TypeParameterType] with the legacy nullability for the given
434-
/// type parameter [element].
435-
///
436-
/// TODO(scheglov): This method is a work around that fact that DartDoc
437-
/// currently represents both type formals and uses of them as actual types,
438-
/// as [TypeParameterType]s. This was not perfect, but worked before Null
439-
/// safety. With Null safety, types have nullability suffixes, but type
440-
/// formals should not. Eventually we should separate models for type formals
441-
/// and types.
442-
static TypeParameterType _legacyTypeParameterType(
443-
TypeParameterElement element,
444-
) {
445-
return element.instantiate(nullabilitySuffix: NullabilitySuffix.star);
446-
}
405+
Iterable<ElementType> _typeArguments;
406+
Iterable<ElementType> get typeArguments =>
407+
_typeArguments ??= type.aliasArguments
408+
?.map((f) => ElementType.from(f, library, packageGraph))
409+
?.toList() ??
410+
[];
447411
}
448412

449413
/// A callable type that may or may not be backed by a declaration using the generic
@@ -455,16 +419,8 @@ class CallableElementType extends ParameterizedElementType
455419
: super(t, library, packageGraph, element, returnedFrom);
456420

457421
@override
458-
String get linkedName {
459-
if (_linkedName == null) {
460-
if (name != null && name.isNotEmpty) {
461-
_linkedName = super.linkedName;
462-
} else {
463-
_linkedName = _renderer.renderLinkedName(this);
464-
}
465-
}
466-
return _linkedName;
467-
}
422+
String get name =>
423+
super.name != null && super.name.isNotEmpty ? super.name : 'Function';
468424

469425
@override
470426
ElementTypeRenderer<CallableElementType> get _renderer =>

Diff for: lib/src/generator/templates.renderers.dart

+70-67
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,26 @@ class _Renderer_CallableElementTypeMixin
500500
_propertyMapCache.putIfAbsent(
501501
CT_,
502502
() => {
503-
..._Renderer_Object.propertyMap<CT_>(),
503+
'linkedName': Property(
504+
getValue: (CT_ c) => c.linkedName,
505+
renderVariable:
506+
(CT_ c, Property<CT_> self, List<String> remainingNames) {
507+
if (remainingNames.isEmpty) {
508+
return self.getValue(c).toString();
509+
}
510+
var name = remainingNames.first;
511+
var nextProperty =
512+
_Renderer_String.propertyMap().getValue(name);
513+
return nextProperty.renderVariable(self.getValue(c),
514+
nextProperty, [...remainingNames.skip(1)]);
515+
},
516+
isNullValue: (CT_ c) => c.linkedName == null,
517+
renderValue:
518+
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
519+
return _render_String(c.linkedName, ast, r.template,
520+
parent: r);
521+
},
522+
),
504523
'returnElement': Property(
505524
getValue: (CT_ c) => c.returnElement,
506525
renderVariable:
@@ -6042,60 +6061,35 @@ String _render_FunctionTypedef(
60426061

60436062
class _Renderer_FunctionTypedef extends RendererBase<FunctionTypedef> {
60446063
static final Map<Type, Object> _propertyMapCache = {};
6045-
static Map<String, Property<CT_>> propertyMap<
6046-
CT_ extends FunctionTypedef>() =>
6047-
_propertyMapCache.putIfAbsent(
6048-
CT_,
6049-
() => {
6050-
..._Renderer_Typedef.propertyMap<CT_>(),
6051-
'aliasedType': Property(
6052-
getValue: (CT_ c) => c.aliasedType,
6053-
renderVariable: (CT_ c, Property<CT_> self,
6054-
List<String> remainingNames) =>
6055-
self.renderSimpleVariable(
6056-
c, remainingNames, 'FunctionType'),
6057-
isNullValue: (CT_ c) => c.aliasedType == null,
6058-
renderValue:
6059-
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
6060-
return renderSimple(c.aliasedType, ast, r.template,
6061-
parent: r);
6062-
},
6063-
),
6064-
'genericTypeParameters': Property(
6065-
getValue: (CT_ c) => c.genericTypeParameters,
6066-
renderVariable: (CT_ c, Property<CT_> self,
6067-
List<String> remainingNames) =>
6068-
self.renderSimpleVariable(
6069-
c, remainingNames, 'List<TypeParameterElement>'),
6070-
renderIterable:
6071-
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
6072-
return c.genericTypeParameters.map(
6073-
(e) => renderSimple(e, ast, r.template, parent: r));
6074-
},
6075-
),
6076-
'modelType': Property(
6077-
getValue: (CT_ c) => c.modelType,
6078-
renderVariable:
6079-
(CT_ c, Property<CT_> self, List<String> remainingNames) {
6080-
if (remainingNames.isEmpty) {
6081-
return self.getValue(c).toString();
6082-
}
6083-
var name = remainingNames.first;
6084-
var nextProperty =
6085-
_Renderer_CallableElementTypeMixin.propertyMap()
6086-
.getValue(name);
6087-
return nextProperty.renderVariable(self.getValue(c),
6088-
nextProperty, [...remainingNames.skip(1)]);
6089-
},
6090-
isNullValue: (CT_ c) => c.modelType == null,
6091-
renderValue:
6092-
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
6093-
return _render_CallableElementTypeMixin(
6094-
c.modelType, ast, r.template,
6095-
parent: r);
6096-
},
6097-
),
6098-
});
6064+
static Map<String, Property<CT_>>
6065+
propertyMap<CT_ extends FunctionTypedef>() =>
6066+
_propertyMapCache.putIfAbsent(
6067+
CT_,
6068+
() => {
6069+
..._Renderer_Typedef.propertyMap<CT_>(),
6070+
'modelType': Property(
6071+
getValue: (CT_ c) => c.modelType,
6072+
renderVariable: (CT_ c, Property<CT_> self,
6073+
List<String> remainingNames) {
6074+
if (remainingNames.isEmpty) {
6075+
return self.getValue(c).toString();
6076+
}
6077+
var name = remainingNames.first;
6078+
var nextProperty =
6079+
_Renderer_CallableElementTypeMixin.propertyMap()
6080+
.getValue(name);
6081+
return nextProperty.renderVariable(self.getValue(c),
6082+
nextProperty, [...remainingNames.skip(1)]);
6083+
},
6084+
isNullValue: (CT_ c) => c.modelType == null,
6085+
renderValue: (CT_ c, RendererBase<CT_> r,
6086+
List<MustachioNode> ast) {
6087+
return _render_CallableElementTypeMixin(
6088+
c.modelType, ast, r.template,
6089+
parent: r);
6090+
},
6091+
),
6092+
});
60996093

61006094
_Renderer_FunctionTypedef(
61016095
FunctionTypedef context, RendererBase<Object> parent, Template template)
@@ -13914,18 +13908,6 @@ class _Renderer_Typedef extends RendererBase<Typedef> {
1391413908
parent: r);
1391513909
},
1391613910
),
13917-
'genericTypeParameters': Property(
13918-
getValue: (CT_ c) => c.genericTypeParameters,
13919-
renderVariable: (CT_ c, Property<CT_> self,
13920-
List<String> remainingNames) =>
13921-
self.renderSimpleVariable(
13922-
c, remainingNames, 'List<TypeParameterElement>'),
13923-
renderIterable:
13924-
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
13925-
return c.genericTypeParameters.map(
13926-
(e) => renderSimple(e, ast, r.template, parent: r));
13927-
},
13928-
),
1392913911
'href': Property(
1393013912
getValue: (CT_ c) => c.href,
1393113913
renderVariable:
@@ -13971,6 +13953,27 @@ class _Renderer_Typedef extends RendererBase<Typedef> {
1397113953
return _render_String(c.kind, ast, r.template, parent: r);
1397213954
},
1397313955
),
13956+
'linkedGenericParameters': Property(
13957+
getValue: (CT_ c) => c.linkedGenericParameters,
13958+
renderVariable:
13959+
(CT_ c, Property<CT_> self, List<String> remainingNames) {
13960+
if (remainingNames.isEmpty) {
13961+
return self.getValue(c).toString();
13962+
}
13963+
var name = remainingNames.first;
13964+
var nextProperty =
13965+
_Renderer_String.propertyMap().getValue(name);
13966+
return nextProperty.renderVariable(self.getValue(c),
13967+
nextProperty, [...remainingNames.skip(1)]);
13968+
},
13969+
isNullValue: (CT_ c) => c.linkedGenericParameters == null,
13970+
renderValue:
13971+
(CT_ c, RendererBase<CT_> r, List<MustachioNode> ast) {
13972+
return _render_String(
13973+
c.linkedGenericParameters, ast, r.template,
13974+
parent: r);
13975+
},
13976+
),
1397413977
'modelType': Property(
1397513978
getValue: (CT_ c) => c.modelType,
1397613979
renderVariable:

Diff for: lib/src/model/typedef.dart

+3-17
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ class Typedef extends ModelElement
3333
@override
3434
String get genericParameters => _renderer.renderGenericParameters(this);
3535

36-
List<TypeParameterElement> get genericTypeParameters =>
37-
element.typeParameters;
36+
@override
37+
String get linkedGenericParameters =>
38+
_renderer.renderLinkedGenericParameters(this);
3839

3940
@override
4041
String get filePath => '${library.dirName}/$fileName';
@@ -87,21 +88,6 @@ class FunctionTypedef extends Typedef {
8788
TypeAliasElement element, Library library, PackageGraph packageGraph)
8889
: super(element, library, packageGraph);
8990

90-
@override
91-
FunctionType get aliasedType => super.aliasedType;
92-
93-
@override
94-
List<TypeParameterElement> get genericTypeParameters {
95-
var aliasedTypeElement = aliasedType.aliasElement;
96-
if (aliasedTypeElement is FunctionTypedElement) {
97-
return aliasedTypeElement.typeParameters;
98-
}
99-
if (aliasedType.typeFormals.isNotEmpty == true) {
100-
return aliasedType.typeFormals;
101-
}
102-
return super.genericTypeParameters;
103-
}
104-
10591
@override
10692
CallableElementTypeMixin get modelType => super.modelType;
10793
}

Diff for: lib/src/render/element_type_renderer.dart

+32
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,22 @@ class CallableElementTypeRendererHtml
141141
buf.write(elementType.returnType.linkedName);
142142
return wrapNullabilityParens(elementType, buf.toString());
143143
}
144+
145+
@override
146+
String renderNameWithGenerics(CallableElementType elementType) {
147+
var buf = StringBuffer();
148+
buf.write(elementType.name);
149+
if (elementType.typeArguments != null) {
150+
if (elementType.typeArguments.isNotEmpty &&
151+
!elementType.typeArguments.every((t) => t.name == 'dynamic')) {
152+
buf.write('&lt;');
153+
buf.writeAll(
154+
elementType.typeArguments.map((t) => t.nameWithGenerics), ', ');
155+
buf.write('>');
156+
}
157+
}
158+
return wrapNullability(elementType, buf.toString());
159+
}
144160
}
145161

146162
// Markdown implementations
@@ -255,4 +271,20 @@ class CallableElementTypeRendererMd
255271
buf.write(elementType.returnType.linkedName);
256272
return wrapNullabilityParens(elementType, buf.toString());
257273
}
274+
275+
@override
276+
String renderNameWithGenerics(CallableElementType elementType) {
277+
var buf = StringBuffer();
278+
buf.write(elementType.name);
279+
if (elementType.typeArguments != null) {
280+
if (elementType.typeArguments.isNotEmpty &&
281+
!elementType.typeArguments.every((t) => t.name == 'dynamic')) {
282+
buf.write('&lt;');
283+
buf.writeAll(
284+
elementType.typeArguments.map((t) => t.nameWithGenerics), ', ');
285+
buf.write('>');
286+
}
287+
}
288+
return wrapNullability(elementType, buf.toString());
289+
}
258290
}

Diff for: lib/src/render/type_parameters_renderer.dart

+20-5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import 'package:dartdoc/src/model/type_parameter.dart';
66

77
abstract class TypeParametersRenderer {
8+
const TypeParametersRenderer();
9+
810
String renderGenericParameters(TypeParameters typeParameters);
911

1012
String renderLinkedGenericParameters(TypeParameters typeParameters);
@@ -19,7 +21,10 @@ class TypeParametersRendererHtml implements TypeParametersRenderer {
1921
return '';
2022
}
2123
var joined = typeParameters.typeParameters
22-
.map((t) => t.name)
24+
.map((t) => [
25+
...t.annotations.map((a) => a.linkedNameWithParameters),
26+
t.name
27+
].join(' '))
2328
.join('</span>, <span class="type-parameter">');
2429
return '&lt;<wbr><span class="type-parameter">$joined</span>&gt;';
2530
}
@@ -30,7 +35,10 @@ class TypeParametersRendererHtml implements TypeParametersRenderer {
3035
return '';
3136
}
3237
var joined = typeParameters.typeParameters
33-
.map((t) => t.linkedName)
38+
.map((t) => [
39+
...t.annotations.map((a) => a.linkedNameWithParameters),
40+
t.linkedName
41+
].join(' '))
3442
.join('</span>, <span class="type-parameter">');
3543
return '<span class="signature">&lt;<wbr><span class="type-parameter">$joined</span>&gt;</span>';
3644
}
@@ -40,12 +48,19 @@ class TypeParametersRendererMd implements TypeParametersRenderer {
4048
const TypeParametersRendererMd();
4149

4250
@override
43-
String renderGenericParameters(TypeParameters typeParameters) =>
44-
_compose(typeParameters.typeParameters, (t) => t.name);
51+
String renderGenericParameters(TypeParameters typeParameters) => _compose(
52+
typeParameters.typeParameters,
53+
(t) => [...t.annotations.map((a) => a.linkedNameWithParameters), t.name]
54+
.join(' '));
4555

4656
@override
4757
String renderLinkedGenericParameters(TypeParameters typeParameters) =>
48-
_compose(typeParameters.typeParameters, (t) => t.linkedName);
58+
_compose(
59+
typeParameters.typeParameters,
60+
(t) => [
61+
...t.annotations.map((a) => a.linkedNameWithParameters),
62+
t.linkedName
63+
].join(' '));
4964

5065
String _compose(List<TypeParameter> typeParameters,
5166
String Function(TypeParameter) mapfn) {

0 commit comments

Comments
 (0)