Migrate Constructor element model (#3987)
diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart
index 803a73f..3203d95 100644
--- a/lib/src/generator/templates.runtime_renderers.dart
+++ b/lib/src/generator/templates.runtime_renderers.dart
@@ -3571,6 +3571,38 @@
);
},
),
+ 'fileName': Property(
+ getValue: (CT_ c) => c.fileName,
+ renderVariable: (
+ CT_ c,
+ Property<CT_> self,
+ List<String> remainingNames,
+ ) {
+ if (remainingNames.isEmpty) {
+ return self.getValue(c).toString();
+ }
+ var name = remainingNames.first;
+ var nextProperty = _Renderer_String.propertyMap().getValue(
+ name,
+ );
+ return nextProperty.renderVariable(
+ self.getValue(c) as String,
+ nextProperty,
+ [...remainingNames.skip(1)],
+ );
+ },
+
+ isNullValue: (CT_ c) => false,
+
+ renderValue: (
+ CT_ c,
+ RendererBase<CT_> r,
+ List<MustachioNode> ast,
+ StringSink sink,
+ ) {
+ _render_String(c.fileName, ast, r.template, sink, parent: r);
+ },
+ ),
'fullKind': Property(
getValue: (CT_ c) => c.fullKind,
renderVariable: (
diff --git a/lib/src/model/constructor.dart b/lib/src/model/constructor.dart
index 343daba..f8ce976 100644
--- a/lib/src/model/constructor.dart
+++ b/lib/src/model/constructor.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// ignore_for_file: analyzer_use_new_elements
-
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/source/line_info.dart';
@@ -17,7 +15,8 @@
class Constructor extends ModelElement with ContainerMember, TypeParameters {
@override
- ConstructorElement get element => element2.asElement;
+ // ignore: analyzer_use_new_elements
+ ConstructorElement get element => element2.asElement;
@override
final ConstructorElement2 element2;
@@ -26,7 +25,7 @@
@override
CharacterLocation? get characterLocation {
- if (element.isSynthetic) {
+ if (element2.isSynthetic) {
// Make warnings for a synthetic constructor refer to somewhere reasonable
// since a synthetic constructor has no definition independent of the
// parent class.
@@ -39,11 +38,11 @@
bool get isPublic {
if (!super.isPublic) return false;
if (element2.hasPrivateName) return false;
- var class_ = element.enclosingElement3;
+ var class_ = element2.enclosingElement2;
// Enums cannot be explicitly constructed or extended.
- if (class_ is EnumElement) return false;
- if (class_ is ClassElement) {
- if (element.isFactory) return true;
+ if (class_ is EnumElement2) return false;
+ if (class_ is ClassElement2) {
+ if (element2.isFactory) return true;
if (class_.isSealed ||
(class_.isAbstract && class_.isFinal) ||
(class_.isAbstract && class_.isInterface)) {
@@ -62,7 +61,12 @@
@override
Container get enclosingElement =>
- getModelFor(element.enclosingElement3, library) as Container;
+ getModelFor2(element2.enclosingElement2, library) as Container;
+
+ @override
+ String get fileName =>
+ // TODO(srawlins): It would be great to use `new.html` as the file name.
+ isUnnamedConstructor ? '${enclosingElement.name}.html' : '$name.html';
@override
String get aboveSidebarPath => enclosingElement.sidebarPath;
@@ -77,39 +81,32 @@
}
@override
- String get fullyQualifiedName {
- if (isUnnamedConstructor) return super.fullyQualifiedName;
- return '${library.name}.$name';
- }
+ String get fullyQualifiedName => '${library.name}.$name';
@override
- bool get isConst => element.isConst;
+ bool get isConst => element2.isConst;
- bool get isUnnamedConstructor => name == enclosingElement.name;
+ bool get isUnnamedConstructor => element2.name3 == 'new';
- bool get isFactory => element.isFactory;
+ bool get isFactory => element2.isFactory;
@override
Kind get kind => Kind.constructor;
- late final Callable modelType = getTypeFor(element.type, library) as Callable;
+ late final Callable modelType =
+ getTypeFor(element2.type, library) as Callable;
@override
- String get name {
- // TODO(jcollins-g): After the old lookup code is retired, rationalize
- // [name] around the conventions used in referenceChildren and replace
- // code there and elsewhere with simple references to the name.
- var constructorName = element.name;
- if (constructorName.isEmpty) {
- return enclosingElement.name;
- }
- return '${enclosingElement.name}.$constructorName';
- }
+ String get name =>
+ // TODO(jcollins-g): After the old lookup code is retired, rationalize
+ // [name] around the conventions used in referenceChildren and replace
+ // code there and elsewhere with simple references to the name.
+ '${enclosingElement.name}.${element2.name3}';
@override
String get nameWithGenerics {
- var constructorName = element.name;
- if (constructorName.isEmpty) {
+ var constructorName = element2.name3!;
+ if (constructorName == 'new') {
return '${enclosingElement.name}$genericParameters';
}
return '${enclosingElement.name}$genericParameters.$constructorName';
@@ -117,7 +114,7 @@
String? get shortName {
if (name.contains('.')) {
- return name.substring(element.enclosingElement3.name.length + 1);
+ return name.substring(element2.enclosingElement2.name3!.length + 1);
} else {
return name;
}
@@ -126,17 +123,17 @@
@override
late final Map<String, CommentReferable> referenceChildren = () {
// Find the element that [parameter] is _really_ referring to.
- Element? dereferenceParameter(ParameterElement? parameter) =>
+ Element2? dereferenceParameter(FormalParameterElement? parameter) =>
switch (parameter) {
- FieldFormalParameterElement() => parameter.field,
- SuperFormalParameterElement() =>
- dereferenceParameter(parameter.superConstructorParameter),
+ FieldFormalParameterElement2() => parameter.field2,
+ SuperFormalParameterElement2() =>
+ dereferenceParameter(parameter.superConstructorParameter2),
_ => parameter
};
var parameterElements = parameters.map((parameter) {
- var element = dereferenceParameter(parameter.element);
- return element == null ? parameter : getModelForElement(element);
+ var element = dereferenceParameter(parameter.element2);
+ return element == null ? parameter : getModelForElement2(element);
});
return {
for (var element in parameterElements) element.referenceName: element,
@@ -146,5 +143,5 @@
@override
String get referenceName =>
- isUnnamedConstructor ? enclosingElement.name : element.name;
+ isUnnamedConstructor ? enclosingElement.name : element2.name3!;
}
diff --git a/lib/src/model/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart
index ace35bb..0475c1d 100644
--- a/lib/src/model/getter_setter_combo.dart
+++ b/lib/src/model/getter_setter_combo.dart
@@ -83,7 +83,6 @@
String linkifyConstantValue(String original) {
if (_constantInitializer is! InstanceCreationExpression) return original;
- var constructorName = _constantInitializer.constructorName.toString();
var element = _constantInitializer.constructorName.element;
if (element == null) return original;
@@ -93,8 +92,11 @@
// TODO(jcollins-g): this logic really should be integrated into
// `Constructor`, but that's not trivial because of `linkedName`'s usage.
- if (enclosingElement.name == target.name) {
- return original.replaceAll(constructorName, target.linkedName);
+ if (target.isUnnamedConstructor) {
+ var parts = target.linkedNameParts;
+ // We don't want the `.new` representation of an unnamed constructor.
+ var linkedName = '${parts.tag}${enclosingElement.name}${parts.endTag}';
+ return original.replaceAll(enclosingElement.name, linkedName);
}
return original.replaceAll('${enclosingElement.name}.${target.name}',
'${enclosingElement.linkedName}.${target.linkedName}');
diff --git a/lib/src/model/inheriting_container.dart b/lib/src/model/inheriting_container.dart
index 7cd552f..0f8c0ec 100644
--- a/lib/src/model/inheriting_container.dart
+++ b/lib/src/model/inheriting_container.dart
@@ -28,7 +28,7 @@
@override
late final List<Constructor> publicConstructorsSorted =
- constructors.wherePublic.toList(growable: false)..sort();
+ constructors.wherePublic.toList(growable: false)..sort(byName);
@override
@visibleForOverriding
diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart
index 2c7f3f8..97e4075 100644
--- a/lib/src/model/model_element.dart
+++ b/lib/src/model/model_element.dart
@@ -228,9 +228,9 @@
if (e is ExecutableMember) {
originalMember = e;
e = e.baseElement;
- } else if (e is FieldMember){
+ } else if (e is FieldMember) {
originalMember = e;
- e = e.baseElement;
+ e = e.baseElement;
}
// Return the cached ModelElement if it exists.
@@ -676,7 +676,14 @@
@override
Library get library => _library;
+ /// The name of this element, wrapped in an HTML link (an `<a>` tag) if [href]
+ /// is non-`null`.
late final String linkedName = () {
+ var parts = linkedNameParts;
+ return '${parts.tag}${parts.text}${parts.endTag}';
+ }();
+
+ ({String tag, String text, String endTag}) get linkedNameParts {
// If `name` is empty, we probably have the wrong Element association or
// there's an analyzer issue.
assert(name.isNotEmpty ||
@@ -689,12 +696,16 @@
if (isPublicAndPackageDocumented) {
warn(PackageWarning.noCanonicalFound);
}
- return htmlEscape.convert(name);
+ return (tag: '', text: htmlEscape.convert(name), endTag: '');
}
var cssClass = isDeprecated ? ' class="deprecated"' : '';
- return '<a$cssClass href="$href">$displayName</a>';
- }();
+ return (
+ tag: '<a$cssClass href="$href">',
+ text: displayName,
+ endTag: '</a>'
+ );
+ }
ParameterRenderer get _parameterRenderer => const ParameterRendererHtml();
diff --git a/lib/src/model/nameable.dart b/lib/src/model/nameable.dart
index a7fc9c4..423948f 100644
--- a/lib/src/model/nameable.dart
+++ b/lib/src/model/nameable.dart
@@ -12,6 +12,7 @@
import 'package:collection/collection.dart';
import 'package:dartdoc/src/element_type.dart';
import 'package:dartdoc/src/model/accessor.dart';
+import 'package:dartdoc/src/model/constructor.dart';
import 'package:dartdoc/src/model/container.dart';
import 'package:dartdoc/src/model/library.dart';
import 'package:dartdoc/src/model/model_element.dart';
@@ -121,7 +122,7 @@
enclosingContainer: enclosingContainer,
);
- /// Returns the [ModelElement] for [element], instantiating it if needed.
+ /// Returns the [ModelElement] for [element], instantiating it if needed.
///
/// A convenience method for [ModelElement.forPropertyInducingElement], see
/// its documentation.
@@ -155,6 +156,12 @@
return compareAsciiLowerCaseNatural(a.displayName, b.displayName);
}
+ if (a is Constructor && b is Constructor) {
+ var aName = a.name.replaceFirst('.new', '');
+ var bName = b.name.replaceFirst('.new', '');
+ return compareAsciiLowerCaseNatural(aName, bName);
+ }
+
var stringCompare = compareAsciiLowerCaseNatural(a.name, b.name);
if (stringCompare != 0) {
return stringCompare;
diff --git a/test/constructors_test.dart b/test/constructors_test.dart
index 81f7449..2e2d74c 100644
--- a/test/constructors_test.dart
+++ b/test/constructors_test.dart
@@ -27,9 +27,8 @@
}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
- // TODO(srawlins): This should be `constructors.C.new`.
- expect(c.fullyQualifiedName, 'constructors.C.C');
+ expect(c.name, equals('C.new'));
+ expect(c.fullyQualifiedName, 'constructors.C.new');
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -42,9 +41,8 @@
}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
- // TODO(srawlins): This should be `constructors.C.new`.
- expect(c.fullyQualifiedName, 'constructors.C.C');
+ expect(c.name, equals('C.new'));
+ expect(c.fullyQualifiedName, 'constructors.C.new');
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -57,9 +55,8 @@
}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
- // TODO(srawlins): This should be `constructors.C.new`.
- expect(c.fullyQualifiedName, 'constructors.C.C');
+ expect(c.name, equals('C.new'));
+ expect(c.fullyQualifiedName, 'constructors.C.new');
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -86,7 +83,7 @@
}
''');
var c = library.classes.named('_C').constructors.first;
- expect(c.name, equals('_C'));
+ expect(c.name, equals('_C.new'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -96,7 +93,7 @@
class C {}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
+ expect(c.name, equals('C.new'));
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '');
}
@@ -123,7 +120,7 @@
}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
+ expect(c.name, equals('C.new'));
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -136,9 +133,8 @@
}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
- // TODO(srawlins): This should be `constructors.C.new`.
- expect(c.fullyQualifiedName, 'constructors.C.C');
+ expect(c.name, equals('C.new'));
+ expect(c.fullyQualifiedName, 'constructors.C.new');
expect(c.isPublic, isTrue);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -151,7 +147,7 @@
}
''');
var c = library.classes.named('C').constructors.first;
- expect(c.name, equals('C'));
+ expect(c.name, equals('C.new'));
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -180,9 +176,8 @@
}
''');
var e = library.enums.named('E').constructors.first;
- expect(e.name, equals('E'));
- // TODO(srawlins): This should be `constructors.E.new`.
- expect(e.fullyQualifiedName, 'constructors.E.E');
+ expect(e.name, equals('E.new'));
+ expect(e.fullyQualifiedName, 'constructors.E.new');
expect(e.isPublic, isFalse);
expect(e.documentationAsHtml, '<p>Constructor.</p>');
}
@@ -196,7 +191,6 @@
''');
var etNamed =
library.extensionTypes.named('ET').constructors.named('ET.named');
- expect(etNamed.name, equals('ET.named'));
expect(etNamed.fullyQualifiedName, 'constructors.ET.named');
expect(etNamed.isPublic, isTrue);
expect(etNamed.documentationAsHtml, '<p>Constructor.</p>');
@@ -208,7 +202,6 @@
''');
var etNamed =
library.extensionTypes.named('ET').constructors.named('ET.named');
- expect(etNamed.name, equals('ET.named'));
expect(etNamed.fullyQualifiedName, 'constructors.ET.named');
expect(etNamed.isPublic, isTrue);
}
@@ -217,10 +210,8 @@
var library = await bootPackageWithLibrary('''
extension type ET(int it) {}
''');
- var et = library.extensionTypes.named('ET').constructors.named('ET');
- expect(et.name, equals('ET'));
- // TODO(srawlins): This should be `constructors.ET.new`.
- expect(et.fullyQualifiedName, 'constructors.ET.ET');
+ var et = library.extensionTypes.named('ET').constructors.named('ET.new');
+ expect(et.fullyQualifiedName, 'constructors.ET.new');
expect(et.isPublic, isTrue);
}
@@ -231,10 +222,9 @@
ET(this.it);
}
''');
- var etNamed = library.extensionTypes.named('ET').constructors.named('ET');
- expect(etNamed.name, equals('ET'));
- // TODO(srawlins): This should be `constructors.ET.new`.
- expect(etNamed.fullyQualifiedName, 'constructors.ET.ET');
+ var etNamed =
+ library.extensionTypes.named('ET').constructors.named('ET.new');
+ expect(etNamed.fullyQualifiedName, 'constructors.ET.new');
expect(etNamed.isPublic, isTrue);
expect(etNamed.documentationAsHtml, '<p>Constructor.</p>');
}
diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart
index b8745b7..b49f7f9 100644
--- a/test/end2end/model_test.dart
+++ b/test/end2end/model_test.dart
@@ -2414,7 +2414,7 @@
aNonDefaultConstructor = baseForDocComments.constructors
.named('BaseForDocComments.aNonDefaultConstructor');
defaultConstructor =
- baseForDocComments.constructors.named('BaseForDocComments');
+ baseForDocComments.constructors.named('BaseForDocComments.new');
somethingShadowyParameter =
defaultConstructor.parameters.named('somethingShadowy');
initializeMe = baseForDocComments.allFields.named('initializeMe');
@@ -2473,7 +2473,7 @@
anotherConstructor = FactoryConstructorThings.constructors
.named('FactoryConstructorThings.anotherConstructor');
factoryConstructorThingsDefault = FactoryConstructorThings.constructors
- .named('FactoryConstructorThings');
+ .named('FactoryConstructorThings.new');
aName = anotherName.parameters.named('aName');
anotherNameParameter = anotherName.parameters.named('anotherName');
@@ -3974,8 +3974,10 @@
});
test('substrings of the constant values type are not linked (#1535)', () {
- expect(aName.constantValue,
- 'const <a href="${htmlBasePlaceholder}ex/ExtendedShortName/ExtendedShortName.html">ExtendedShortName</a>("hello there")');
+ expect(
+ aName.constantValue,
+ 'const <a href="${htmlBasePlaceholder}ex/ExtendedShortName/ExtendedShortName.html">ExtendedShortName</a>("hello there")',
+ );
});
test('constant field values are escaped', () {
@@ -4040,10 +4042,10 @@
constCat = exLibrary.classes.named('ConstantCat');
constructorTester = fakeLibrary.classes.named('ConstructorTester');
constCatConstructor = constCat.constructors.first;
- appleDefaultConstructor = apple.constructors.named('Apple');
+ appleDefaultConstructor = apple.constructors.named('Apple.new');
appleConstructorFromString = apple.constructors.named('Apple.fromString');
constructorTesterDefault =
- constructorTester.constructors.named('ConstructorTester');
+ constructorTester.constructors.named('ConstructorTester.new');
constructorTesterFromSomething = constructorTester.constructors
.named('ConstructorTester.fromSomething');
referToADefaultConstructor =
@@ -4095,8 +4097,8 @@
test('has constructor', () {
expect(appleDefaultConstructor, isNotNull);
- expect(appleDefaultConstructor.name, equals('Apple'));
- expect(appleDefaultConstructor.shortName, equals('Apple'));
+ expect(appleDefaultConstructor.name, equals('Apple.new'));
+ expect(appleDefaultConstructor.shortName, equals('new'));
});
test('title has factory qualifier', () {
diff --git a/test/parameters_test.dart b/test/parameters_test.dart
index f43a636..d9c3908 100644
--- a/test/parameters_test.dart
+++ b/test/parameters_test.dart
@@ -251,7 +251,7 @@
C(this.p);
}
''');
- var cConstructor = library.classes.named('C').constructors.named('C');
+ var cConstructor = library.classes.named('C').constructors.named('C.new');
// There is no link, but also no wrong link or crash.
expect(cConstructor.documentationAsHtml, '<p>Text <code>p</code>.</p>');
}
@@ -264,7 +264,7 @@
C(this._);
}
''');
- var cConstructor = library.classes.named('C').constructors.named('C');
+ var cConstructor = library.classes.named('C').constructors.named('C.new');
// There is no link, but also no wrong link or crash.
expect(cConstructor.documentationAsHtml, '<p>Text <code>_</code>.</p>');
}
@@ -279,7 +279,7 @@
D(super._) {}
}
''');
- var dConstructor = library.classes.named('D').constructors.named('D');
+ var dConstructor = library.classes.named('D').constructors.named('D.new');
// There is no link, but also no wrong link or crash.
expect(dConstructor.documentationAsHtml, '<p>Text <code>_</code>.</p>');
}
diff --git a/test/templates/class_test.dart b/test/templates/class_test.dart
index 2e46a46..c70ef2b 100644
--- a/test/templates/class_test.dart
+++ b/test/templates/class_test.dart
@@ -218,7 +218,7 @@
htmlLines.expectMainContentContainsAllInOrder([
matches('<h2>Constructors</h2>'),
- matches('<a href="../lib/C/C.html">C</a>'),
+ matches('<a href="../lib/C/C.html">C.new</a>'),
matches('An unnamed constructor.'),
]);
}
diff --git a/test/templates/extension_type_test.dart b/test/templates/extension_type_test.dart
index 5c9a7cb..4d50a24 100644
--- a/test/templates/extension_type_test.dart
+++ b/test/templates/extension_type_test.dart
@@ -166,9 +166,8 @@
htmlLines.expectMainContentContainsAllInOrder([
matches('<h2>Constructors</h2>'),
- matches('<a href="../lib/One/One.html">One</a>'),
- matches('<a href="../lib/One/One.named.html">'
- 'One.named</a>'),
+ matches('<a href="../lib/One/One.html">One.new</a>'),
+ matches('<a href="../lib/One/One.named.html">One.named</a>'),
matches('A named constructor.'),
]);
}