Skip to content

Commit

Permalink
Correctly show extension type ctors and hide enum ctors (#3804)
Browse files Browse the repository at this point in the history
Fixes #3252

* All enum constructors should be hidden.
* All public extension type constructors should be shown.
  • Loading branch information
srawlins committed Jun 28, 2024
1 parent 2a39376 commit 31833c3
Show file tree
Hide file tree
Showing 10 changed files with 127 additions and 91 deletions.
46 changes: 20 additions & 26 deletions lib/src/generator/templates.aot_renderers_for_html.dart
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,6 @@ String renderEnum(EnumTemplateData context0) {
</dl>
</section>''');
}
buffer.write('\n\n ');
buffer.write(_renderEnum_partial_constructors_9(context2));
buffer.writeln();
if (context2.hasPublicEnumValues) {
buffer.writeln();
Expand All @@ -561,32 +559,32 @@ String renderEnum(EnumTemplateData context0) {
var context3 = context2.publicEnumValues;
for (var context4 in context3) {
buffer.write('\n ');
buffer.write(_renderEnum_partial_constant_10(context4));
buffer.write(_renderEnum_partial_constant_9(context4));
}
buffer.writeln();
buffer.write('''
</dl>
</section>''');
}
buffer.write('\n\n ');
buffer.write(_renderEnum_partial_instance_fields_11(context2));
buffer.write(_renderEnum_partial_instance_fields_10(context2));
buffer.write('\n ');
buffer.write(_renderEnum_partial_instance_methods_12(context2));
buffer.write(_renderEnum_partial_instance_methods_11(context2));
buffer.write('\n ');
buffer.write(_renderEnum_partial_instance_operators_13(context2));
buffer.write(_renderEnum_partial_instance_operators_12(context2));
buffer.write('\n ');
buffer.write(_renderEnum_partial_static_properties_14(context2));
buffer.write(_renderEnum_partial_static_properties_13(context2));
buffer.write('\n ');
buffer.write(_renderEnum_partial_static_methods_15(context2));
buffer.write(_renderEnum_partial_static_methods_14(context2));
buffer.write('\n ');
buffer.write(_renderEnum_partial_static_constants_16(context2));
buffer.write(_renderEnum_partial_static_constants_15(context2));
buffer.writeln();
buffer.write('''
</div><!-- /.main-content -->
<div id="dartdoc-sidebar-left" class="sidebar sidebar-offcanvas-left">
''');
buffer.write(_renderEnum_partial_search_sidebar_17(context0));
buffer.write(_renderEnum_partial_search_sidebar_16(context0));
buffer.writeln();
buffer.write('''
<h5>''');
Expand All @@ -601,7 +599,7 @@ String renderEnum(EnumTemplateData context0) {
</div><!-- /.sidebar-offcanvas -->
''');
buffer.write(_renderEnum_partial_footer_18(context0));
buffer.write(_renderEnum_partial_footer_17(context0));
buffer.writeln();

return buffer.toString();
Expand Down Expand Up @@ -1696,7 +1694,7 @@ String renderSidebarForContainer<T extends Documentable>(
buffer.write('''<ol>''');
var context1 = context0.container;
buffer.writeln();
if (context1.isClassOrEnum) {
if (context1.isClassOrExtensionType) {
if (context1.hasPublicConstructors) {
buffer.writeln();
buffer.write('''
Expand Down Expand Up @@ -2706,34 +2704,31 @@ String _renderEnum_partial_mixed_in_types_7(Enum context1) {
String _renderEnum_partial_container_annotations_8(Enum context1) =>
_deduplicated_lib_templates__container_annotations_html(context1);

String _renderEnum_partial_constructors_9(Enum context1) =>
_deduplicated_lib_templates__constructors_html(context1);

String _renderEnum_partial_constant_10(Field context2) =>
String _renderEnum_partial_constant_9(Field context2) =>
_deduplicated_lib_templates__constant_html(context2);

String _renderEnum_partial_instance_fields_11(Enum context1) =>
String _renderEnum_partial_instance_fields_10(Enum context1) =>
_deduplicated_lib_templates__instance_fields_html(context1);

String _renderEnum_partial_instance_methods_12(Enum context1) =>
String _renderEnum_partial_instance_methods_11(Enum context1) =>
_deduplicated_lib_templates__instance_methods_html(context1);

String _renderEnum_partial_instance_operators_13(Enum context1) =>
String _renderEnum_partial_instance_operators_12(Enum context1) =>
_deduplicated_lib_templates__instance_operators_html(context1);

String _renderEnum_partial_static_properties_14(Enum context1) =>
String _renderEnum_partial_static_properties_13(Enum context1) =>
_deduplicated_lib_templates__static_properties_html(context1);

String _renderEnum_partial_static_methods_15(Enum context1) =>
String _renderEnum_partial_static_methods_14(Enum context1) =>
_deduplicated_lib_templates__static_methods_html(context1);

String _renderEnum_partial_static_constants_16(Enum context1) =>
String _renderEnum_partial_static_constants_15(Enum context1) =>
_deduplicated_lib_templates__static_constants_html(context1);

String _renderEnum_partial_search_sidebar_17(EnumTemplateData context0) =>
String _renderEnum_partial_search_sidebar_16(EnumTemplateData context0) =>
_deduplicated_lib_templates__search_sidebar_html(context0);

String _renderEnum_partial_footer_18(EnumTemplateData context0) =>
String _renderEnum_partial_footer_17(EnumTemplateData context0) =>
_deduplicated_lib_templates__footer_html(context0);

String _renderError_partial_head_0(PackageTemplateData context0) =>
Expand Down Expand Up @@ -4417,8 +4412,7 @@ String _deduplicated_lib_templates__container_annotations_html(
return buffer.toString();
}

String _deduplicated_lib_templates__constructors_html(
InheritingContainer context0) {
String _deduplicated_lib_templates__constructors_html(Constructable context0) {
final buffer = StringBuffer();
if (context0.hasPublicConstructors) {
buffer.writeln();
Expand Down
15 changes: 14 additions & 1 deletion lib/src/generator/templates.runtime_renderers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2936,6 +2936,13 @@ class _Renderer_Container extends RendererBase<Container> {
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.isClassOrEnum,
),
'isClassOrExtensionType': Property(
getValue: (CT_ c) => c.isClassOrExtensionType,
renderVariable: (CT_ c, Property<CT_> self,
List<String> remainingNames) =>
self.renderSimpleVariable(c, remainingNames, 'bool'),
getBool: (CT_ c) => c.isClassOrExtensionType,
),
'isEnum': Property(
getValue: (CT_ c) => c.isEnum,
renderVariable: (CT_ c, Property<CT_> self,
Expand Down Expand Up @@ -16294,7 +16301,12 @@ const _invisibleGetters = {
'runtimeType',
'superclassConstraints'
},
'ModelNode': {'hashCode', 'runtimeType', 'sourceCode'},
'ModelNode': {
'commentReferenceData',
'hashCode',
'runtimeType',
'sourceCode'
},
'PackageGraph': {
'allConstructedModelElements',
'allExtensionsAdded',
Expand Down Expand Up @@ -16482,6 +16494,7 @@ const _invisibleGetters = {
'aliasedType',
'enclosingElement',
'hashCode',
'isAugmentation',
'name',
'runtimeType'
},
Expand Down
21 changes: 12 additions & 9 deletions lib/src/model/constructor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,18 @@ class Constructor extends ModelElement with ContainerMember, TypeParameters {
if (!super.isPublic) return false;
if (element.hasPrivateName) return false;
var class_ = element.enclosingElement;
if (class_ is! ClassElement) return true;
if (element.isFactory) return true;
if (class_.isSealed ||
(class_.isAbstract && class_.isFinal) ||
(class_.isAbstract && class_.isInterface)) {
/// Sealed classes, abstract final classes, and abstract interface
/// classes, cannot be instantiated nor extended, from outside the
/// declaring library. Avoid documenting them.
return false;
// Enums cannot be explicitly constructed or extended.
if (class_ is EnumElement) return false;
if (class_ is ClassElement) {
if (element.isFactory) return true;
if (class_.isSealed ||
(class_.isAbstract && class_.isFinal) ||
(class_.isAbstract && class_.isInterface)) {
/// Sealed classes, abstract final classes, and abstract interface
/// classes, cannot be instantiated nor extended, from outside the
/// declaring library. Avoid documenting them.
return false;
}
}
return true;
}
Expand Down
4 changes: 4 additions & 0 deletions lib/src/model/container.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ abstract class Container extends ModelElement
/// Whether this is a class or an enum.
bool get isClassOrEnum => element is InterfaceElement;

/// Whether this is a class or an extension type.
bool get isClassOrExtensionType =>
element is ClassElement || element is ExtensionTypeElement;

/// Whether this is a mixin.
bool get isMixin => element is MixinElement;

Expand Down
4 changes: 2 additions & 2 deletions lib/templates/_sidebar_for_container.html
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<ol>
{{ #container }}

{{ #isClassOrEnum }}
{{ #isClassOrExtensionType }}
{{ #hasPublicConstructors }}
<li class="section-title"><a href="{{{ href }}}#constructors">Constructors</a></li>
{{ #publicConstructorsSorted }}
<li><a{{ #isDeprecated }} class="deprecated"{{ /isDeprecated }} href="{{{ href }}}">{{ shortName }}</a></li>
{{ /publicConstructorsSorted }}
{{ /hasPublicConstructors }}
{{ /isClassOrEnum }}
{{ /isClassOrExtensionType }}

{{ #isEnum }}
{{ #hasPublicEnumValues }}
Expand Down
2 changes: 0 additions & 2 deletions lib/templates/enum.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,6 @@ <h1>
</section>
{{ /hasModifiers }}

{{ >constructors }}

{{ #hasPublicEnumValues }}
<section class="summary offset-anchor" id="values">
<h2>Values</h2>
Expand Down
74 changes: 74 additions & 0 deletions test/constructors_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,78 @@ sealed class C {
expect(c.isPublic, isFalse);
expect(c.documentationAsHtml, '<p>Constructor.</p>');
}

void test_enum_named() async {
var library = await bootPackageWithLibrary('''
enum E {
one.named(), two.named();
/// Constructor.
const E.named();
}
''');
var e = library.enums.named('E').constructors.first;
expect(e.name, equals('E.named'));
expect(e.isPublic, isFalse);
expect(e.documentationAsHtml, '<p>Constructor.</p>');
}

void test_enum_unnamed() async {
var library = await bootPackageWithLibrary('''
enum E {
one(), two();
/// Constructor.
const E();
}
''');
var e = library.enums.named('E').constructors.first;
expect(e.name, equals('E'));
expect(e.isPublic, isFalse);
expect(e.documentationAsHtml, '<p>Constructor.</p>');
}

void test_extensionType_named() async {
var library = await bootPackageWithLibrary('''
extension type ET(int it) {
/// Constructor.
ET.named(this.it);
}
''');
var etNamed =
library.extensionTypes.named('ET').constructors.named('ET.named');
expect(etNamed.name, equals('ET.named'));
expect(etNamed.isPublic, isTrue);
expect(etNamed.documentationAsHtml, '<p>Constructor.</p>');
}

void test_extensionType_primaryNamed() async {
var library = await bootPackageWithLibrary('''
extension type ET.named(int it) {}
''');
var etNamed =
library.extensionTypes.named('ET').constructors.named('ET.named');
expect(etNamed.name, equals('ET.named'));
expect(etNamed.isPublic, isTrue);
}

void test_extensionType_primaryUnnamed() async {
var library = await bootPackageWithLibrary('''
extension type ET(int it) {}
''');
var et = library.extensionTypes.named('ET').constructors.named('ET');
expect(et.name, equals('ET'));
expect(et.isPublic, isTrue);
}

void test_extensionType_unnamed() async {
var library = await bootPackageWithLibrary('''
extension type ET.named(int it) {
/// Constructor.
ET(this.it);
}
''');
var etNamed = library.extensionTypes.named('ET').constructors.named('ET');
expect(etNamed.name, equals('ET'));
expect(etNamed.isPublic, isTrue);
expect(etNamed.documentationAsHtml, '<p>Constructor.</p>');
}
}
2 changes: 1 addition & 1 deletion test/dartdoc_test_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ abstract class DartdocTestBase {

String get dartCoreUrlPrefix => 'https://api.dart.dev/stable/3.2.0/dart-core';

String get sdkConstraint => '>=3.2.0 <4.0.0';
String get sdkConstraint => '>=3.3.0 <4.0.0';

List<String> get experiments => [];

Expand Down
21 changes: 0 additions & 21 deletions test/enum_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -218,27 +218,6 @@ enum E<T> with M<T>, N { one, two, three; }
expect(eEnum.mixedInElements.map((e) => e.name), equals(['M', 'N']));
}

void test_namedConstructorCanBeReferenced() async {
// TODO(srawlins): As all supported Dart is >=2.15.0, this test can just
// be a "constructors" test rather than an "enum" test.
var library = await bootPackageWithLibrary('''
enum E {
one.named(1),
two.named(2);
const E.named(int x);
}
/// Reference to [E.named].
class C {}
''');
var cClass = library.classes.named('C');
expect(
cClass.documentationAsHtml,
'<p>Reference to <a href="$linkPrefix/E/E.named.html">E.named</a>.</p>',
);
}

void test_operatorsAreDocumented() async {
// TODO(srawlins): As all supported Dart is >=2.15.0, this test can just
// be an "operator" test rather than an "enum" test.
Expand Down
29 changes: 0 additions & 29 deletions test/templates/enum_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ void main() async {
late List<String> eLines;
late List<String> eRightSidebarLines;
late List<String> enumWithDefaultConstructorLines;
late List<String> enumWithDefaultConstructorRightSidebarLines;

group('enums', () {
setUpAll(() async {
Expand Down Expand Up @@ -131,11 +130,6 @@ enum EnumWithDefaultConstructor {
packagePath, 'doc', 'lib', 'EnumWithDefaultConstructor.html'))
.readAsStringSync()
.split('\n');
enumWithDefaultConstructorRightSidebarLines = resourceProvider
.getFile(path.join(packagePath, 'doc', 'lib',
'EnumWithDefaultConstructor-enum-sidebar.html'))
.readAsStringSync()
.split('\n');
});

test('enum page contains enum name with generics', () async {
Expand Down Expand Up @@ -342,29 +336,6 @@ enum EnumWithDefaultConstructor {
]));
});

test('enum sidebar contains default constructors', () async {
expect(
enumWithDefaultConstructorRightSidebarLines,
containsAllInOrder([
matches('<a href="lib/EnumWithDefaultConstructor.html#constructors">'
'Constructors</a>'),
matches(
'<a href="lib/EnumWithDefaultConstructor/EnumWithDefaultConstructor.html">'
'EnumWithDefaultConstructor</a>'),
]),
);
});

test('enum sidebar contains explicit constructors', () async {
expect(
eRightSidebarLines,
containsAllInOrder([
matches('<a href="lib/E.html#constructors">Constructors</a>'),
matches('<a href="lib/E/E.named.html">named</a>'),
]),
);
});

test('enum sidebar contains values', () async {
expect(
eRightSidebarLines,
Expand Down

0 comments on commit 31833c3

Please sign in to comment.