From eb4394ab8d0a0b9da2695709192e1aca70b517dc Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Thu, 29 Feb 2024 15:57:22 -0800 Subject: [PATCH 1/2] Generate docs for enum static methods. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes https://github.com/dart-lang/dartdoc/issues/3584 The GeneratorFrontEnd code was really long, and I think that made it easy to omit things. I've refactored it to reuse more code. Also, the repeated code had bugs: * For extensions and extension types, we likely _over_-documented, because we didn't omit things that we're canonical. * For enums, we omitted static methods and static fields (#3584). Also in this change: * Change some `clazz` and `eNum` parameter names to `class_` and `enum_`. More standard, and standard inside the analyzer. * Migrate methods_test.dart to use test_reflective_loader. * Add method tests for methods on classes, enums, mixins, extensions, and extension types. * In the shared testing code, add some code that prints out the in-memory files when a file cannot be read. Here's a snippet of what that looks like: ```none /temp/method_test/doc/ ├─ index.html ├─ __404error.html ├─ search.html ├─ lib/ │ ├─ lib-library.html │ ├─ lib-library-sidebar.html │ ├─ E-class.html │ ├─ E-enum-sidebar.html │ └─ E/ │ │ ├─ values-constant.html ``` --- lib/src/generator/file_structure.dart | 5 +- lib/src/generator/generator_backend.dart | 24 +- lib/src/generator/generator_frontend.dart | 331 ++++++------------ lib/src/generator/html_generator.dart | 16 +- .../templates.aot_renderers_for_html.dart | 85 ++--- .../templates.runtime_renderers.dart | 125 +------ lib/src/model/class.dart | 34 +- lib/src/model/container.dart | 8 + lib/src/model/enum.dart | 47 +-- lib/src/model/model_element.dart | 2 +- lib/src/render/enum_field_renderer.dart | 12 +- test/enum_test.dart | 25 +- test/templates/method_test.dart | 272 +++++++++----- test/templates/template_test_base.dart | 33 +- 14 files changed, 448 insertions(+), 571 deletions(-) diff --git a/lib/src/generator/file_structure.dart b/lib/src/generator/file_structure.dart index 910af4770a..85a05b2a30 100644 --- a/lib/src/generator/file_structure.dart +++ b/lib/src/generator/file_structure.dart @@ -24,7 +24,8 @@ abstract class FileStructure { // This should be the common case. FileStructure._fromModelElement(documentable), _ => throw UnimplementedError( - 'Tried to build a FileStructure for an unknown subtype of Documentable: ${documentable.runtimeType}') + 'Tried to build a FileStructure for an unknown subtype of ' + "Documentable: '${documentable.runtimeType}'") }; } @@ -42,6 +43,8 @@ abstract class FileStructure { return switch (modelElement) { Library() => FileStructureImpl(modelElement.dirName, 'library'), Mixin() => FileStructureImpl(modelElement.name, 'mixin'), + // Probably just an archaic state, but enums do not have a file suffix. + Enum() => FileStructureImpl(modelElement.name, null), Class() => FileStructureImpl(modelElement.name, 'class'), ExtensionType() => FileStructureImpl(modelElement.name, 'extension-type'), Operator() => FileStructureImpl( diff --git a/lib/src/generator/generator_backend.dart b/lib/src/generator/generator_backend.dart index 4f6a976e93..5679dada14 100644 --- a/lib/src/generator/generator_backend.dart +++ b/lib/src/generator/generator_backend.dart @@ -125,11 +125,11 @@ abstract class GeneratorBackend { runtimeStats.incrementAccumulator('writtenCategoryFileCount'); } - /// Emits documentation content for the [clazz]. - void generateClass(PackageGraph packageGraph, Library library, Class clazz) { - var data = ClassTemplateData(options, packageGraph, library, clazz); + /// Emits documentation content for the [class_]. + void generateClass(PackageGraph packageGraph, Library library, Class class_) { + var data = ClassTemplateData(options, packageGraph, library, class_); var content = templates.renderClass(data); - write(writer, clazz.filePath, data, content); + write(writer, class_.filePath, data, content); runtimeStats.incrementAccumulator('writtenClassFileCount'); } @@ -143,11 +143,11 @@ abstract class GeneratorBackend { runtimeStats.incrementAccumulator('writtenConstructorFileCount'); } - /// Emits documentation content for the [eNum]. - void generateEnum(PackageGraph packageGraph, Library library, Enum eNum) { - var data = EnumTemplateData(options, packageGraph, library, eNum); + /// Emits documentation content for the [enum_]. + void generateEnum(PackageGraph packageGraph, Library library, Enum enum_) { + var data = EnumTemplateData(options, packageGraph, library, enum_); var content = templates.renderEnum(data); - write(writer, eNum.filePath, data, content); + write(writer, enum_.filePath, data, content); runtimeStats.incrementAccumulator('writtenEnumFileCount'); } @@ -189,9 +189,9 @@ abstract class GeneratorBackend { /// Emits documentation content for the [method]. void generateMethod(PackageGraph packageGraph, Library library, - Container clazz, Method method) { + Container container, Method method) { var data = - MethodTemplateData(options, packageGraph, library, clazz, method); + MethodTemplateData(options, packageGraph, library, container, method); var content = templates.renderMethod(data); write(writer, method.filePath, data, content); runtimeStats.incrementAccumulator('writtenMethodFileCount'); @@ -215,9 +215,9 @@ abstract class GeneratorBackend { /// Emits documentation content for the [field]. void generateProperty(PackageGraph packageGraph, Library library, - Container clazz, Field field) { + Container container, Field field) { var data = - PropertyTemplateData(options, packageGraph, library, clazz, field); + PropertyTemplateData(options, packageGraph, library, container, field); var content = templates.renderProperty(data); write(writer, field.filePath, data, content); runtimeStats.incrementAccumulator('writtenPropertyFileCount'); diff --git a/lib/src/generator/generator_frontend.dart b/lib/src/generator/generator_frontend.dart index 00035aaaef..0c7b20ff31 100644 --- a/lib/src/generator/generator_frontend.dart +++ b/lib/src/generator/generator_frontend.dart @@ -77,6 +77,71 @@ class GeneratorFrontEnd implements Generator { var indexAccumulator = []; var multiplePackages = packageGraph.localPackages.length > 1; + + void generateConstants(Container container) { + for (var constant in filterNonDocumented(container.constantFields)) { + if (!constant.isCanonical) continue; + indexAccumulator.add(constant); + _generatorBackend.generateProperty( + packageGraph, container.library, container, constant); + } + } + + void generateConstructors(Constructable constructable) { + for (var constructor in filterNonDocumented(constructable.constructors)) { + if (!constructor.isCanonical) continue; + indexAccumulator.add(constructor); + _generatorBackend.generateConstructor( + packageGraph, constructable.library, constructable, constructor); + } + } + + void generateInstanceMethods(Container container) { + for (var method in filterNonDocumented(container.instanceMethods)) { + if (!method.isCanonical) continue; + indexAccumulator.add(method); + _generatorBackend.generateMethod( + packageGraph, container.library, container, method); + } + } + + void generateInstanceOperators(Container container) { + for (var operator in filterNonDocumented(container.instanceOperators)) { + if (!operator.isCanonical) continue; + indexAccumulator.add(operator); + _generatorBackend.generateMethod( + packageGraph, container.library, container, operator); + } + } + + void generateInstanceProperty(Container container) { + for (var property in filterNonDocumented(container.instanceFields)) { + if (!property.isCanonical) continue; + indexAccumulator.add(property); + _generatorBackend.generateProperty( + packageGraph, container.library, container, property); + } + } + + void generateStaticMethods(Container container) { + for (var method in filterNonDocumented(container.staticMethods)) { + if (!method.isCanonical) continue; + indexAccumulator.add(method); + _generatorBackend.generateMethod( + packageGraph, container.library, container, method); + } + } + + void generateStaticProperty(Container container) { + for (var property + in filterNonDocumented(container.variableStaticFields)) { + if (!property.isCanonical) continue; + indexAccumulator.add(property); + _generatorBackend.generateProperty( + packageGraph, container.library, container, property); + } + } + for (var package in packageGraph.localPackages) { if (multiplePackages) { logInfo('Generating docs for package ${package.name}...'); @@ -99,110 +164,29 @@ class GeneratorFrontEnd implements Generator { indexAccumulator.add(lib); _generatorBackend.generateLibrary(packageGraph, lib); - for (var clazz in filterNonDocumented(lib.allClasses)) { - indexAccumulator.add(clazz); - _generatorBackend.generateClass(packageGraph, lib, clazz); - - for (var constructor in filterNonDocumented(clazz.constructors)) { - if (!constructor.isCanonical) continue; - - indexAccumulator.add(constructor); - _generatorBackend.generateConstructor( - packageGraph, lib, clazz, constructor); - } - - for (var constant in filterNonDocumented(clazz.constantFields)) { - if (!constant.isCanonical) continue; - - indexAccumulator.add(constant); - _generatorBackend.generateProperty( - packageGraph, lib, clazz, constant); - } - - for (var property - in filterNonDocumented(clazz.variableStaticFields)) { - if (!property.isCanonical) continue; - - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, clazz, property); - } - - for (var property in filterNonDocumented(clazz.instanceFields)) { - if (!property.isCanonical) continue; - - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, clazz, property); - } - - for (var method in filterNonDocumented(clazz.instanceMethods)) { - if (!method.isCanonical) continue; - - indexAccumulator.add(method); - _generatorBackend.generateMethod(packageGraph, lib, clazz, method); - } - - for (var operator in filterNonDocumented(clazz.instanceOperators)) { - if (!operator.isCanonical) continue; - - indexAccumulator.add(operator); - _generatorBackend.generateMethod( - packageGraph, lib, clazz, operator); - } - - for (var method in filterNonDocumented(clazz.staticMethods)) { - if (!method.isCanonical) continue; - - indexAccumulator.add(method); - _generatorBackend.generateMethod(packageGraph, lib, clazz, method); - } + for (var class_ in filterNonDocumented(lib.allClasses)) { + indexAccumulator.add(class_); + _generatorBackend.generateClass(packageGraph, lib, class_); + + generateConstants(class_); + generateConstructors(class_); + generateInstanceMethods(class_); + generateInstanceOperators(class_); + generateInstanceProperty(class_); + generateStaticMethods(class_); + generateStaticProperty(class_); } for (var extension in filterNonDocumented(lib.extensions)) { indexAccumulator.add(extension); _generatorBackend.generateExtension(packageGraph, lib, extension); - for (var constant in filterNonDocumented(extension.constantFields)) { - indexAccumulator.add(constant); - _generatorBackend.generateProperty( - packageGraph, lib, extension, constant); - } - - for (var method - in filterNonDocumented(extension.publicInstanceMethods)) { - indexAccumulator.add(method); - _generatorBackend.generateMethod( - packageGraph, lib, extension, method); - } - - for (var operator - in filterNonDocumented(extension.instanceOperators)) { - indexAccumulator.add(operator); - _generatorBackend.generateMethod( - packageGraph, lib, extension, operator); - } - - for (var property in filterNonDocumented(extension.instanceFields)) { - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, extension, property); - } - - for (var staticField - in filterNonDocumented(extension.variableStaticFields)) { - indexAccumulator.add(staticField); - _generatorBackend.generateProperty( - packageGraph, lib, extension, staticField); - } - - for (var method in filterNonDocumented(extension.staticMethods)) { - if (!method.isCanonical) continue; - - indexAccumulator.add(method); - _generatorBackend.generateMethod( - packageGraph, lib, extension, method); - } + generateConstants(extension); + generateInstanceMethods(extension); + generateInstanceOperators(extension); + generateInstanceProperty(extension); + generateStaticMethods(extension); + generateStaticProperty(extension); } for (var extensionType in filterNonDocumented(lib.extensionTypes)) { @@ -210,149 +194,38 @@ class GeneratorFrontEnd implements Generator { _generatorBackend.generateExtensionType( packageGraph, lib, extensionType); - for (var constructor - in filterNonDocumented(extensionType.constructors)) { - if (!constructor.isCanonical) continue; - - indexAccumulator.add(constructor); - _generatorBackend.generateConstructor( - packageGraph, lib, extensionType, constructor); - } - - for (var constant - in filterNonDocumented(extensionType.constantFields)) { - indexAccumulator.add(constant); - _generatorBackend.generateProperty( - packageGraph, lib, extensionType, constant); - } - - for (var method - in filterNonDocumented(extensionType.publicInstanceMethods)) { - indexAccumulator.add(method); - _generatorBackend.generateMethod( - packageGraph, lib, extensionType, method); - } - - for (var operator - in filterNonDocumented(extensionType.instanceOperators)) { - indexAccumulator.add(operator); - _generatorBackend.generateMethod( - packageGraph, lib, extensionType, operator); - } - - for (var property - in filterNonDocumented(extensionType.instanceFields)) { - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, extensionType, property); - } - - for (var staticField - in filterNonDocumented(extensionType.variableStaticFields)) { - indexAccumulator.add(staticField); - _generatorBackend.generateProperty( - packageGraph, lib, extensionType, staticField); - } - - for (var method in filterNonDocumented(extensionType.staticMethods)) { - if (!method.isCanonical) continue; - - indexAccumulator.add(method); - _generatorBackend.generateMethod( - packageGraph, lib, extensionType, method); - } + generateConstants(extensionType); + generateConstructors(extensionType); + generateInstanceMethods(extensionType); + generateInstanceOperators(extensionType); + generateInstanceProperty(extensionType); + generateStaticMethods(extensionType); + generateStaticProperty(extensionType); } for (var mixin in filterNonDocumented(lib.mixins)) { indexAccumulator.add(mixin); _generatorBackend.generateMixin(packageGraph, lib, mixin); - for (var constant in filterNonDocumented(mixin.constantFields)) { - if (!constant.isCanonical) continue; - indexAccumulator.add(constant); - _generatorBackend.generateProperty( - packageGraph, lib, mixin, constant); - } - - for (var property - in filterNonDocumented(mixin.variableStaticFields)) { - if (!property.isCanonical) continue; - - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, mixin, property); - } - - for (var property in filterNonDocumented(mixin.instanceFields)) { - if (!property.isCanonical) continue; - - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, mixin, property); - } - - for (var method in filterNonDocumented(mixin.instanceMethods)) { - if (!method.isCanonical) continue; - - indexAccumulator.add(method); - _generatorBackend.generateMethod(packageGraph, lib, mixin, method); - } - - for (var operator in filterNonDocumented(mixin.instanceOperators)) { - if (!operator.isCanonical) continue; - - indexAccumulator.add(operator); - _generatorBackend.generateMethod( - packageGraph, lib, mixin, operator); - } - - for (var method in filterNonDocumented(mixin.staticMethods)) { - if (!method.isCanonical) continue; - - indexAccumulator.add(method); - _generatorBackend.generateMethod(packageGraph, lib, mixin, method); - } + generateConstants(mixin); + generateInstanceProperty(mixin); + generateInstanceMethods(mixin); + generateInstanceOperators(mixin); + generateStaticMethods(mixin); + generateStaticProperty(mixin); } for (var enum_ in filterNonDocumented(lib.enums)) { indexAccumulator.add(enum_); _generatorBackend.generateEnum(packageGraph, lib, enum_); - for (var constant in filterNonDocumented(enum_.constantFields)) { - if (constant is EnumField) { - // Enum values don't get their own page; just any additional - // constants. - continue; - } - if (!constant.isCanonical) continue; - - indexAccumulator.add(constant); - _generatorBackend.generateProperty( - packageGraph, lib, enum_, constant); - } - - for (var constructor in filterNonDocumented(enum_.constructors)) { - if (!constructor.isCanonical) continue; - - indexAccumulator.add(constructor); - _generatorBackend.generateConstructor( - packageGraph, lib, enum_, constructor); - } - - for (var property in filterNonDocumented(enum_.instanceFields)) { - indexAccumulator.add(property); - _generatorBackend.generateProperty( - packageGraph, lib, enum_, property); - } - for (var operator in filterNonDocumented(enum_.instanceOperators)) { - indexAccumulator.add(operator); - _generatorBackend.generateMethod( - packageGraph, lib, enum_, operator); - } - for (var method in filterNonDocumented(enum_.instanceMethods)) { - indexAccumulator.add(method); - _generatorBackend.generateMethod(packageGraph, lib, enum_, method); - } + generateConstants(enum_); + generateConstructors(enum_); + generateInstanceMethods(enum_); + generateInstanceOperators(enum_); + generateInstanceProperty(enum_); + generateStaticMethods(enum_); + generateStaticProperty(enum_); } for (var constant in filterNonDocumented(lib.constants)) { diff --git a/lib/src/generator/html_generator.dart b/lib/src/generator/html_generator.dart index a8a2869e85..b55b966f7e 100644 --- a/lib/src/generator/html_generator.dart +++ b/lib/src/generator/html_generator.dart @@ -36,20 +36,20 @@ class HtmlGeneratorBackend extends GeneratorBackend { super.options, super.templates, super.writer, super.resourceProvider); @override - void generateClass(PackageGraph packageGraph, Library library, Class clazz) { - super.generateClass(packageGraph, library, clazz); - var data = ClassTemplateData(options, packageGraph, library, clazz); + void generateClass(PackageGraph packageGraph, Library library, Class class_) { + super.generateClass(packageGraph, library, class_); + var data = ClassTemplateData(options, packageGraph, library, class_); var sidebarContent = templates.renderSidebarForContainer(data); - write(writer, clazz.sidebarPath, data, sidebarContent, isSidebar: true); + write(writer, class_.sidebarPath, data, sidebarContent, isSidebar: true); runtimeStats.incrementAccumulator('writtenSidebarFileCount'); } @override - void generateEnum(PackageGraph packageGraph, Library library, Enum eNum) { - super.generateEnum(packageGraph, library, eNum); - var data = EnumTemplateData(options, packageGraph, library, eNum); + void generateEnum(PackageGraph packageGraph, Library library, Enum enum_) { + super.generateEnum(packageGraph, library, enum_); + var data = EnumTemplateData(options, packageGraph, library, enum_); var sidebarContent = templates.renderSidebarForContainer(data); - write(writer, eNum.sidebarPath, data, sidebarContent, isSidebar: true); + write(writer, enum_.sidebarPath, data, sidebarContent, isSidebar: true); runtimeStats.incrementAccumulator('writtenSidebarFileCount'); } diff --git a/lib/src/generator/templates.aot_renderers_for_html.dart b/lib/src/generator/templates.aot_renderers_for_html.dart index 203c8e3756..bcddb1bb58 100644 --- a/lib/src/generator/templates.aot_renderers_for_html.dart +++ b/lib/src/generator/templates.aot_renderers_for_html.dart @@ -2661,32 +2661,8 @@ String _renderClass_partial_interfaces_6(Class context1) { return buffer.toString(); } -String _renderClass_partial_mixed_in_types_7(Class context1) { - final buffer = StringBuffer(); - if (context1.hasPublicMixedInTypes) { - buffer.writeln(); - buffer.write(''' -
Mixed in types
-
-
    '''); - var context2 = context1.publicMixedInTypes; - for (var context3 in context2) { - buffer.writeln(); - buffer.write(''' -
  • '''); - buffer.write(context3.linkedName); - buffer.write('''
  • '''); - } - buffer.writeln(); - buffer.write(''' -
-
'''); - } - - return buffer.toString(); -} +String _renderClass_partial_mixed_in_types_7(Class context1) => + _deduplicated_lib_templates__mixed_in_types_html(context1); String _renderClass_partial_container_annotations_8(Class context1) => _deduplicated_lib_templates__container_annotations_html(context1); @@ -2788,32 +2764,8 @@ String _renderEnum_partial_interfaces_6(Enum context1) { return buffer.toString(); } -String _renderEnum_partial_mixed_in_types_7(Enum context1) { - final buffer = StringBuffer(); - if (context1.hasPublicMixedInTypes) { - buffer.writeln(); - buffer.write(''' -
Mixed in types
-
-
    '''); - var context2 = context1.publicMixedInTypes; - for (var context3 in context2) { - buffer.writeln(); - buffer.write(''' -
  • '''); - buffer.write(context3.linkedName); - buffer.write('''
  • '''); - } - buffer.writeln(); - buffer.write(''' -
-
'''); - } - - return buffer.toString(); -} +String _renderEnum_partial_mixed_in_types_7(Enum context1) => + _deduplicated_lib_templates__mixed_in_types_html(context1); String _renderEnum_partial_container_annotations_8(Enum context1) => _deduplicated_lib_templates__container_annotations_html(context1); @@ -4484,7 +4436,7 @@ String _deduplicated_lib_templates__feature_set_html(ModelElement context0) { } String _deduplicated_lib_templates__super_chain_html( - InheritingContainer context0) { + TypeImplementing context0) { final buffer = StringBuffer(); if (context0.hasPublicSuperChainReversed) { buffer.writeln(); @@ -4518,6 +4470,33 @@ String _deduplicated_lib_templates__super_chain_html( return buffer.toString(); } +String _deduplicated_lib_templates__mixed_in_types_html(Class context0) { + final buffer = StringBuffer(); + if (context0.hasPublicMixedInTypes) { + buffer.writeln(); + buffer.write(''' +
Mixed in types
+
+
    '''); + var context1 = context0.publicMixedInTypes; + for (var context2 in context1) { + buffer.writeln(); + buffer.write(''' +
  • '''); + buffer.write(context2.linkedName); + buffer.write('''
  • '''); + } + buffer.writeln(); + buffer.write(''' +
+
'''); + } + + return buffer.toString(); +} + String _deduplicated_lib_templates__container_annotations_html( Container context0) { final buffer = StringBuffer(); diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 1f7763935a..e1ea08a77f 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -1765,12 +1765,13 @@ class _Renderer_Class extends RendererBase { renderVariable: (CT_ c, Property self, List remainingNames) => self.renderSimpleVariable( - c, remainingNames, 'ClassElement'), + c, remainingNames, 'InterfaceElement'), isNullValue: (CT_ c) => false, renderValue: (CT_ c, RendererBase r, List ast, StringSink sink) { renderSimple(c.element, ast, r.template, sink, - parent: r, getters: _invisibleGetters['ClassElement']!); + parent: r, + getters: _invisibleGetters['InterfaceElement']!); }, ), 'inheritanceChain': Property( @@ -4568,23 +4569,7 @@ class _Renderer_Enum extends RendererBase { _propertyMapCache.putIfAbsent( CT_, () => { - ..._Renderer_InheritingContainer.propertyMap(), - ..._Renderer_Constructable.propertyMap(), - ..._Renderer_TypeImplementing.propertyMap(), - ..._Renderer_MixedInTypes.propertyMap(), - 'allModelElements': Property( - getValue: (CT_ c) => c.allModelElements, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.allModelElements.map((e) => _render_ModelElement( - e, ast, r.template, sink, - parent: r)); - }, - ), + ..._Renderer_Class.propertyMap(), 'constantFields': Property( getValue: (CT_ c) => c.constantFields, renderVariable: (CT_ c, Property self, @@ -4597,74 +4582,6 @@ class _Renderer_Enum extends RendererBase { _render_Field(e, ast, r.template, sink, parent: r)); }, ), - 'element': Property( - getValue: (CT_ c) => c.element, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'EnumElement'), - isNullValue: (CT_ c) => false, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - renderSimple(c.element, ast, r.template, sink, - parent: r, getters: _invisibleGetters['EnumElement']!); - }, - ), - 'hasPublicEnumValues': Property( - getValue: (CT_ c) => c.hasPublicEnumValues, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.hasPublicEnumValues, - ), - 'inheritanceChain': Property( - getValue: (CT_ c) => c.inheritanceChain, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.inheritanceChain.map((e) => - _render_InheritingContainer(e, ast, r.template, sink, - parent: r)); - }, - ), - 'isAbstract': Property( - getValue: (CT_ c) => c.isAbstract, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.isAbstract, - ), - 'isBase': Property( - getValue: (CT_ c) => c.isBase, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.isBase, - ), - 'isInterface': Property( - getValue: (CT_ c) => c.isInterface, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.isInterface, - ), - 'isMixinClass': Property( - getValue: (CT_ c) => c.isMixinClass, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.isMixinClass, - ), - 'isSealed': Property( - getValue: (CT_ c) => c.isSealed, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable(c, remainingNames, 'bool'), - getBool: (CT_ c) => c.isSealed, - ), 'kind': Property( getValue: (CT_ c) => c.kind, renderVariable: (CT_ c, Property self, @@ -12550,7 +12467,7 @@ class _Renderer_Package extends RendererBase { } } -String renderSearchPage(PackageTemplateData context, Template template) { +String renderError(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -12788,13 +12705,13 @@ class _Renderer_PackageTemplateData extends RendererBase { } } -String renderIndex(PackageTemplateData context, Template template) { +String renderSearchPage(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); } -String renderError(PackageTemplateData context, Template template) { +String renderIndex(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -16242,27 +16159,6 @@ const _invisibleGetters = { 'lineNumber', 'runtimeType' }, - 'ClassElement': { - 'augmentation', - 'augmentationTarget', - 'augmented', - 'hasNonFinalField', - 'hashCode', - 'isAbstract', - 'isBase', - 'isConstructable', - 'isDartCoreEnum', - 'isDartCoreObject', - 'isExhaustive', - 'isFinal', - 'isInline', - 'isInterface', - 'isMixinApplication', - 'isMixinClass', - 'isSealed', - 'isValidMixin', - 'runtimeType' - }, 'CommentReferable': { 'definingCommentReferable', 'href', @@ -16494,13 +16390,6 @@ const _invisibleGetters = { 'isVisibleOutsideTemplate', 'runtimeType' }, - 'EnumElement': { - 'augmentation', - 'augmentationTarget', - 'augmented', - 'hashCode', - 'runtimeType' - }, 'ExecutableMember': { 'augmentationSubstitution', 'children', diff --git a/lib/src/model/class.dart b/lib/src/model/class.dart index f61af52c4d..1b5d3dc2a2 100644 --- a/lib/src/model/class.dart +++ b/lib/src/model/class.dart @@ -5,7 +5,7 @@ import 'package:analyzer/dart/element/element.dart'; import 'package:dartdoc/src/model/model.dart'; -/// A [Container] defined with a `class` declaration in Dart. +/// A [Container] defined with a `class` or `enum` declaration. /// /// Members follow similar naming rules to [Container], with the following /// additions: @@ -15,7 +15,7 @@ import 'package:dartdoc/src/model/model.dart'; class Class extends InheritingContainer with Constructable, TypeImplementing, MixedInTypes { @override - final ClassElement element; + final InterfaceElement element; @override late final List allModelElements = [ @@ -48,10 +48,16 @@ class Class extends InheritingContainer } @override - bool get isAbstract => element.isAbstract; + bool get isAbstract => switch (element) { + ClassElement class_ when class_.isAbstract => true, + _ => false, + }; @override - bool get isBase => element.isBase && !element.isSealed; + bool get isBase => switch (element) { + ClassElement class_ when class_.isBase && !class_.isSealed => true, + _ => false, + }; bool get isErrorOrException { bool isError(InterfaceElement element) => @@ -64,16 +70,28 @@ class Class extends InheritingContainer } @override - bool get isFinal => element.isFinal && !element.isSealed; + bool get isFinal => switch (element) { + ClassElement class_ when class_.isFinal && !class_.isSealed => true, + _ => false, + }; @override - bool get isInterface => element.isInterface && !element.isSealed; + bool get isInterface => switch (element) { + ClassElement class_ when class_.isInterface && !class_.isSealed => true, + _ => false, + }; @override - bool get isMixinClass => element.isMixinClass; + bool get isMixinClass => switch (element) { + ClassElement class_ when class_.isMixinClass => true, + _ => false, + }; @override - bool get isSealed => element.isSealed; + bool get isSealed => switch (element) { + ClassElement class_ when class_.isSealed => true, + _ => false, + }; @override Kind get kind => Kind.class_; diff --git a/lib/src/model/container.dart b/lib/src/model/container.dart index 6791e67839..959ee6e9e7 100644 --- a/lib/src/model/container.dart +++ b/lib/src/model/container.dart @@ -153,8 +153,16 @@ abstract class Container extends ModelElement late final List publicConstantFieldsSorted = publicConstantFields.toList(growable: false)..sort(byName); + /// The total list of public enum values. + /// + /// This is defined on [Container] instead of just [Enum], because the + /// `ContainerSidebar` Mustache template needs to refer to this field. Iterable get publicEnumValues => const []; + /// Whether this container has any public enum values. + /// + /// This is defined on [Container] instead of just [Enum], because the + /// `ContainerSidebar` Mustache template needs to refer to this field. bool get hasPublicEnumValues => publicEnumValues.isNotEmpty; Iterable get instanceAccessors => diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart index 0efcefbd6e..f1f856520c 100644 --- a/lib/src/model/enum.dart +++ b/lib/src/model/enum.dart @@ -8,31 +8,8 @@ import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model_utils.dart' as model_utils; import 'package:dartdoc/src/render/enum_field_renderer.dart'; -/// The [Enum] class only inherits from [InheritingContainer] because declared -/// `enum`s inherit methods from [Object]. It can't actually participate -/// meaningfully in other inheritance or have class modifiers. -class Enum extends InheritingContainer - with Constructable, TypeImplementing, MixedInTypes { - @override - final EnumElement element; - - Enum(this.element, super.library, super.packageGraph); - - @override - late final List allModelElements = [ - ...super.allModelElements, - ...constructors, - ]; - - @override - late final List inheritanceChain = [ - this, - for (var container in mixedInElements.reversed) - ...container.inheritanceChain, - for (var container in superChain.modelElements) - ...container.inheritanceChain, - ...interfaceElements.expandInheritanceChain, - ]; +class Enum extends Class { + Enum(super.element, super.library, super.packageGraph); @override String get sidebarPath => '${library.dirName}/$name-enum-sidebar.html'; @@ -45,30 +22,12 @@ class Enum extends InheritingContainer @override Iterable get constantFields => - declaredFields.where((f) => f is! EnumField && f.isConst); + super.constantFields.where((f) => f is! EnumField); @override late final List publicEnumValues = model_utils .filterNonPublic(allFields.whereType()) .toList(growable: false); - - @override - bool get hasPublicEnumValues => publicEnumValues.isNotEmpty; - - @override - bool get isAbstract => false; - - @override - bool get isBase => false; - - @override - bool get isInterface => false; - - @override - bool get isMixinClass => false; - - @override - bool get isSealed => false; } /// A field specific to an enum's values. diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 231f4a7b69..fdae87bb12 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -422,8 +422,8 @@ abstract class ModelElement extends Canonicalization final enclosingElement = this.enclosingElement; var preferredClass = switch (enclosingElement) { // TODO(srawlins): Add mixin. - Class() => enclosingElement, Enum() => enclosingElement, + Class() => enclosingElement, Extension() => enclosingElement, ExtensionType() => enclosingElement, _ => null, diff --git a/lib/src/render/enum_field_renderer.dart b/lib/src/render/enum_field_renderer.dart index 8f2779d265..539390e70c 100644 --- a/lib/src/render/enum_field_renderer.dart +++ b/lib/src/render/enum_field_renderer.dart @@ -14,15 +14,11 @@ class EnumFieldRendererHtml implements EnumFieldRenderer { const EnumFieldRendererHtml(); @override - String renderValue(EnumField field) { - if (field.name == 'values') { - return 'const List<' + String renderValue(EnumField field) => field.name == 'values' + ? 'const List<' '${field.enclosingElement.name}' - '>'; - } else { - return 'const ${field.enclosingElement.name}(${field.index})'; - } - } + '>' + : field.constantValue; @override String renderLinkedName(EnumField field) { diff --git a/test/enum_test.dart b/test/enum_test.dart index 9d23a19447..1707c28ce4 100644 --- a/test/enum_test.dart +++ b/test/enum_test.dart @@ -400,10 +400,16 @@ enum E { one, two } '''); var oneValue = library.enums.named('E').publicEnumValues.named('one'); - expect(oneValue.constantValueTruncated, 'const E(0)'); + expect( + oneValue.constantValueTruncated, + 'const E(0)', + ); var twoValue = library.enums.named('E').publicEnumValues.named('two'); - expect(twoValue.constantValueTruncated, 'const E(1)'); + expect( + twoValue.constantValueTruncated, + 'const E(1)', + ); } void test_constantValue_explicitConstructorCall() async { @@ -605,9 +611,18 @@ enum E { var threeValue = library.enums.named('E').publicEnumValues.named('three') as EnumField; - expect(oneValue.constantValue, equals('const E(0)')); - expect(twoValue.constantValue, equals('const E(1)')); - expect(threeValue.constantValue, equals('const E(2)')); + expect( + oneValue.constantValue, + equals('const E(0)'), + ); + expect( + twoValue.constantValue, + equals('const E(1)'), + ); + expect( + threeValue.constantValue, + equals('const E(2)'), + ); } void test_valuesConstant() async { diff --git a/test/templates/method_test.dart b/test/templates/method_test.dart index 02df945f5b..a87be07beb 100644 --- a/test/templates/method_test.dart +++ b/test/templates/method_test.dart @@ -2,99 +2,207 @@ // 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. -import 'package:analyzer/file_system/memory_file_system.dart'; -import 'package:dartdoc/src/dartdoc.dart'; -import 'package:dartdoc/src/model/model.dart'; -import 'package:path/path.dart' as path; import 'package:test/test.dart'; +import 'package:test_reflective_loader/test_reflective_loader.dart'; -import '../src/test_descriptor_utils.dart' as d; import '../src/utils.dart'; +import 'template_test_base.dart'; + void main() async { - const packageName = 'test_package'; - - late List m1Lines; - - group('methods', () { - setUpAll(() async { - final packageMetaProvider = testPackageMetaProvider; - final resourceProvider = - packageMetaProvider.resourceProvider as MemoryResourceProvider; - final packagePath = await d.createPackage( - packageName, - pubspec: ''' -name: methods -version: 0.0.1 -environment: - sdk: '>=2.18.0 <3.0.0' -''', - libFiles: [ - d.file('lib.dart', ''' + defineReflectiveSuite(() { + defineReflectiveTests(MethodTest); + }); +} + +@reflectiveTest +class MethodTest extends TemplateTestBase { + @override + String get packageName => 'method_test'; + + @override + String get libraryName => 'method'; + + void test_methodName() async { + await createPackageWithLibrary(''' +class C { + void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'C', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder([ + matches('

m1 method'), + ]); + } + + void test_annotations() async { + await createPackageWithLibrary(''' class A { const A(String m); } -class B { +class C { @deprecated @A('message') void m1() {} } -'''), - ], - resourceProvider: resourceProvider, - ); - await writeDartdocResources(resourceProvider); - final context = await generatorContextFromArgv([ - '--input', - packagePath, - '--output', - path.join(packagePath, 'doc'), - '--sdk-dir', - packageMetaProvider.defaultSdkDir.path, - '--no-link-to-remote', - ], packageMetaProvider); - - final packageConfigProvider = - getTestPackageConfigProvider(packageMetaProvider.defaultSdkDir.path); - packageConfigProvider.addPackageToConfigFor( - packagePath, packageName, Uri.file('$packagePath/')); - final packageBuilder = PubPackageBuilder( - context, - packageMetaProvider, - packageConfigProvider, - skipUnreachableSdkLibraries: true, - ); - await (await Dartdoc.fromContext(context, packageBuilder)).generateDocs(); - m1Lines = resourceProvider - .getFile(path.join(packagePath, 'doc', 'lib', 'B', 'm1.html')) - .readAsStringSync() - .split('\n'); - }); - - test('method page contains method name', () async { - m1Lines.expectMainContentContainsAllInOrder( - [ - matches('

m1 method'), - ], - ); - }); - - test('method page contains annotations', () async { - m1Lines.expectMainContentContainsAllInOrder( - [ - matches('
    '), - matches('
  1. @deprecated
  2. '), - matches( - r'
  3. @A\('message'\)
  4. '), - matches('
'), - ], - ); - }); - - // TODO(srawlins): Add rendering tests. - // * how inherited members look on subclass page ('inherited' feature) - // * generic methods, static methods - // * linked elements in signature - }); +'''); + var m1Lines = readLines(['lib', 'C', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('
    '), + matches('
  1. @deprecated
  2. '), + matches( + r'
  3. @A\('message'\)
  4. '), + matches('
'), + ], + ); + } + + void test_onClass() async { + await createPackageWithLibrary(''' +class C { + void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'C', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 method'), + ], + ); + } + + void test_onClass_static() async { + await createPackageWithLibrary(''' +class C { + static void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'C', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 static method'), + ], + ); + } + + void test_onEnum() async { + await createPackageWithLibrary(''' +enum E { + one, two; + void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'E', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 method'), + ], + ); + } + + void test_onEnum_static() async { + await createPackageWithLibrary(''' +enum E { + one, two; + static void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'E', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 static method'), + ], + ); + } + + void test_onExtension() async { + await createPackageWithLibrary(''' +extension E on int { + void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'E', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 method'), + ], + ); + } + + void test_onExtension_static() async { + await createPackageWithLibrary(''' +extension E on int { + static void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'E', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 static method'), + ], + ); + } + + void test_onMixin() async { + await createPackageWithLibrary(''' +mixin M { + void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'M', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 method'), + ], + ); + } + + void test_onMixin_static() async { + await createPackageWithLibrary(''' +mixin M { + static void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'M', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 static method'), + ], + ); + } + + void test_onExtensionType() async { + await createPackageWithLibrary(''' +extension type E(int it) { + void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'E', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 method'), + ], + ); + } + + void test_onExtensionType_static() async { + await createPackageWithLibrary(''' +extension type E(int it) { + static void m1() {} +} +'''); + var m1Lines = readLines(['lib', 'E', 'm1.html']); + m1Lines.expectMainContentContainsAllInOrder( + [ + matches('

m1 static method'), + ], + ); + } + + // TODO(srawlins): Add rendering tests. + // * how inherited members look on subclass page ('inherited' feature) + // * generic methods + // * linked elements in signature } diff --git a/test/templates/template_test_base.dart b/test/templates/template_test_base.dart index e229b9df77..889ae71ec2 100644 --- a/test/templates/template_test_base.dart +++ b/test/templates/template_test_base.dart @@ -2,6 +2,7 @@ // 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. +import 'package:analyzer/file_system/file_system.dart'; import 'package:analyzer/file_system/memory_file_system.dart'; import 'package:path/path.dart' as path; @@ -40,6 +41,34 @@ environment: } extension on MemoryResourceProvider { - List readLines(List pathParts) => - getFile(path.joinAll(pathParts)).readAsStringSync().split('\n'); + List readLines(List pathParts) { + try { + return getFile(path.joinAll(pathParts)).readAsStringSync().split('\n'); + } on FileSystemException { + void listRecursive(Folder folder, {required int indentDepth}) { + var indent = ' ${'│ ' * indentDepth}'; + var children = folder.getChildren(); + for (var child in children) { + var pipes = child == children.last ? '└─' : '├─'; + if (child is File) { + print('$indent$pipes ${child.shortName}'); + } else if (child is Folder) { + print('$indent$pipes ${child.shortName}/'); + listRecursive(child, indentDepth: indentDepth + 1); + } + } + } + + // Attempt to show the files listed in the generated `doc/` directory. + var docIndex = pathParts.indexOf('doc'); + if (docIndex > -1) { + var docPath = path.joinAll(pathParts.getRange(0, docIndex + 1)); + print('$docPath/'); + var docFolder = getFolder(docPath); + listRecursive(docFolder, indentDepth: 0); + } + + rethrow; + } + } } From e188d5b7e55456149e4be1f3b57d98ef1b0b6a3a Mon Sep 17 00:00:00 2001 From: Sam Rawlins Date: Wed, 6 Mar 2024 17:19:47 -0800 Subject: [PATCH 2/2] Back out inheritance change --- .../templates.aot_renderers_for_html.dart | 85 ++++++++++------ .../templates.runtime_renderers.dart | 97 ++++++++++++++++++- lib/src/model/enum.dart | 44 ++++++++- lib/src/model/model_element.dart | 2 +- test/enum_test.dart | 25 +++-- 5 files changed, 200 insertions(+), 53 deletions(-) diff --git a/lib/src/generator/templates.aot_renderers_for_html.dart b/lib/src/generator/templates.aot_renderers_for_html.dart index bcddb1bb58..203c8e3756 100644 --- a/lib/src/generator/templates.aot_renderers_for_html.dart +++ b/lib/src/generator/templates.aot_renderers_for_html.dart @@ -2661,8 +2661,32 @@ String _renderClass_partial_interfaces_6(Class context1) { return buffer.toString(); } -String _renderClass_partial_mixed_in_types_7(Class context1) => - _deduplicated_lib_templates__mixed_in_types_html(context1); +String _renderClass_partial_mixed_in_types_7(Class context1) { + final buffer = StringBuffer(); + if (context1.hasPublicMixedInTypes) { + buffer.writeln(); + buffer.write(''' +
Mixed in types
+
+
    '''); + var context2 = context1.publicMixedInTypes; + for (var context3 in context2) { + buffer.writeln(); + buffer.write(''' +
  • '''); + buffer.write(context3.linkedName); + buffer.write('''
  • '''); + } + buffer.writeln(); + buffer.write(''' +
+
'''); + } + + return buffer.toString(); +} String _renderClass_partial_container_annotations_8(Class context1) => _deduplicated_lib_templates__container_annotations_html(context1); @@ -2764,8 +2788,32 @@ String _renderEnum_partial_interfaces_6(Enum context1) { return buffer.toString(); } -String _renderEnum_partial_mixed_in_types_7(Enum context1) => - _deduplicated_lib_templates__mixed_in_types_html(context1); +String _renderEnum_partial_mixed_in_types_7(Enum context1) { + final buffer = StringBuffer(); + if (context1.hasPublicMixedInTypes) { + buffer.writeln(); + buffer.write(''' +
Mixed in types
+
+
    '''); + var context2 = context1.publicMixedInTypes; + for (var context3 in context2) { + buffer.writeln(); + buffer.write(''' +
  • '''); + buffer.write(context3.linkedName); + buffer.write('''
  • '''); + } + buffer.writeln(); + buffer.write(''' +
+
'''); + } + + return buffer.toString(); +} String _renderEnum_partial_container_annotations_8(Enum context1) => _deduplicated_lib_templates__container_annotations_html(context1); @@ -4436,7 +4484,7 @@ String _deduplicated_lib_templates__feature_set_html(ModelElement context0) { } String _deduplicated_lib_templates__super_chain_html( - TypeImplementing context0) { + InheritingContainer context0) { final buffer = StringBuffer(); if (context0.hasPublicSuperChainReversed) { buffer.writeln(); @@ -4470,33 +4518,6 @@ String _deduplicated_lib_templates__super_chain_html( return buffer.toString(); } -String _deduplicated_lib_templates__mixed_in_types_html(Class context0) { - final buffer = StringBuffer(); - if (context0.hasPublicMixedInTypes) { - buffer.writeln(); - buffer.write(''' -
Mixed in types
-
-
    '''); - var context1 = context0.publicMixedInTypes; - for (var context2 in context1) { - buffer.writeln(); - buffer.write(''' -
  • '''); - buffer.write(context2.linkedName); - buffer.write('''
  • '''); - } - buffer.writeln(); - buffer.write(''' -
-
'''); - } - - return buffer.toString(); -} - String _deduplicated_lib_templates__container_annotations_html( Container context0) { final buffer = StringBuffer(); diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 51f4f8bece..0a41945734 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -4569,7 +4569,23 @@ class _Renderer_Enum extends RendererBase { _propertyMapCache.putIfAbsent( CT_, () => { - ..._Renderer_Class.propertyMap(), + ..._Renderer_InheritingContainer.propertyMap(), + ..._Renderer_Constructable.propertyMap(), + ..._Renderer_TypeImplementing.propertyMap(), + ..._Renderer_MixedInTypes.propertyMap(), + 'allModelElements': Property( + getValue: (CT_ c) => c.allModelElements, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'List'), + renderIterable: (CT_ c, RendererBase r, + List ast, StringSink sink) { + return c.allModelElements.map((e) => _render_ModelElement( + e, ast, r.template, sink, + parent: r)); + }, + ), 'constantFields': Property( getValue: (CT_ c) => c.constantFields, renderVariable: (CT_ c, Property self, @@ -4582,6 +4598,74 @@ class _Renderer_Enum extends RendererBase { _render_Field(e, ast, r.template, sink, parent: r)); }, ), + 'element': Property( + getValue: (CT_ c) => c.element, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'EnumElement'), + isNullValue: (CT_ c) => false, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + renderSimple(c.element, ast, r.template, sink, + parent: r, getters: _invisibleGetters['EnumElement']!); + }, + ), + 'hasPublicEnumValues': Property( + getValue: (CT_ c) => c.hasPublicEnumValues, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.hasPublicEnumValues, + ), + 'inheritanceChain': Property( + getValue: (CT_ c) => c.inheritanceChain, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'List'), + renderIterable: (CT_ c, RendererBase r, + List ast, StringSink sink) { + return c.inheritanceChain.map((e) => + _render_InheritingContainer(e, ast, r.template, sink, + parent: r)); + }, + ), + 'isAbstract': Property( + getValue: (CT_ c) => c.isAbstract, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.isAbstract, + ), + 'isBase': Property( + getValue: (CT_ c) => c.isBase, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.isBase, + ), + 'isInterface': Property( + getValue: (CT_ c) => c.isInterface, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.isInterface, + ), + 'isMixinClass': Property( + getValue: (CT_ c) => c.isMixinClass, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.isMixinClass, + ), + 'isSealed': Property( + getValue: (CT_ c) => c.isSealed, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.isSealed, + ), 'kind': Property( getValue: (CT_ c) => c.kind, renderVariable: (CT_ c, Property self, @@ -12455,7 +12539,7 @@ class _Renderer_Package extends RendererBase { } } -String renderError(PackageTemplateData context, Template template) { +String renderSearchPage(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -12693,7 +12777,7 @@ class _Renderer_PackageTemplateData extends RendererBase { } } -String renderSearchPage(PackageTemplateData context, Template template) { +String renderError(PackageTemplateData context, Template template) { var buffer = StringBuffer(); _render_PackageTemplateData(context, template.ast, template, buffer); return buffer.toString(); @@ -16378,6 +16462,13 @@ const _invisibleGetters = { 'isVisibleOutsideTemplate', 'runtimeType' }, + 'EnumElement': { + 'augmentation', + 'augmentationTarget', + 'augmented', + 'hashCode', + 'runtimeType' + }, 'ExecutableMember': { 'augmentationSubstitution', 'children', diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart index f1f856520c..ee09cbec00 100644 --- a/lib/src/model/enum.dart +++ b/lib/src/model/enum.dart @@ -8,8 +8,28 @@ import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/model_utils.dart' as model_utils; import 'package:dartdoc/src/render/enum_field_renderer.dart'; -class Enum extends Class { - Enum(super.element, super.library, super.packageGraph); +class Enum extends InheritingContainer + with Constructable, TypeImplementing, MixedInTypes { + @override + final EnumElement element; + + Enum(this.element, super.library, super.packageGraph); + + @override + late final List allModelElements = [ + ...super.allModelElements, + ...constructors, + ]; + + @override + late final List inheritanceChain = [ + this, + for (var container in mixedInElements.reversed) + ...container.inheritanceChain, + for (var container in superChain.modelElements) + ...container.inheritanceChain, + ...interfaceElements.expandInheritanceChain, + ]; @override String get sidebarPath => '${library.dirName}/$name-enum-sidebar.html'; @@ -22,12 +42,30 @@ class Enum extends Class { @override Iterable get constantFields => - super.constantFields.where((f) => f is! EnumField); + declaredFields.where((f) => f is! EnumField && f.isConst); @override late final List publicEnumValues = model_utils .filterNonPublic(allFields.whereType()) .toList(growable: false); + + @override + bool get hasPublicEnumValues => publicEnumValues.isNotEmpty; + + @override + bool get isAbstract => false; + + @override + bool get isBase => false; + + @override + bool get isInterface => false; + + @override + bool get isMixinClass => false; + + @override + bool get isSealed => false; } /// A field specific to an enum's values. diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index fdae87bb12..231f4a7b69 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -422,8 +422,8 @@ abstract class ModelElement extends Canonicalization final enclosingElement = this.enclosingElement; var preferredClass = switch (enclosingElement) { // TODO(srawlins): Add mixin. - Enum() => enclosingElement, Class() => enclosingElement, + Enum() => enclosingElement, Extension() => enclosingElement, ExtensionType() => enclosingElement, _ => null, diff --git a/test/enum_test.dart b/test/enum_test.dart index 1707c28ce4..e8e9bc623b 100644 --- a/test/enum_test.dart +++ b/test/enum_test.dart @@ -402,13 +402,17 @@ enum E { one, two } var oneValue = library.enums.named('E').publicEnumValues.named('one'); expect( oneValue.constantValueTruncated, - 'const E(0)', + // TODO(srawlins): This should link back to the E enum. Something like + // `'const E(0)'`. + 'const E(0)', ); var twoValue = library.enums.named('E').publicEnumValues.named('two'); expect( twoValue.constantValueTruncated, - 'const E(1)', + // TODO(srawlins): This should link back to the E enum. Something like + // `'const E(1)'`. + 'const E(1)', ); } @@ -611,18 +615,11 @@ enum E { var threeValue = library.enums.named('E').publicEnumValues.named('three') as EnumField; - expect( - oneValue.constantValue, - equals('const E(0)'), - ); - expect( - twoValue.constantValue, - equals('const E(1)'), - ); - expect( - threeValue.constantValue, - equals('const E(2)'), - ); + // TODO(srawlins): These should link back to the E enum. Something like + // `'const E(0)'`. + expect(oneValue.constantValue, equals('const E(0)')); + expect(twoValue.constantValue, equals('const E(1)')); + expect(threeValue.constantValue, equals('const E(2)')); } void test_valuesConstant() async {