diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 5abfcd2d64..2b1240781b 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -68,6 +68,27 @@ class _Renderer_Accessor extends RendererBase { getters: _invisibleGetters['GetterSetterCombo']); }, ), + 'documentationComment': Property( + getValue: (CT_ c) => c.documentationComment, + renderVariable: + (CT_ c, Property self, List remainingNames) { + if (remainingNames.isEmpty) { + return self.getValue(c).toString(); + } + var name = remainingNames.first; + var nextProperty = + _Renderer_String.propertyMap().getValue(name); + return nextProperty.renderVariable(self.getValue(c), + nextProperty, [...remainingNames.skip(1)]); + }, + isNullValue: (CT_ c) => c.documentationComment == null, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + _render_String( + c.documentationComment, ast, r.template, sink, + parent: r); + }, + ), 'element': Property( getValue: (CT_ c) => c.element, renderVariable: (CT_ c, Property self, @@ -3907,6 +3928,26 @@ class _Renderer_DocumentationComment _propertyMapCache.putIfAbsent( CT_, () => { + 'documentationAsHtml': Property( + getValue: (CT_ c) => c.documentationAsHtml, + renderVariable: + (CT_ c, Property self, List remainingNames) { + if (remainingNames.isEmpty) { + return self.getValue(c).toString(); + } + var name = remainingNames.first; + var nextProperty = + _Renderer_String.propertyMap().getValue(name); + return nextProperty.renderVariable(self.getValue(c), + nextProperty, [...remainingNames.skip(1)]); + }, + isNullValue: (CT_ c) => c.documentationAsHtml == null, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + _render_String(c.documentationAsHtml, ast, r.template, sink, + parent: r); + }, + ), 'documentationComment': Property( getValue: (CT_ c) => c.documentationComment, renderVariable: @@ -3928,6 +3969,20 @@ class _Renderer_DocumentationComment parent: r); }, ), + 'documentationFrom': Property( + getValue: (CT_ c) => c.documentationFrom, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'List'), + renderIterable: (CT_ c, RendererBase r, + List ast, StringSink sink) { + return c.documentationFrom.map((e) => renderSimple( + e, ast, r.template, sink, + parent: r, + getters: _invisibleGetters['DocumentationComment'])); + }, + ), 'documentationLocal': Property( getValue: (CT_ c) => c.documentationLocal, renderVariable: @@ -3948,6 +4003,19 @@ class _Renderer_DocumentationComment parent: r); }, ), + 'elementDocumentation': Property( + getValue: (CT_ c) => c.elementDocumentation, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable( + c, remainingNames, 'Documentation'), + isNullValue: (CT_ c) => c.elementDocumentation == null, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + renderSimple(c.elementDocumentation, ast, r.template, sink, + parent: r, getters: _invisibleGetters['Documentation']); + }, + ), 'fullyQualifiedNameWithoutLibrary': Property( getValue: (CT_ c) => c.fullyQualifiedNameWithoutLibrary, renderVariable: @@ -5865,17 +5933,39 @@ class _Renderer_GetterSetterCombo extends RendererBase { parent: r); }, ), + 'documentationComment': Property( + getValue: (CT_ c) => c.documentationComment, + renderVariable: + (CT_ c, Property self, List remainingNames) { + if (remainingNames.isEmpty) { + return self.getValue(c).toString(); + } + var name = remainingNames.first; + var nextProperty = + _Renderer_String.propertyMap().getValue(name); + return nextProperty.renderVariable(self.getValue(c), + nextProperty, [...remainingNames.skip(1)]); + }, + isNullValue: (CT_ c) => c.documentationComment == null, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + _render_String( + c.documentationComment, ast, r.template, sink, + parent: r); + }, + ), 'documentationFrom': Property( getValue: (CT_ c) => c.documentationFrom, renderVariable: (CT_ c, Property self, List remainingNames) => self.renderSimpleVariable( - c, remainingNames, 'List'), + c, remainingNames, 'List'), renderIterable: (CT_ c, RendererBase r, List ast, StringSink sink) { - return c.documentationFrom.map((e) => _render_ModelElement( + return c.documentationFrom.map((e) => renderSimple( e, ast, r.template, sink, - parent: r)); + parent: r, + getters: _invisibleGetters['DocumentationComment'])); }, ), 'enclosingElement': Property( @@ -5926,28 +6016,6 @@ class _Renderer_GetterSetterCombo extends RendererBase { self.renderSimpleVariable(c, remainingNames, 'bool'), getBool: (CT_ c) => c.getterSetterBothAvailable == true, ), - 'getterSetterDocumentationComment': Property( - getValue: (CT_ c) => c.getterSetterDocumentationComment, - renderVariable: - (CT_ c, Property self, List remainingNames) { - if (remainingNames.isEmpty) { - return self.getValue(c).toString(); - } - var name = remainingNames.first; - var nextProperty = - _Renderer_String.propertyMap().getValue(name); - return nextProperty.renderVariable(self.getValue(c), - nextProperty, [...remainingNames.skip(1)]); - }, - isNullValue: (CT_ c) => - c.getterSetterDocumentationComment == null, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_String(c.getterSetterDocumentationComment, ast, - r.template, sink, - parent: r); - }, - ), 'hasAccessorsWithDocs': Property( getValue: (CT_ c) => c.hasAccessorsWithDocs, renderVariable: (CT_ c, Property self, @@ -9397,19 +9465,6 @@ class _Renderer_ModelElement extends RendererBase { getters: _invisibleGetters['CompilationUnitElement']); }, ), - 'computeDocumentationFrom': Property( - getValue: (CT_ c) => c.computeDocumentationFrom, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.computeDocumentationFrom.map((e) => - _render_ModelElement(e, ast, r.template, sink, - parent: r)); - }, - ), 'config': Property( getValue: (CT_ c) => c.config, renderVariable: (CT_ c, Property self, @@ -9476,8 +9531,8 @@ class _Renderer_ModelElement extends RendererBase { parent: r); }, ), - 'documentationAsHtml': Property( - getValue: (CT_ c) => c.documentationAsHtml, + 'documentationComment': Property( + getValue: (CT_ c) => c.documentationComment, renderVariable: (CT_ c, Property self, List remainingNames) { if (remainingNames.isEmpty) { @@ -9489,26 +9544,14 @@ class _Renderer_ModelElement extends RendererBase { return nextProperty.renderVariable(self.getValue(c), nextProperty, [...remainingNames.skip(1)]); }, - isNullValue: (CT_ c) => c.documentationAsHtml == null, + isNullValue: (CT_ c) => c.documentationComment == null, renderValue: (CT_ c, RendererBase r, List ast, StringSink sink) { - _render_String(c.documentationAsHtml, ast, r.template, sink, + _render_String( + c.documentationComment, ast, r.template, sink, parent: r); }, ), - 'documentationFrom': Property( - getValue: (CT_ c) => c.documentationFrom, - renderVariable: (CT_ c, Property self, - List remainingNames) => - self.renderSimpleVariable( - c, remainingNames, 'List'), - renderIterable: (CT_ c, RendererBase r, - List ast, StringSink sink) { - return c.documentationFrom.map((e) => _render_ModelElement( - e, ast, r.template, sink, - parent: r)); - }, - ), 'element': Property( getValue: (CT_ c) => c.element, renderVariable: (CT_ c, Property self, @@ -15207,6 +15250,27 @@ const _invisibleGetters = { 'useBaseHref' }, 'DocumentLocation': {'hashCode', 'runtimeType', 'index'}, + 'Documentation': { + 'hashCode', + 'runtimeType', + 'hasExtendedDocs', + 'asHtml', + 'asOneLiner', + 'commentRefs' + }, + 'DocumentationComment': { + 'documentationFrom', + 'documentationAsHtml', + 'elementDocumentation', + 'documentationComment', + 'hasNodoc', + 'sourceFileName', + 'fullyQualifiedNameWithoutLibrary', + 'pathContext', + 'modelElementRenderer', + 'documentationLocal', + 'needsPrecache' + }, 'Element': { 'hashCode', 'runtimeType', @@ -15415,7 +15479,7 @@ const _invisibleGetters = { 'hasAccessorsWithDocs', 'getterSetterBothAvailable', 'oneLineDoc', - 'getterSetterDocumentationComment', + 'documentationComment', 'modelType', 'isCallable', 'hasParameters', diff --git a/lib/src/model/accessor.dart b/lib/src/model/accessor.dart index 6a926eb72b..e3296ec22e 100644 --- a/lib/src/model/accessor.dart +++ b/lib/src/model/accessor.dart @@ -72,24 +72,29 @@ class Accessor extends ModelElement implements EnclosedElement { return _sourceCode; } + bool _documentationCommentComputed = false; + String _documentationComment; @override - String computeDocumentationComment() { - if (isSynthetic) { - // If we're a setter, only display something if we have something different than the getter. - // TODO(jcollins-g): modify analyzer to do this itself? - if (isGetter || - definingCombo.hasNodoc || - (isSetter && - definingCombo.hasGetter && - definingCombo.getter.documentationComment != - definingCombo.documentationComment)) { - return stripComments(definingCombo.documentationComment); - } else { - return ''; - } - } - return stripComments(super.computeDocumentationComment()); - } + String get documentationComment => _documentationCommentComputed + ? _documentationComment + : _documentationComment ??= () { + _documentationCommentComputed = true; + if (isSynthetic) { + // If we're a setter, only display something if we have something different than the getter. + // TODO(jcollins-g): modify analyzer to do this itself? + if (isGetter || + definingCombo.hasNodoc || + (isSetter && + definingCombo.hasGetter && + definingCombo.getter.documentationComment != + definingCombo.documentationComment)) { + return stripComments(definingCombo.documentationComment); + } else { + return ''; + } + } + return stripComments(super.documentationComment); + }(); @override void warn(PackageWarning kind, diff --git a/lib/src/model/container_member.dart b/lib/src/model/container_member.dart index 1898bc0ba0..e6ad58d012 100644 --- a/lib/src/model/container_member.dart +++ b/lib/src/model/container_member.dart @@ -73,7 +73,7 @@ mixin ContainerMember on ModelElement implements EnclosedElement { // TODO(jcollins-g): split Field documentation up between accessors // and resolve the pieces with different scopes. dart-lang/dartdoc#2693. // Until then, just pretend we're handling this correctly. - yield documentationFrom.first.definingLibrary; + yield (documentationFrom.first as ModelElement).definingLibrary; // TODO(jcollins-g): Wean users off of depending on canonical library // resolution. dart-lang/dartdoc#2696 if (canonicalLibrary != null) yield canonicalLibrary; diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 405804dc3f..ad59825147 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -1,7 +1,10 @@ import 'package:args/args.dart'; import 'package:crypto/crypto.dart' as crypto; import 'package:dartdoc/src/model/documentable.dart'; +import 'package:dartdoc/src/model/documentation.dart'; +import 'package:dartdoc/src/model/inheritable.dart'; import 'package:dartdoc/src/model/locatable.dart'; +import 'package:dartdoc/src/model/model_element.dart'; import 'package:dartdoc/src/model/source_code_mixin.dart'; import 'package:dartdoc/src/render/model_element_renderer.dart'; import 'package:dartdoc/src/utils.dart'; @@ -37,23 +40,48 @@ final RegExp _needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); /// entrypoints. mixin DocumentationComment on Documentable, Warnable, Locatable, SourceCodeMixin { - /// The documentation comment on the Element may be null, so memoization - /// cannot rely on the null-ness of [_documentationComment], it must be - /// more explicit. - bool _documentationCommentComputed = false; - String _documentationComment; - - String get documentationComment { - if (_documentationCommentComputed == false) { - _documentationComment = computeDocumentationComment(); - _documentationCommentComputed = true; - } - return _documentationComment; + List _documentationFrom; + + /// Returns the ModelElement(s) from which we will get documentation. + /// Can be more than one if this is a Field composing documentation from + /// multiple Accessors. + /// + /// This getter will walk up the inheritance hierarchy + /// to find docs, if the current class doesn't have docs + /// for this element. + @override + List get documentationFrom => + _documentationFrom ??= () { + if (documentationComment == null && + this is Inheritable && + (this as Inheritable).overriddenElement != null) { + return (this as Inheritable).overriddenElement.documentationFrom; + } else if (this is Inheritable && (this as Inheritable).isInherited) { + var thisInheritable = (this as Inheritable); + var fromThis = ModelElement.fromElement( + element, thisInheritable.definingEnclosingContainer.packageGraph); + return fromThis.documentationFrom; + } else { + return [this]; + } + }(); + + String _documentationAsHtml; + @override + String get documentationAsHtml { + if (_documentationAsHtml != null) return _documentationAsHtml; + _documentationAsHtml = _injectHtmlFragments(elementDocumentation.asHtml); + return _documentationAsHtml; + } + + Documentation _elementDocumentation; + Documentation get elementDocumentation { + if (_elementDocumentation != null) return _elementDocumentation; + _elementDocumentation = Documentation.forElement(this); + return _elementDocumentation; } - /// Implement to derive the raw documentation comment string from the - /// analyzer. - String computeDocumentationComment(); + String get documentationComment; /// Returns true if the raw documentation comment has a nodoc indication. bool get hasNodoc { @@ -809,7 +837,7 @@ mixin DocumentationComment /// /// And the HTML fragment will not have been processed or changed by Markdown, /// but just injected verbatim. - String injectHtmlFragments(String rawDocs) { + String _injectHtmlFragments(String rawDocs) { if (!config.injectHtml) return rawDocs; return rawDocs.replaceAllMapped(_htmlInjectRegExp, (match) { diff --git a/lib/src/model/enum.dart b/lib/src/model/enum.dart index 8423136c2c..b5ebb310b0 100644 --- a/lib/src/model/enum.dart +++ b/lib/src/model/enum.dart @@ -54,7 +54,7 @@ class EnumField extends Field { String get constantValueBase => _fieldRenderer.renderValue(this); @override - List get documentationFrom { + List get documentationFrom { if (name == 'values' || name == 'index') return [this]; return super.documentationFrom; } diff --git a/lib/src/model/field.dart b/lib/src/model/field.dart index 115a56d2ac..3c63c15fdb 100644 --- a/lib/src/model/field.dart +++ b/lib/src/model/field.dart @@ -136,13 +136,6 @@ class Field extends ModelElement return allFeatures; } - @override - String computeDocumentationComment() { - var docs = getterSetterDocumentationComment; - if (docs.isEmpty) return field.documentationComment; - return docs; - } - FieldElement get field => (element as FieldElement); @override diff --git a/lib/src/model/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart index 134cd6c045..5074f34382 100644 --- a/lib/src/model/getter_setter_combo.dart +++ b/lib/src/model/getter_setter_combo.dart @@ -109,10 +109,10 @@ mixin GetterSetterCombo on ModelElement { @override bool get isPublic => hasPublicGetter || hasPublicSetter; - List _documentationFrom; + List _documentationFrom; @override - List get documentationFrom { + List get documentationFrom { if (_documentationFrom == null) { _documentationFrom = []; if (hasPublicGetter) { @@ -122,7 +122,7 @@ mixin GetterSetterCombo on ModelElement { } if (_documentationFrom.isEmpty || _documentationFrom.every((e) => e.documentationComment == '')) { - _documentationFrom = computeDocumentationFrom; + _documentationFrom = super.documentationFrom; } } return _documentationFrom; @@ -158,7 +158,20 @@ mixin GetterSetterCombo on ModelElement { return _oneLineDoc; } - String get getterSetterDocumentationComment { + bool _documentationCommentComputed = false; + String _documentationComment; + @override + String get documentationComment => _documentationCommentComputed + ? _documentationComment + : _documentationComment ??= () { + _documentationCommentComputed = true; + var docs = _getterSetterDocumentationComment; + if (docs.isEmpty) return element.documentationComment; + return docs; + }(); + + /// Derive a synthetic documentation comment using the documentation from + String get _getterSetterDocumentationComment { var buffer = StringBuffer(); // Check for synthetic before public, always, or stack overflow. diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 6eaa00a4b6..398427610d 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -104,7 +104,6 @@ abstract class ModelElement extends Canonicalization final Member /*?*/ _originalMember; final Library /*?*/ _library; - Documentation __documentation; UnmodifiableListView _parameters; String _linkedName; @@ -491,15 +490,6 @@ abstract class ModelElement extends Canonicalization ModelElement get canonicalModelElement => _canonicalModelElement ??= buildCanonicalModelElement(); - List _documentationFrom; - - // TODO(jcollins-g): untangle when mixins can call super - @override - List get documentationFrom { - _documentationFrom ??= computeDocumentationFrom; - return _documentationFrom; - } - bool get hasSourceHref => sourceHref.isNotEmpty; String _sourceHref; @@ -508,29 +498,6 @@ abstract class ModelElement extends Canonicalization return _sourceHref; } - /// Returns the ModelElement(s) from which we will get documentation. - /// Can be more than one if this is a Field composing documentation from - /// multiple Accessors. - /// - /// This getter will walk up the inheritance hierarchy - /// to find docs, if the current class doesn't have docs - /// for this element. - List get computeDocumentationFrom { - if (documentationComment == null && - _canOverride && - this is Inheritable && - (this as Inheritable).overriddenElement != null) { - return (this as Inheritable).overriddenElement.documentationFrom; - } else if (this is Inheritable && (this as Inheritable).isInherited) { - var thisInheritable = (this as Inheritable); - var fromThis = ModelElement.fromElement( - element, thisInheritable.definingEnclosingContainer.packageGraph); - return fromThis.documentationFrom; - } else { - return [this]; - } - } - Library get definingLibrary { var library = packageGraph.findButDoNotCreateLibraryFor(element); if (library == null) { @@ -674,14 +641,6 @@ abstract class ModelElement extends Canonicalization documentationFrom.map((e) => e.documentationLocal).join('

')); } - String _documentationAsHtml; - @override - String get documentationAsHtml { - if (_documentationAsHtml != null) return _documentationAsHtml; - _documentationAsHtml = injectHtmlFragments(_elementDocumentation.asHtml); - return _documentationAsHtml; - } - @override Element get element => _element; @@ -762,7 +721,7 @@ abstract class ModelElement extends Canonicalization @override bool get hasExtendedDocumentation => - href != null && _elementDocumentation.hasExtendedDocs; + href != null && elementDocumentation.hasExtendedDocs; bool get hasParameters => parameters.isNotEmpty; @@ -867,7 +826,7 @@ abstract class ModelElement extends Canonicalization String get name => _name ??= element.name; @override - String get oneLineDoc => _elementDocumentation.asOneLiner; + String get oneLineDoc => elementDocumentation.asOneLiner; Member get originalMember => _originalMember; @@ -958,25 +917,15 @@ abstract class ModelElement extends Canonicalization } @override - String computeDocumentationComment() => element.documentationComment; - - Documentation get _elementDocumentation { - if (__documentation != null) return __documentation; - __documentation = Documentation.forElement(this); - return __documentation; - } + String get documentationComment => element.documentationComment; String _sourceCode; - @override String get sourceCode { return _sourceCode ??= _sourceCodeRenderer.renderSourceCode(super.sourceCode); } - bool get _canOverride => - element is ClassMemberElement || element is PropertyAccessorElement; - @override int compareTo(dynamic other) { if (other is ModelElement) { diff --git a/lib/src/model/top_level_variable.dart b/lib/src/model/top_level_variable.dart index 3046a60b77..801bead338 100644 --- a/lib/src/model/top_level_variable.dart +++ b/lib/src/model/top_level_variable.dart @@ -77,13 +77,6 @@ class TopLevelVariable extends ModelElement @override Set get features => {...super.features, ...comboFeatures}; - @override - String computeDocumentationComment() { - var docs = getterSetterDocumentationComment; - if (docs.isEmpty) return _variable.documentationComment; - return docs; - } - @override String get fileName => '${isConst ? '$name-constant' : name}.$fileType';