diff --git a/lib/src/generator/templates.renderers.dart b/lib/src/generator/templates.renderers.dart index 1a3cb162bb..4baae0f571 100644 --- a/lib/src/generator/templates.renderers.dart +++ b/lib/src/generator/templates.renderers.dart @@ -8143,18 +8143,6 @@ class _Renderer_GetterSetterCombo extends RendererBase { parent: r); }, ), - 'comboFeatures': Property( - getValue: (CT_ c) => c.comboFeatures, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'Set'), - renderIterable: - (CT_ c, RendererBase r, List ast) { - return c.comboFeatures.map( - (e) => _render_String(e, ast, r.template, parent: r)); - }, - ), 'constantInitializer': Property( getValue: (CT_ c) => c.constantInitializer, renderVariable: (CT_ c, Property self, diff --git a/lib/src/model/container_member.dart b/lib/src/model/container_member.dart index 64c69b089d..110eb17aa5 100644 --- a/lib/src/model/container_member.dart +++ b/lib/src/model/container_member.dart @@ -25,11 +25,10 @@ mixin ContainerMember on ModelElement implements EnclosedElement { } @override - Set get features { - var _features = super.features; - if (isExtended) _features.add('extended'); - return _features; - } + Set get features => { + ...super.features, + if (isExtended) 'extended', + }; bool _canonicalEnclosingContainerIsSet = false; Container _canonicalEnclosingContainer; diff --git a/lib/src/model/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart index fa5ff1cfb1..aef7100a39 100644 --- a/lib/src/model/getter_setter_combo.dart +++ b/lib/src/model/getter_setter_combo.dart @@ -12,6 +12,7 @@ import 'package:dartdoc/src/element_type.dart'; import 'package:dartdoc/src/model/model.dart'; import 'package:dartdoc/src/utils.dart'; import 'package:dartdoc/src/warnings.dart'; +import 'package:meta/meta.dart'; /// Mixin for top-level variables and fields (aka properties) mixin GetterSetterCombo on ModelElement { @@ -25,6 +26,7 @@ mixin GetterSetterCombo on ModelElement { } } + @protected Set get comboFeatures { var allFeatures = {}; if (hasExplicitGetter && hasPublicGetter) { diff --git a/lib/src/model/inheritable.dart b/lib/src/model/inheritable.dart index 7c4e03ccd5..f1656519ec 100644 --- a/lib/src/model/inheritable.dart +++ b/lib/src/model/inheritable.dart @@ -28,13 +28,12 @@ mixin Inheritable on ContainerMember { bool get isCovariant; @override - Set get features { - var _features = super.features; - if (isOverride) _features.add('override'); - if (isInherited) _features.add('inherited'); - if (isCovariant) _features.add('covariant'); - return _features; - } + Set get features => { + ...super.features, + if (isOverride) 'override', + if (isInherited) 'inherited', + if (isCovariant) 'covariant', + }; @override Library get canonicalLibrary => canonicalEnclosingContainer?.canonicalLibrary; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index b145af31fe..47fca3717c 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -384,6 +384,8 @@ abstract class ModelElement extends Canonicalization throw 'Unknown type ${e.runtimeType}'; } + static const _htmlEscape = HtmlEscape(); + // Stub for mustache, which would otherwise search enclosing elements to find // names for members. bool get hasCategoryNames => false; @@ -412,30 +414,11 @@ abstract class ModelElement extends Canonicalization var annotationStrings = []; if (md == null) return annotationStrings; for (var a in md) { - var annotation = (const HtmlEscape()).convert(a.toSource()); - var annotationElement = a.element; - - if (annotationElement is ConstructorElement) { - // TODO(srawlins): I think we should actually link to the constructor, - // which may have details about parameters. For example, given the - // annotation `@Immutable('text')`, the constructor documents what the - // parameter is, and the class only references `immutable`. It's a - // lose-lose cycle of mis-direction. - annotationElement = - (annotationElement as ConstructorElement).returnType.element; - } else if (annotationElement is PropertyAccessorElement) { - annotationElement = - (annotationElement as PropertyAccessorElement).variable; - } - if (annotationElement is Member) { - annotationElement = (annotationElement as Member).declaration; - } - - // Some annotations are intended to be invisible (such as `@pragma`). - if (!_shouldDisplayAnnotation(annotationElement)) continue; + if (!_shouldDisplayAnnotation(a.realElement)) continue; + var annotation = _htmlEscape.convert(a.toSource()); var annotationModelElement = - packageGraph.findCanonicalModelElementFor(annotationElement); + packageGraph.findCanonicalModelElementFor(a.realElement); if (annotationModelElement != null) { annotation = annotation.replaceFirst( annotationModelElement.name, annotationModelElement.linkedName); @@ -445,6 +428,10 @@ abstract class ModelElement extends Canonicalization return annotationStrings; } + /// Returns whether [annotationElement] should be displayed when rendering + /// this element. + /// + /// Some annotations are intended to be invisible (such as `@pragma`). bool _shouldDisplayAnnotation(Element annotationElement) { if (annotationElement is ClassElement) { var annotationClass = @@ -540,6 +527,8 @@ abstract class ModelElement extends Canonicalization }; } + /// Returns [features] as a single String, sorted [byFeatureOrdering], joined + /// with commas. String get featuresAsString { var allFeatures = features.toList()..sort(byFeatureOrdering); return allFeatures.join(', '); @@ -1222,3 +1211,26 @@ abstract class ModelElement extends Canonicalization }); } } + +extension on ElementAnnotation { + /// Returns this annotation's "real" element, passing through unused, + /// intermediate elements. + Element get realElement { + Element getDeclaration(Element e) => e is Member ? e.declaration : e; + + var element = this.element; + + if (element is ConstructorElement) { + // TODO(srawlins): I think we should actually link to the constructor, + // which may have details about parameters. For example, given the + // annotation `@Immutable('text')`, the constructor documents what the + // parameter is, and the class only references `immutable`. It's a + // lose-lose cycle of mis-direction. + return getDeclaration(element.returnType.element); + } else if (element is PropertyAccessorElement) { + return getDeclaration(element.variable); + } else { + return getDeclaration(element); + } + } +} diff --git a/lib/templates/html/_features.html b/lib/templates/html/_features.html index 507bd0d8a7..14379183cb 100644 --- a/lib/templates/html/_features.html +++ b/lib/templates/html/_features.html @@ -1 +1 @@ -{{ #featuresAsString.isNotEmpty }}
{{{featuresAsString}}}
{{ /featuresAsString.isNotEmpty }} +{{ #features }}
{{{featuresAsString}}}
{{ /features }} diff --git a/lib/templates/md/_features.md b/lib/templates/md/_features.md index 2083ee0c19..d02fc49854 100644 --- a/lib/templates/md/_features.md +++ b/lib/templates/md/_features.md @@ -1 +1 @@ -{{ #featuresAsString.isNotEmpty }}_{{{featuresAsString}}}_{{ /featuresAsString.isNotEmpty }} +{{ #features }}_{{{featuresAsString}}}_{{ /features }}