From 58e295f2efcd4e7eed2d7fb890cf13d26d616259 Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Fri, 28 Jun 2024 09:12:26 -0700 Subject: [PATCH] Correctly show extension type ctors and hide enum ctors Fixes #3252 * All enum constructors should be hidden. * All public extension type constructors should be shown. --- .../templates.aot_renderers_for_html.dart | 46 +++++------- .../templates.runtime_renderers.dart | 15 +++- lib/src/model/constructor.dart | 21 +++--- lib/src/model/container.dart | 4 + lib/templates/_sidebar_for_container.html | 4 +- lib/templates/enum.html | 2 - test/constructors_test.dart | 74 +++++++++++++++++++ test/dartdoc_test_base.dart | 2 +- test/enum_test.dart | 21 ------ test/templates/enum_test.dart | 29 -------- 10 files changed, 127 insertions(+), 91 deletions(-) diff --git a/lib/src/generator/templates.aot_renderers_for_html.dart b/lib/src/generator/templates.aot_renderers_for_html.dart index bced76cacc..2663dd84d2 100644 --- a/lib/src/generator/templates.aot_renderers_for_html.dart +++ b/lib/src/generator/templates.aot_renderers_for_html.dart @@ -548,8 +548,6 @@ String renderEnum(EnumTemplateData context0) { '''); } - buffer.write('\n\n '); - buffer.write(_renderEnum_partial_constructors_9(context2)); buffer.writeln(); if (context2.hasPublicEnumValues) { buffer.writeln(); @@ -561,7 +559,7 @@ 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(''' @@ -569,24 +567,24 @@ String renderEnum(EnumTemplateData context0) { '''); } 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(''' '''); - buffer.write(_renderEnum_partial_footer_18(context0)); + buffer.write(_renderEnum_partial_footer_17(context0)); buffer.writeln(); return buffer.toString(); @@ -1696,7 +1694,7 @@ String renderSidebarForContainer( buffer.write('''
    '''); var context1 = context0.container; buffer.writeln(); - if (context1.isClassOrEnum) { + if (context1.isClassOrExtensionType) { if (context1.hasPublicConstructors) { buffer.writeln(); buffer.write(''' @@ -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) => @@ -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(); diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index f1d7961fec..7e9fe11363 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -2936,6 +2936,13 @@ class _Renderer_Container extends RendererBase { self.renderSimpleVariable(c, remainingNames, 'bool'), getBool: (CT_ c) => c.isClassOrEnum, ), + 'isClassOrExtensionType': Property( + getValue: (CT_ c) => c.isClassOrExtensionType, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.isClassOrExtensionType, + ), 'isEnum': Property( getValue: (CT_ c) => c.isEnum, renderVariable: (CT_ c, Property self, @@ -16294,7 +16301,12 @@ const _invisibleGetters = { 'runtimeType', 'superclassConstraints' }, - 'ModelNode': {'hashCode', 'runtimeType', 'sourceCode'}, + 'ModelNode': { + 'commentReferenceData', + 'hashCode', + 'runtimeType', + 'sourceCode' + }, 'PackageGraph': { 'allConstructedModelElements', 'allExtensionsAdded', @@ -16482,6 +16494,7 @@ const _invisibleGetters = { 'aliasedType', 'enclosingElement', 'hashCode', + 'isAugmentation', 'name', 'runtimeType' }, diff --git a/lib/src/model/constructor.dart b/lib/src/model/constructor.dart index 331ee6482d..94b229cdf5 100644 --- a/lib/src/model/constructor.dart +++ b/lib/src/model/constructor.dart @@ -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; } diff --git a/lib/src/model/container.dart b/lib/src/model/container.dart index 88def839d6..51ff52e8b7 100644 --- a/lib/src/model/container.dart +++ b/lib/src/model/container.dart @@ -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; diff --git a/lib/templates/_sidebar_for_container.html b/lib/templates/_sidebar_for_container.html index 66d4d98369..35c7263526 100644 --- a/lib/templates/_sidebar_for_container.html +++ b/lib/templates/_sidebar_for_container.html @@ -1,14 +1,14 @@
      {{ #container }} - {{ #isClassOrEnum }} + {{ #isClassOrExtensionType }} {{ #hasPublicConstructors }}
    1. Constructors
    2. {{ #publicConstructorsSorted }}
    3. {{ shortName }}
    4. {{ /publicConstructorsSorted }} {{ /hasPublicConstructors }} - {{ /isClassOrEnum }} + {{ /isClassOrExtensionType }} {{ #isEnum }} {{ #hasPublicEnumValues }} diff --git a/lib/templates/enum.html b/lib/templates/enum.html index 9b3fd3ee17..59eb913204 100644 --- a/lib/templates/enum.html +++ b/lib/templates/enum.html @@ -28,8 +28,6 @@

      {{ /hasModifiers }} - {{ >constructors }} - {{ #hasPublicEnumValues }}

      Values

      diff --git a/test/constructors_test.dart b/test/constructors_test.dart index 664b5d8b01..d6e9978a61 100644 --- a/test/constructors_test.dart +++ b/test/constructors_test.dart @@ -145,4 +145,78 @@ sealed class C { expect(c.isPublic, isFalse); expect(c.documentationAsHtml, '

      Constructor.

      '); } + + 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, '

      Constructor.

      '); + } + + 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, '

      Constructor.

      '); + } + + 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, '

      Constructor.

      '); + } + + 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, '

      Constructor.

      '); + } } diff --git a/test/dartdoc_test_base.dart b/test/dartdoc_test_base.dart index 835571eb8c..4bc7e764eb 100644 --- a/test/dartdoc_test_base.dart +++ b/test/dartdoc_test_base.dart @@ -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 get experiments => []; diff --git a/test/enum_test.dart b/test/enum_test.dart index 71ca8af6ed..6fc4640ddb 100644 --- a/test/enum_test.dart +++ b/test/enum_test.dart @@ -218,27 +218,6 @@ enum E with M, 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, - '

      Reference to E.named.

      ', - ); - } - 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. diff --git a/test/templates/enum_test.dart b/test/templates/enum_test.dart index 8c36a3303f..ab30c295fb 100644 --- a/test/templates/enum_test.dart +++ b/test/templates/enum_test.dart @@ -17,7 +17,6 @@ void main() async { late List eLines; late List eRightSidebarLines; late List enumWithDefaultConstructorLines; - late List enumWithDefaultConstructorRightSidebarLines; group('enums', () { setUpAll(() async { @@ -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 { @@ -342,29 +336,6 @@ enum EnumWithDefaultConstructor { ])); }); - test('enum sidebar contains default constructors', () async { - expect( - enumWithDefaultConstructorRightSidebarLines, - containsAllInOrder([ - matches('' - 'Constructors'), - matches( - '' - 'EnumWithDefaultConstructor'), - ]), - ); - }); - - test('enum sidebar contains explicit constructors', () async { - expect( - eRightSidebarLines, - containsAllInOrder([ - matches('Constructors'), - matches('named'), - ]), - ); - }); - test('enum sidebar contains values', () async { expect( eRightSidebarLines,