From c867d5f1008e4bfec0f84aa0b8ca0f10c7c00014 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 28 Sep 2021 16:35:18 -0700 Subject: [PATCH 01/15] Straight move --- lib/src/model/built_documentation.dart | 61 ++++++++++++++++++++++++ lib/src/model/documentation_comment.dart | 61 +++++++++++++++++++++++- lib/src/model/model.dart | 2 +- lib/src/model/model_element.dart | 55 +-------------------- 4 files changed, 123 insertions(+), 56 deletions(-) create mode 100644 lib/src/model/built_documentation.dart diff --git a/lib/src/model/built_documentation.dart b/lib/src/model/built_documentation.dart new file mode 100644 index 0000000000..6e0b402ee1 --- /dev/null +++ b/lib/src/model/built_documentation.dart @@ -0,0 +1,61 @@ +// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file +// 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:dartdoc/src/model/documentation_comment.dart'; +import 'package:dartdoc/src/model/model_element.dart'; +import 'package:dartdoc/src/utils.dart'; +/* +final RegExp _needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); + +class BuiltDocumentation { + + final DocumentationComment modelElement; + + BuiltDocumentation(this.modelElement); + + @deprecated + String buildDocumentationAddition(String docs) => docs ??= ''; + + String _rawDocs; + String _documentationLocal; + /// Returns the documentation for this literal element unless + /// [config.dropTextFrom] indicates it should not be returned. Macro + /// definitions are stripped, but macros themselves are not injected. This + /// is a two stage process to avoid ordering problems. + String get documentationLocal => _documentationLocal ??= () { + assert(_rawDocs == null, + 'reentrant calls to _buildDocumentation* not allowed'); + // Do not use the sync method if we need to evaluate tools or templates. + assert(!modelElement.isCanonical || + !_needsPrecacheRegExp.hasMatch(modelElement.documentationComment ?? '')); + if (modelElement.config.dropTextFrom.contains(modelElement.element.library.name)) { + _rawDocs = ''; + } else { + _rawDocs = _processCommentWithoutTools(modelElement.documentationComment ?? ''); + } + _rawDocs = buildDocumentationAddition(_rawDocs); + return _rawDocs; + } (); + + /// Process a [documentationComment], performing various actions based on + /// `{@}`-style directives, except `{@tool}`, returning the processed result. + String _processCommentWithoutTools(String documentationComment) { + var docs = stripComments(documentationComment); + if (!docs.contains('{@')) { + _analyzeCodeBlocks(docs); + return docs; + } + docs = _injectExamples(docs); + docs = _injectYouTube(docs); + docs = _injectAnimations(docs); + + _analyzeCodeBlocks(docs); + + // TODO(srawlins): Processing templates here causes #2281. But leaving them + // unprocessed causes #2272. + docs = _stripHtmlAndAddToIndex(docs); + return docs; + } +} +*/ diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 1422cc8f5b..4582ac618e 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -1,6 +1,8 @@ import 'package:args/args.dart'; import 'package:crypto/crypto.dart' as crypto; -import 'package:dartdoc/src/model/model.dart'; +import 'package:dartdoc/src/model/documentable.dart'; +import 'package:dartdoc/src/model/locatable.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'; import 'package:dartdoc/src/warnings.dart'; @@ -23,6 +25,8 @@ final _basicToolPattern = RegExp( final _examplePattern = RegExp(r'{@example\s+([^}]+)}'); +final RegExp needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); + /// Features for processing directives in a documentation comment. /// /// [processCommentWithoutTools] and [processComment] are the primary @@ -707,4 +711,59 @@ mixin DocumentationComment } }); } + + /// Returns the documentation for this literal element unless + /// [config.dropTextFrom] indicates it should not be returned. Macro + /// definitions are stripped, but macros themselves are not injected. This + /// is a two stage process to avoid ordering problems. + String _documentationLocal; + + String get documentationLocal => + _documentationLocal ??= _buildDocumentationLocal(); + + /// Unconditionally precache local documentation. + /// + /// Use only in factory for [PackageGraph]. + Future precacheLocalDocs() async { + _documentationLocal = await _buildDocumentationBase(); + } + + String _rawDocs; + + String _buildDocumentationLocal() => _buildDocumentationBaseSync(); + + /// Override this to add more features to the documentation builder in a + /// subclass. + String buildDocumentationAddition(String docs) => docs ??= ''; + + /// Separate from _buildDocumentationLocal for overriding. + String _buildDocumentationBaseSync() { + assert(_rawDocs == null, + 'reentrant calls to _buildDocumentation* not allowed'); + // Do not use the sync method if we need to evaluate tools or templates. + assert(!isCanonical || + !needsPrecacheRegExp.hasMatch(documentationComment ?? '')); + if (config.dropTextFrom.contains(element.library.name)) { + _rawDocs = ''; + } else { + _rawDocs = processCommentWithoutTools(documentationComment ?? ''); + } + _rawDocs = buildDocumentationAddition(_rawDocs); + return _rawDocs; + } + + /// Separate from _buildDocumentationLocal for overriding. Can only be + /// used as part of [PackageGraph.setUpPackageGraph]. + Future _buildDocumentationBase() async { + assert(_rawDocs == null, + 'reentrant calls to _buildDocumentation* not allowed'); + // Do not use the sync method if we need to evaluate tools or templates. + if (config.dropTextFrom.contains(element.library.name)) { + _rawDocs = ''; + } else { + _rawDocs = await processComment(documentationComment ?? ''); + } + _rawDocs = buildDocumentationAddition(_rawDocs); + return _rawDocs; + } } diff --git a/lib/src/model/model.dart b/lib/src/model/model.dart index a6d40f3d2f..694dc1fbe1 100644 --- a/lib/src/model/model.dart +++ b/lib/src/model/model.dart @@ -28,7 +28,7 @@ export 'library_container.dart'; export 'locatable.dart'; export 'method.dart'; export 'mixin.dart'; -export 'model_element.dart'; +export 'model_element.dart' hide needsPrecacheRegExp; export 'model_function.dart'; export 'model_node.dart'; export 'nameable.dart'; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 9d834dd151..a905ea32a5 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -36,6 +36,7 @@ import 'package:path/path.dart' as path show Context; /// This doc may need to be processed in case it has a template or html /// fragment. +@Deprecated('Use version in documentation_comment.dart.') final RegExp needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); final _htmlInjectRegExp = RegExp(r'([a-f0-9]+)'); @@ -118,7 +119,6 @@ abstract class ModelElement extends Canonicalization final Member /*?*/ _originalMember; final Library /*?*/ _library; - String _rawDocs; Documentation __documentation; UnmodifiableListView _parameters; String _linkedName; @@ -546,52 +546,6 @@ abstract class ModelElement extends Canonicalization } } - String _buildDocumentationLocal() => _buildDocumentationBaseSync(); - - /// Override this to add more features to the documentation builder in a - /// subclass. - String buildDocumentationAddition(String docs) => docs ??= ''; - - /// Separate from _buildDocumentationLocal for overriding. - String _buildDocumentationBaseSync() { - assert(_rawDocs == null, - 'reentrant calls to _buildDocumentation* not allowed'); - // Do not use the sync method if we need to evaluate tools or templates. - assert(!isCanonical || - !needsPrecacheRegExp.hasMatch(documentationComment ?? '')); - if (config.dropTextFrom.contains(element.library.name)) { - _rawDocs = ''; - } else { - _rawDocs = processCommentWithoutTools(documentationComment ?? ''); - } - _rawDocs = buildDocumentationAddition(_rawDocs); - return _rawDocs; - } - - /// Separate from _buildDocumentationLocal for overriding. Can only be - /// used as part of [PackageGraph.setUpPackageGraph]. - Future _buildDocumentationBase() async { - assert(_rawDocs == null, - 'reentrant calls to _buildDocumentation* not allowed'); - // Do not use the sync method if we need to evaluate tools or templates. - if (config.dropTextFrom.contains(element.library.name)) { - _rawDocs = ''; - } else { - _rawDocs = await processComment(documentationComment ?? ''); - } - _rawDocs = buildDocumentationAddition(_rawDocs); - return _rawDocs; - } - - /// Returns the documentation for this literal element unless - /// [config.dropTextFrom] indicates it should not be returned. Macro - /// definitions are stripped, but macros themselves are not injected. This - /// is a two stage process to avoid ordering problems. - String _documentationLocal; - - String get documentationLocal => - _documentationLocal ??= _buildDocumentationLocal(); - /// Returns the docs, stripped of their leading comments syntax. @override String get documentation { @@ -1022,13 +976,6 @@ abstract class ModelElement extends Canonicalization @override String computeDocumentationComment() => element.documentationComment; - /// Unconditionally precache local documentation. - /// - /// Use only in factory for [PackageGraph]. - Future precacheLocalDocs() async { - _documentationLocal = await _buildDocumentationBase(); - } - Documentation get _documentation { if (__documentation != null) return __documentation; __documentation = Documentation.forElement(this); From 08b4b6cf3b71f4661728eb940ee3f7d246a8353c Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Tue, 28 Sep 2021 17:09:32 -0700 Subject: [PATCH 02/15] Partial --- lib/src/model/documentation_comment.dart | 103 +++++++++++++++++-- lib/src/model/model.dart | 2 +- lib/src/model/model_element.dart | 125 +++-------------------- lib/src/model/package_graph.dart | 3 +- 4 files changed, 112 insertions(+), 121 deletions(-) diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 4582ac618e..6806106a86 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -25,11 +25,15 @@ final _basicToolPattern = RegExp( final _examplePattern = RegExp(r'{@example\s+([^}]+)}'); -final RegExp needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); +final _macroRegExp = RegExp(r'{@macro\s+([^}]+)}'); + +final _htmlInjectRegExp = RegExp(r'([a-f0-9]+)'); + +final RegExp _needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); /// Features for processing directives in a documentation comment. /// -/// [processCommentWithoutTools] and [processComment] are the primary +/// [_processCommentWithoutTools] and [processComment] are the primary /// entrypoints. mixin DocumentationComment on Documentable, Warnable, Locatable, SourceCodeMixin { @@ -63,7 +67,7 @@ mixin DocumentationComment /// Process a [documentationComment], performing various actions based on /// `{@}`-style directives, except `{@tool}`, returning the processed result. - String processCommentWithoutTools(String documentationComment) { + String _processCommentWithoutTools(String documentationComment) { var docs = stripComments(documentationComment); if (!docs.contains('{@')) { _analyzeCodeBlocks(docs); @@ -83,6 +87,7 @@ mixin DocumentationComment /// Process [documentationComment], performing various actions based on /// `{@}`-style directives, returning the processed result. + @visibleForTesting Future processComment(String documentationComment) async { var docs = stripComments(documentationComment); // Must evaluate tools first, in case they insert any other directives. @@ -728,6 +733,10 @@ mixin DocumentationComment _documentationLocal = await _buildDocumentationBase(); } + bool _needsPrecache; + bool get needsPrecache => _needsPrecache ??= + _needsPrecacheRegExp.hasMatch(documentationComment ?? ''); + String _rawDocs; String _buildDocumentationLocal() => _buildDocumentationBaseSync(); @@ -741,12 +750,11 @@ mixin DocumentationComment assert(_rawDocs == null, 'reentrant calls to _buildDocumentation* not allowed'); // Do not use the sync method if we need to evaluate tools or templates. - assert(!isCanonical || - !needsPrecacheRegExp.hasMatch(documentationComment ?? '')); + assert(!isCanonical || !needsPrecache); if (config.dropTextFrom.contains(element.library.name)) { _rawDocs = ''; } else { - _rawDocs = processCommentWithoutTools(documentationComment ?? ''); + _rawDocs = _processCommentWithoutTools(documentationComment ?? ''); } _rawDocs = buildDocumentationAddition(_rawDocs); return _rawDocs; @@ -766,4 +774,87 @@ mixin DocumentationComment _rawDocs = buildDocumentationAddition(_rawDocs); return _rawDocs; } + + /// Replace <[digest]> in API comments with + /// the contents of the HTML fragment earlier defined by the + /// {@inject-html} directive. The [digest] is a SHA1 of the contents + /// of the HTML fragment, automatically generated upon parsing the + /// {@inject-html} directive. + /// + /// This markup is generated and inserted by [_stripHtmlAndAddToIndex] when it + /// removes the HTML fragment in preparation for markdown processing. It isn't + /// meant to be used at a user level. + /// + /// Example: + /// + /// You place the fragment in a dartdoc comment: + /// + /// Some comments + /// {@inject-html} + /// <p>[HTML contents!]</p> + /// {@endtemplate} + /// More comments + /// + /// and [_stripHtmlAndAddToIndex] will replace your HTML fragment with this: + /// + /// Some comments + /// <dartdoc-html>4cc02f877240bf69855b4c7291aba8a16e5acce0</dartdoc-html> + /// More comments + /// + /// Which will render in the final HTML output as: + /// + /// Some comments + /// <p>[HTML contents!]</p> + /// More comments + /// + /// And the HTML fragment will not have been processed or changed by Markdown, + /// but just injected verbatim. + String injectHtmlFragments(String rawDocs) { + if (!config.injectHtml) return rawDocs; + + return rawDocs.replaceAllMapped(_htmlInjectRegExp, (match) { + var fragment = packageGraph.getHtmlFragment(match[1]); + if (fragment == null) { + warn(PackageWarning.unknownHtmlFragment, message: match[1]); + } + return fragment; + }); + } + + /// Replace {@macro ...} in API comments with the contents of the macro + /// + /// Syntax: + /// + /// {@macro NAME} + /// + /// Example: + /// + /// You define the template in any comment for a documentable entity like: + /// + /// {@template foo} + /// Foo contents! + /// {@endtemplate} + /// + /// and them somewhere use it like this: + /// + /// Some comments + /// {@macro foo} + /// More comments + /// + /// Which will render + /// + /// Some comments + /// Foo contents! + /// More comments + /// + String injectMacros(String rawDocs) { + return rawDocs.replaceAllMapped(_macroRegExp, (match) { + var macro = packageGraph.getMacro(match[1]); + if (macro == null) { + warn(PackageWarning.unknownMacro, message: match[1]); + } + macro = processCommentDirectives(macro ?? ''); + return macro; + }); + } } diff --git a/lib/src/model/model.dart b/lib/src/model/model.dart index 694dc1fbe1..a6d40f3d2f 100644 --- a/lib/src/model/model.dart +++ b/lib/src/model/model.dart @@ -28,7 +28,7 @@ export 'library_container.dart'; export 'locatable.dart'; export 'method.dart'; export 'mixin.dart'; -export 'model_element.dart' hide needsPrecacheRegExp; +export 'model_element.dart'; export 'model_function.dart'; export 'model_node.dart'; export 'nameable.dart'; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index a905ea32a5..6eaa00a4b6 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -34,21 +34,6 @@ import 'package:dartdoc/src/warnings.dart'; import 'package:meta/meta.dart'; import 'package:path/path.dart' as path show Context; -/// This doc may need to be processed in case it has a template or html -/// fragment. -@Deprecated('Use version in documentation_comment.dart.') -final RegExp needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); - -final _htmlInjectRegExp = RegExp(r'([a-f0-9]+)'); -@Deprecated('Public variable intended to be private; will be removed as early ' - 'as Dartdoc 1.0.0') -RegExp get htmlInjectRegExp => _htmlInjectRegExp; - -final _macroRegExp = RegExp(r'{@macro\s+([^}]+)}'); -@Deprecated('Public variable intended to be private; will be removed as early ' - 'as Dartdoc 1.0.0') -RegExp get macroRegExp => _macroRegExp; - // TODO(jcollins-g): Implement resolution per ECMA-408 4th edition, page 39 #22. /// Resolves this very rare case incorrectly by picking the closest element in /// the inheritance and interface chains from the analyzer. @@ -546,13 +531,6 @@ abstract class ModelElement extends Canonicalization } } - /// Returns the docs, stripped of their leading comments syntax. - @override - String get documentation { - return _injectMacros( - documentationFrom.map((e) => e.documentationLocal).join('

')); - } - Library get definingLibrary { var library = packageGraph.findButDoNotCreateLibraryFor(element); if (library == null) { @@ -689,13 +667,19 @@ abstract class ModelElement extends Canonicalization return i.enclosingElement == i.canonicalEnclosingContainer; } - String _htmlDocumentation; + /// Returns the docs, stripped of their leading comments syntax. + @override + String get documentation { + return injectMacros( + documentationFrom.map((e) => e.documentationLocal).join('

')); + } + String _documentationAsHtml; @override String get documentationAsHtml { - if (_htmlDocumentation != null) return _htmlDocumentation; - _htmlDocumentation = _injectHtmlFragments(_documentation.asHtml); - return _htmlDocumentation; + if (_documentationAsHtml != null) return _documentationAsHtml; + _documentationAsHtml = injectHtmlFragments(_elementDocumentation.asHtml); + return _documentationAsHtml; } @override @@ -778,7 +762,7 @@ abstract class ModelElement extends Canonicalization @override bool get hasExtendedDocumentation => - href != null && _documentation.hasExtendedDocs; + href != null && _elementDocumentation.hasExtendedDocs; bool get hasParameters => parameters.isNotEmpty; @@ -883,7 +867,7 @@ abstract class ModelElement extends Canonicalization String get name => _name ??= element.name; @override - String get oneLineDoc => _documentation.asOneLiner; + String get oneLineDoc => _elementDocumentation.asOneLiner; Member get originalMember => _originalMember; @@ -976,7 +960,7 @@ abstract class ModelElement extends Canonicalization @override String computeDocumentationComment() => element.documentationComment; - Documentation get _documentation { + Documentation get _elementDocumentation { if (__documentation != null) return __documentation; __documentation = Documentation.forElement(this); return __documentation; @@ -1034,87 +1018,4 @@ abstract class ModelElement extends Canonicalization return modelElementRenderer.renderLinkedName(this); } - - /// Replace <[digest]> in API comments with - /// the contents of the HTML fragment earlier defined by the - /// {@inject-html} directive. The [digest] is a SHA1 of the contents - /// of the HTML fragment, automatically generated upon parsing the - /// {@inject-html} directive. - /// - /// This markup is generated and inserted by [_stripHtmlAndAddToIndex] when it - /// removes the HTML fragment in preparation for markdown processing. It isn't - /// meant to be used at a user level. - /// - /// Example: - /// - /// You place the fragment in a dartdoc comment: - /// - /// Some comments - /// {@inject-html} - /// <p>[HTML contents!]</p> - /// {@endtemplate} - /// More comments - /// - /// and [_stripHtmlAndAddToIndex] will replace your HTML fragment with this: - /// - /// Some comments - /// <dartdoc-html>4cc02f877240bf69855b4c7291aba8a16e5acce0</dartdoc-html> - /// More comments - /// - /// Which will render in the final HTML output as: - /// - /// Some comments - /// <p>[HTML contents!]</p> - /// More comments - /// - /// And the HTML fragment will not have been processed or changed by Markdown, - /// but just injected verbatim. - String _injectHtmlFragments(String rawDocs) { - if (!config.injectHtml) return rawDocs; - - return rawDocs.replaceAllMapped(_htmlInjectRegExp, (match) { - var fragment = packageGraph.getHtmlFragment(match[1]); - if (fragment == null) { - warn(PackageWarning.unknownHtmlFragment, message: match[1]); - } - return fragment; - }); - } - - /// Replace {@macro ...} in API comments with the contents of the macro - /// - /// Syntax: - /// - /// {@macro NAME} - /// - /// Example: - /// - /// You define the template in any comment for a documentable entity like: - /// - /// {@template foo} - /// Foo contents! - /// {@endtemplate} - /// - /// and them somewhere use it like this: - /// - /// Some comments - /// {@macro foo} - /// More comments - /// - /// Which will render - /// - /// Some comments - /// Foo contents! - /// More comments - /// - String _injectMacros(String rawDocs) { - return rawDocs.replaceAllMapped(_macroRegExp, (match) { - var macro = packageGraph.getMacro(match[1]); - if (macro == null) { - warn(PackageWarning.unknownMacro, message: match[1]); - } - macro = processCommentDirectives(macro ?? ''); - return macro; - }); - } } diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index 07b26ef911..26210a2d7d 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -135,8 +135,7 @@ class PackageGraph with CommentReferable, Nameable { Iterable> precacheOneElement(ModelElement m) sync* { for (var d in m.documentationFrom.where((d) => d.documentationComment != null)) { - if (needsPrecacheRegExp.hasMatch(d.documentationComment) && - !precachedElements.contains(d)) { + if (d.needsPrecache && !precachedElements.contains(d)) { precachedElements.add(d); yield d.precacheLocalDocs(); logProgress(d.name); From 0a975cddbf2e0bd260c8a806181cd7e43d7f7596 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 29 Sep 2021 12:55:32 -0700 Subject: [PATCH 03/15] delete experiment --- lib/src/model/built_documentation.dart | 61 -------------------------- 1 file changed, 61 deletions(-) delete mode 100644 lib/src/model/built_documentation.dart diff --git a/lib/src/model/built_documentation.dart b/lib/src/model/built_documentation.dart deleted file mode 100644 index 6e0b402ee1..0000000000 --- a/lib/src/model/built_documentation.dart +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file -// 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:dartdoc/src/model/documentation_comment.dart'; -import 'package:dartdoc/src/model/model_element.dart'; -import 'package:dartdoc/src/utils.dart'; -/* -final RegExp _needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); - -class BuiltDocumentation { - - final DocumentationComment modelElement; - - BuiltDocumentation(this.modelElement); - - @deprecated - String buildDocumentationAddition(String docs) => docs ??= ''; - - String _rawDocs; - String _documentationLocal; - /// Returns the documentation for this literal element unless - /// [config.dropTextFrom] indicates it should not be returned. Macro - /// definitions are stripped, but macros themselves are not injected. This - /// is a two stage process to avoid ordering problems. - String get documentationLocal => _documentationLocal ??= () { - assert(_rawDocs == null, - 'reentrant calls to _buildDocumentation* not allowed'); - // Do not use the sync method if we need to evaluate tools or templates. - assert(!modelElement.isCanonical || - !_needsPrecacheRegExp.hasMatch(modelElement.documentationComment ?? '')); - if (modelElement.config.dropTextFrom.contains(modelElement.element.library.name)) { - _rawDocs = ''; - } else { - _rawDocs = _processCommentWithoutTools(modelElement.documentationComment ?? ''); - } - _rawDocs = buildDocumentationAddition(_rawDocs); - return _rawDocs; - } (); - - /// Process a [documentationComment], performing various actions based on - /// `{@}`-style directives, except `{@tool}`, returning the processed result. - String _processCommentWithoutTools(String documentationComment) { - var docs = stripComments(documentationComment); - if (!docs.contains('{@')) { - _analyzeCodeBlocks(docs); - return docs; - } - docs = _injectExamples(docs); - docs = _injectYouTube(docs); - docs = _injectAnimations(docs); - - _analyzeCodeBlocks(docs); - - // TODO(srawlins): Processing templates here causes #2281. But leaving them - // unprocessed causes #2272. - docs = _stripHtmlAndAddToIndex(docs); - return docs; - } -} -*/ From 61696c7b1ef9abb7fd6c411c02e23a68e3c120f8 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 29 Sep 2021 12:57:37 -0700 Subject: [PATCH 04/15] rebuild --- .../templates.runtime_renderers.dart | 48 +++++++++++-------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index f7fa4d9ad4..5abfcd2d64 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -3928,6 +3928,26 @@ class _Renderer_DocumentationComment parent: r); }, ), + 'documentationLocal': Property( + getValue: (CT_ c) => c.documentationLocal, + 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.documentationLocal == null, + renderValue: (CT_ c, RendererBase r, + List ast, StringSink sink) { + _render_String(c.documentationLocal, ast, r.template, sink, + parent: r); + }, + ), 'fullyQualifiedNameWithoutLibrary': Property( getValue: (CT_ c) => c.fullyQualifiedNameWithoutLibrary, renderVariable: @@ -3971,6 +3991,13 @@ class _Renderer_DocumentationComment getters: _invisibleGetters['ModelElementRenderer']); }, ), + 'needsPrecache': Property( + getValue: (CT_ c) => c.needsPrecache, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.needsPrecache == true, + ), 'pathContext': Property( getValue: (CT_ c) => c.pathContext, renderVariable: (CT_ c, Property self, @@ -4229,6 +4256,7 @@ class _Renderer_Enum extends RendererBase { CT_, () => { ..._Renderer_InheritingContainer.propertyMap(), + ..._Renderer_TypeImplementing.propertyMap(), 'inheritanceChain': Property( getValue: (CT_ c) => c.inheritanceChain, renderVariable: (CT_ c, Property self, @@ -9481,26 +9509,6 @@ class _Renderer_ModelElement extends RendererBase { parent: r)); }, ), - 'documentationLocal': Property( - getValue: (CT_ c) => c.documentationLocal, - 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.documentationLocal == null, - renderValue: (CT_ c, RendererBase r, - List ast, StringSink sink) { - _render_String(c.documentationLocal, ast, r.template, sink, - parent: r); - }, - ), 'element': Property( getValue: (CT_ c) => c.element, renderVariable: (CT_ c, Property self, From eec7326d23ae2980b06376ca5a4b19fb822aeb56 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Wed, 29 Sep 2021 13:17:09 -0700 Subject: [PATCH 05/15] moved computeDocumentationComment and documentationComment --- lib/src/model/accessor.dart | 12 +++++++++--- lib/src/model/documentation_comment.dart | 17 +---------------- lib/src/model/field.dart | 7 +++++-- lib/src/model/model_element.dart | 8 ++++++-- lib/src/model/top_level_variable.dart | 7 +++++-- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/lib/src/model/accessor.dart b/lib/src/model/accessor.dart index 6a926eb72b..498392fc26 100644 --- a/lib/src/model/accessor.dart +++ b/lib/src/model/accessor.dart @@ -72,8 +72,12 @@ class Accessor extends ModelElement implements EnclosedElement { return _sourceCode; } + + bool _documentationCommentComputed = false; + String _documentationComment; @override - String 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? @@ -88,8 +92,10 @@ class Accessor extends ModelElement implements EnclosedElement { return ''; } } - return stripComments(super.computeDocumentationComment()); - } + return stripComments(super.documentationComment); + } (); + + @override void warn(PackageWarning kind, diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 6806106a86..4d68aece67 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -37,23 +37,8 @@ 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; - } - /// 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 { diff --git a/lib/src/model/field.dart b/lib/src/model/field.dart index 115a56d2ac..cc2a7b0267 100644 --- a/lib/src/model/field.dart +++ b/lib/src/model/field.dart @@ -136,12 +136,15 @@ class Field extends ModelElement return allFeatures; } + bool _documentationCommentComputed = false; + String _documentationComment; @override - String computeDocumentationComment() { + String get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { + _documentationCommentComputed = true; var docs = getterSetterDocumentationComment; if (docs.isEmpty) return field.documentationComment; return docs; - } + } (); FieldElement get field => (element as FieldElement); diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 6eaa00a4b6..e9c40372b2 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -957,8 +957,13 @@ abstract class ModelElement extends Canonicalization return _parameters; } + bool _documentationCommentComputed = false; + String _documentationComment; @override - String computeDocumentationComment() => element.documentationComment; + String get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { + _documentationCommentComputed = true; + return element.documentationComment; + } (); Documentation get _elementDocumentation { if (__documentation != null) return __documentation; @@ -967,7 +972,6 @@ abstract class ModelElement extends Canonicalization } String _sourceCode; - @override String get sourceCode { return _sourceCode ??= diff --git a/lib/src/model/top_level_variable.dart b/lib/src/model/top_level_variable.dart index 3046a60b77..fe6e0b851f 100644 --- a/lib/src/model/top_level_variable.dart +++ b/lib/src/model/top_level_variable.dart @@ -77,12 +77,15 @@ class TopLevelVariable extends ModelElement @override Set get features => {...super.features, ...comboFeatures}; + bool _documentationCommentComputed = false; + String _documentationComment; @override - String computeDocumentationComment() { + String get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { + _documentationCommentComputed = true; var docs = getterSetterDocumentationComment; if (docs.isEmpty) return _variable.documentationComment; return docs; - } + } (); @override String get fileName => '${isConst ? '$name-constant' : name}.$fileType'; From 8a1b94cb90faa9b388248c3d0acead6683e06567 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 09:43:13 -0700 Subject: [PATCH 06/15] Move more documentation comment handling --- .../templates.runtime_renderers.dart | 173 ++++++++++++++---- lib/src/model/container_member.dart | 2 +- lib/src/model/documentation_comment.dart | 44 ++++- lib/src/model/enum.dart | 2 +- lib/src/model/getter_setter_combo.dart | 6 +- lib/src/model/model_element.dart | 59 +----- 6 files changed, 192 insertions(+), 94 deletions(-) diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 5abfcd2d64..15558fabc3 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: @@ -5176,6 +5244,27 @@ class _Renderer_Field 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); + }, + ), 'enclosingElement': Property( getValue: (CT_ c) => c.enclosingElement, renderVariable: @@ -5870,12 +5959,13 @@ class _Renderer_GetterSetterCombo extends RendererBase { 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( @@ -9397,19 +9487,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 +9553,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 +9566,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, @@ -13808,6 +13873,27 @@ class _Renderer_TopLevelVariable 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); + }, + ), 'enclosingElement': Property( getValue: (CT_ c) => c.enclosingElement, renderVariable: @@ -15207,6 +15293,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', 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 4d68aece67..aa195bcbd6 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'; @@ -38,6 +41,45 @@ final RegExp _needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); mixin DocumentationComment on Documentable, Warnable, Locatable, SourceCodeMixin { + 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; + } + String get documentationComment; /// Returns true if the raw documentation comment has a nodoc indication. @@ -794,7 +836,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/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart index 134cd6c045..d72d40cff6 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; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index e9c40372b2..ad901a1c98 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -104,7 +104,7 @@ abstract class ModelElement extends Canonicalization final Member /*?*/ _originalMember; final Library /*?*/ _library; - Documentation __documentation; + UnmodifiableListView _parameters; String _linkedName; @@ -491,14 +491,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 +500,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,13 +643,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 +724,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 +829,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; @@ -957,19 +919,8 @@ abstract class ModelElement extends Canonicalization return _parameters; } - bool _documentationCommentComputed = false; - String _documentationComment; @override - String get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { - _documentationCommentComputed = true; - return element.documentationComment; - } (); - - Documentation get _elementDocumentation { - if (__documentation != null) return __documentation; - __documentation = Documentation.forElement(this); - return __documentation; - } + String get documentationComment => element.documentationComment; String _sourceCode; @override @@ -978,8 +929,6 @@ abstract class ModelElement extends Canonicalization _sourceCodeRenderer.renderSourceCode(super.sourceCode); } - bool get _canOverride => - element is ClassMemberElement || element is PropertyAccessorElement; @override int compareTo(dynamic other) { From 41e1fde1e9a24e98fc40a6202139b3dae434c982 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 09:55:19 -0700 Subject: [PATCH 07/15] remove ??= from a cut and paste --- lib/src/model/documentation_comment.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 6806106a86..405804dc3f 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -743,7 +743,7 @@ mixin DocumentationComment /// Override this to add more features to the documentation builder in a /// subclass. - String buildDocumentationAddition(String docs) => docs ??= ''; + String buildDocumentationAddition(String docs) => docs ?? ''; /// Separate from _buildDocumentationLocal for overriding. String _buildDocumentationBaseSync() { From fc1c37b83ce9cee21af3592d930ceaa2d6e01f5d Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 11:04:51 -0700 Subject: [PATCH 08/15] Documentation comment move for combos --- .../templates.runtime_renderers.dart | 87 +++++-------------- lib/src/model/accessor.dart | 41 +++++---- lib/src/model/documentation_comment.dart | 31 +++---- lib/src/model/field.dart | 10 --- lib/src/model/getter_setter_combo.dart | 15 +++- lib/src/model/model_element.dart | 4 - lib/src/model/top_level_variable.dart | 10 --- 7 files changed, 72 insertions(+), 126 deletions(-) diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 15558fabc3..2b1240781b 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -5244,27 +5244,6 @@ class _Renderer_Field 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); - }, - ), 'enclosingElement': Property( getValue: (CT_ c) => c.enclosingElement, renderVariable: @@ -5954,6 +5933,27 @@ 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, @@ -6016,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, @@ -13873,27 +13851,6 @@ class _Renderer_TopLevelVariable 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); - }, - ), 'enclosingElement': Property( getValue: (CT_ c) => c.enclosingElement, renderVariable: @@ -15522,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 498392fc26..e3296ec22e 100644 --- a/lib/src/model/accessor.dart +++ b/lib/src/model/accessor.dart @@ -72,30 +72,29 @@ class Accessor extends ModelElement implements EnclosedElement { return _sourceCode; } - bool _documentationCommentComputed = false; String _documentationComment; @override - 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); - } (); - - + 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/documentation_comment.dart b/lib/src/model/documentation_comment.dart index a7dda1adc0..ad59825147 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -40,8 +40,8 @@ final RegExp _needsPrecacheRegExp = RegExp(r'{@(template|tool|inject-html)'); /// entrypoints. mixin DocumentationComment on Documentable, Warnable, Locatable, SourceCodeMixin { - 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. @@ -50,20 +50,21 @@ mixin DocumentationComment /// 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]; - } - } (); + 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 diff --git a/lib/src/model/field.dart b/lib/src/model/field.dart index cc2a7b0267..3c63c15fdb 100644 --- a/lib/src/model/field.dart +++ b/lib/src/model/field.dart @@ -136,16 +136,6 @@ class Field extends ModelElement return allFeatures; } - bool _documentationCommentComputed = false; - String _documentationComment; - @override - String get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { - _documentationCommentComputed = true; - 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 d72d40cff6..9b78c6bcba 100644 --- a/lib/src/model/getter_setter_combo.dart +++ b/lib/src/model/getter_setter_combo.dart @@ -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 _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 ad901a1c98..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; - UnmodifiableListView _parameters; String _linkedName; @@ -491,7 +490,6 @@ abstract class ModelElement extends Canonicalization ModelElement get canonicalModelElement => _canonicalModelElement ??= buildCanonicalModelElement(); - bool get hasSourceHref => sourceHref.isNotEmpty; String _sourceHref; @@ -643,7 +641,6 @@ abstract class ModelElement extends Canonicalization documentationFrom.map((e) => e.documentationLocal).join('

')); } - @override Element get element => _element; @@ -929,7 +926,6 @@ abstract class ModelElement extends Canonicalization _sourceCodeRenderer.renderSourceCode(super.sourceCode); } - @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 fe6e0b851f..801bead338 100644 --- a/lib/src/model/top_level_variable.dart +++ b/lib/src/model/top_level_variable.dart @@ -77,16 +77,6 @@ class TopLevelVariable extends ModelElement @override Set get features => {...super.features, ...comboFeatures}; - bool _documentationCommentComputed = false; - String _documentationComment; - @override - String get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { - _documentationCommentComputed = true; - var docs = getterSetterDocumentationComment; - if (docs.isEmpty) return _variable.documentationComment; - return docs; - } (); - @override String get fileName => '${isConst ? '$name-constant' : name}.$fileType'; From 97628db4002755595ef69757ab49efdf9b18c9d7 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 11:15:18 -0700 Subject: [PATCH 09/15] better as a getter --- lib/src/model/getter_setter_combo.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/src/model/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart index 9b78c6bcba..5074f34382 100644 --- a/lib/src/model/getter_setter_combo.dart +++ b/lib/src/model/getter_setter_combo.dart @@ -165,13 +165,13 @@ mixin GetterSetterCombo on ModelElement { ? _documentationComment : _documentationComment ??= () { _documentationCommentComputed = true; - var docs = _getterSetterDocumentationComment(); + var docs = _getterSetterDocumentationComment; if (docs.isEmpty) return element.documentationComment; return docs; }(); /// Derive a synthetic documentation comment using the documentation from - String _getterSetterDocumentationComment() { + String get _getterSetterDocumentationComment { var buffer = StringBuffer(); // Check for synthetic before public, always, or stack overflow. From f64ba52fd05631c836ffb0fc48ffaa20058e4ade Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 12:57:03 -0700 Subject: [PATCH 10/15] Untangle synthetic combo documentation in preparing for non-null --- lib/src/model/accessor.dart | 49 ++++++++++++++----- lib/src/model/documentation_comment.dart | 4 ++ lib/src/model/getter_setter_combo.dart | 60 ++++++++++++++---------- lib/src/model/model_element.dart | 3 ++ 4 files changed, 78 insertions(+), 38 deletions(-) diff --git a/lib/src/model/accessor.dart b/lib/src/model/accessor.dart index e3296ec22e..2a80a8f22d 100644 --- a/lib/src/model/accessor.dart +++ b/lib/src/model/accessor.dart @@ -80,22 +80,47 @@ class Accessor extends ModelElement implements EnclosedElement { : _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 _syntheticDocumentationComment; } return stripComments(super.documentationComment); }(); + String __syntheticDocumentationComment; + + /// Build a documentation comment for this accessor assuming it is synthetic. + /// Value here is not useful if [isSynthetic] is false. + String get _syntheticDocumentationComment => + __syntheticDocumentationComment ??= () { + // If we're a setter, and a getter exists, do not add synthetic + // documentation if the combo's documentation is actually derived + // from that getter. + bool _comboDocsAreIndependent() { + if (isSetter && definingCombo.hasGetter) { + if (definingCombo.getter.isSynthetic || + !definingCombo.documentationFrom.contains(this)) { + return true; + } + } + return false; + } + + if ( // If this is a getter, assume we want synthetic documentation. + isGetter || + // If the definingCombo has a nodoc tag, we want synthetic documentation + // for a synthetic accessor just in case it is inherited somewhere + // down the line due to split inheritance. + definingCombo.hasNodoc || + _comboDocsAreIndependent()) { + return definingCombo.documentationComment; + } + return null; + }(); + + @override + bool get hasDocumentationComment => isSynthetic + ? _syntheticDocumentationComment != null + : element.documentationComment != null; + @override void warn(PackageWarning kind, {String message, diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index ad59825147..63a4ac429b 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -83,6 +83,10 @@ mixin DocumentationComment String get documentationComment; + /// True if [this] has a synthetic/inherited or local documentation + /// comment. False otherwise. + bool get hasDocumentationComment; + /// Returns true if the raw documentation comment has a nodoc indication. bool get hasNodoc { if (documentationComment != null && diff --git a/lib/src/model/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart index 5074f34382..630c2d3714 100644 --- a/lib/src/model/getter_setter_combo.dart +++ b/lib/src/model/getter_setter_combo.dart @@ -170,35 +170,43 @@ mixin GetterSetterCombo on ModelElement { return docs; }(); + @override + bool get hasDocumentationComment => + _getterSetterDocumentationComment.isEmpty && + element.documentationComment == null; + + String __getterSetterDocumentationComment; + /// Derive a synthetic documentation comment using the documentation from - String get _getterSetterDocumentationComment { - var buffer = StringBuffer(); - - // Check for synthetic before public, always, or stack overflow. - if (hasGetter && !getter.isSynthetic && getter.isPublic) { - assert(getter.documentationFrom.length == 1); - // We have to check against dropTextFrom here since documentationFrom - // doesn't yield the real elements for GetterSetterCombos. - if (!config.dropTextFrom - .contains(getter.documentationFrom.first.element.library.name)) { - var docs = getter.documentationFrom.first.documentationComment; - if (docs != null) buffer.write(docs); - } - } + String get _getterSetterDocumentationComment => + __getterSetterDocumentationComment ??= () { + var buffer = StringBuffer(); - if (hasSetter && !setter.isSynthetic && setter.isPublic) { - assert(setter.documentationFrom.length == 1); - if (!config.dropTextFrom - .contains(setter.documentationFrom.first.element.library.name)) { - var docs = setter.documentationFrom.first.documentationComment; - if (docs != null) { - if (buffer.isNotEmpty) buffer.write('\n\n'); - buffer.write(docs); + // Check for synthetic before public, always, or stack overflow. + if (hasGetter && !getter.isSynthetic && getter.isPublic) { + assert(getter.documentationFrom.length == 1); + // We have to check against dropTextFrom here since documentationFrom + // doesn't yield the real elements for GetterSetterCombos. + if (!config.dropTextFrom + .contains(getter.documentationFrom.first.element.library.name)) { + var docs = getter.documentationFrom.first.documentationComment; + if (docs != null) buffer.write(docs); + } } - } - } - return buffer.toString(); - } + + if (hasSetter && !setter.isSynthetic && setter.isPublic) { + assert(setter.documentationFrom.length == 1); + if (!config.dropTextFrom + .contains(setter.documentationFrom.first.element.library.name)) { + var docs = setter.documentationFrom.first.documentationComment; + if (docs != null) { + if (buffer.isNotEmpty) buffer.write('\n\n'); + buffer.write(docs); + } + } + } + return buffer.toString(); + }(); ElementType get modelType { if (hasGetter) return getter.modelType.returnType; diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index 398427610d..f79402c3b1 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -919,6 +919,9 @@ abstract class ModelElement extends Canonicalization @override String get documentationComment => element.documentationComment; + @override + bool get hasDocumentationComment => element.documentationComment == null; + String _sourceCode; @override String get sourceCode { From a8f252d9df2694ecee66aebd85255993a5670aca Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 13:08:25 -0700 Subject: [PATCH 11/15] rebuild --- .../templates.runtime_renderers.dart | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/lib/src/generator/templates.runtime_renderers.dart b/lib/src/generator/templates.runtime_renderers.dart index 2b1240781b..f82fc57365 100644 --- a/lib/src/generator/templates.runtime_renderers.dart +++ b/lib/src/generator/templates.runtime_renderers.dart @@ -165,6 +165,13 @@ class _Renderer_Accessor extends RendererBase { parent: r); }, ), + 'hasDocumentationComment': Property( + getValue: (CT_ c) => c.hasDocumentationComment, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.hasDocumentationComment == true, + ), 'href': Property( getValue: (CT_ c) => c.href, renderVariable: @@ -4038,6 +4045,13 @@ class _Renderer_DocumentationComment parent: r); }, ), + 'hasDocumentationComment': Property( + getValue: (CT_ c) => c.hasDocumentationComment, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.hasDocumentationComment == true, + ), 'hasNodoc': Property( getValue: (CT_ c) => c.hasNodoc, renderVariable: (CT_ c, Property self, @@ -6023,6 +6037,13 @@ class _Renderer_GetterSetterCombo extends RendererBase { self.renderSimpleVariable(c, remainingNames, 'bool'), getBool: (CT_ c) => c.hasAccessorsWithDocs == true, ), + 'hasDocumentationComment': Property( + getValue: (CT_ c) => c.hasDocumentationComment, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.hasDocumentationComment == true, + ), 'hasExplicitGetter': Property( getValue: (CT_ c) => c.hasExplicitGetter, renderVariable: (CT_ c, Property self, @@ -9752,6 +9773,13 @@ class _Renderer_ModelElement extends RendererBase { self.renderSimpleVariable(c, remainingNames, 'bool'), getBool: (CT_ c) => c.hasDocumentation == true, ), + 'hasDocumentationComment': Property( + getValue: (CT_ c) => c.hasDocumentationComment, + renderVariable: (CT_ c, Property self, + List remainingNames) => + self.renderSimpleVariable(c, remainingNames, 'bool'), + getBool: (CT_ c) => c.hasDocumentationComment == true, + ), 'hasExtendedDocumentation': Property( getValue: (CT_ c) => c.hasExtendedDocumentation, renderVariable: (CT_ c, Property self, @@ -15263,6 +15291,7 @@ const _invisibleGetters = { 'documentationAsHtml', 'elementDocumentation', 'documentationComment', + 'hasDocumentationComment', 'hasNodoc', 'sourceFileName', 'fullyQualifiedNameWithoutLibrary', @@ -15480,6 +15509,7 @@ const _invisibleGetters = { 'getterSetterBothAvailable', 'oneLineDoc', 'documentationComment', + 'hasDocumentationComment', 'modelType', 'isCallable', 'hasParameters', From a913bafe59e2f346a4d4c2ba5e6ae4ffb152f107 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 15:34:43 -0700 Subject: [PATCH 12/15] documentationComment can be made non-nullable --- lib/src/model/accessor.dart | 52 ++++++++++++------------ lib/src/model/documentation_comment.dart | 6 +-- lib/src/model/getter_setter_combo.dart | 31 +++++++------- lib/src/model/model_element.dart | 4 +- lib/src/model/package_graph.dart | 2 +- test/end2end/model_test.dart | 2 +- 6 files changed, 50 insertions(+), 47 deletions(-) diff --git a/lib/src/model/accessor.dart b/lib/src/model/accessor.dart index 2a80a8f22d..a9fb81b3ab 100644 --- a/lib/src/model/accessor.dart +++ b/lib/src/model/accessor.dart @@ -85,40 +85,42 @@ class Accessor extends ModelElement implements EnclosedElement { return stripComments(super.documentationComment); }(); - String __syntheticDocumentationComment; + String /*!*/ __syntheticDocumentationComment; /// Build a documentation comment for this accessor assuming it is synthetic. /// Value here is not useful if [isSynthetic] is false. - String get _syntheticDocumentationComment => + String /*!*/ get _syntheticDocumentationComment => __syntheticDocumentationComment ??= () { - // If we're a setter, and a getter exists, do not add synthetic - // documentation if the combo's documentation is actually derived - // from that getter. - bool _comboDocsAreIndependent() { - if (isSetter && definingCombo.hasGetter) { - if (definingCombo.getter.isSynthetic || - !definingCombo.documentationFrom.contains(this)) { - return true; - } - } - return false; - } - - if ( // If this is a getter, assume we want synthetic documentation. - isGetter || - // If the definingCombo has a nodoc tag, we want synthetic documentation - // for a synthetic accessor just in case it is inherited somewhere - // down the line due to split inheritance. - definingCombo.hasNodoc || - _comboDocsAreIndependent()) { - return definingCombo.documentationComment; + if (_hasSyntheticDocumentationComment) { + return definingCombo.documentationComment ?? ''; } - return null; + return ''; }(); + /// If this is a getter, assume we want synthetic documentation. + /// If the definingCombo has a nodoc tag, we want synthetic documentation + /// for a synthetic accessor just in case it is inherited somewhere + /// down the line due to split inheritance. + bool get _hasSyntheticDocumentationComment => + (isGetter || definingCombo.hasNodoc || _comboDocsAreIndependent()) && + definingCombo.hasDocumentationComment; + + // If we're a setter, and a getter exists, do not add synthetic + // documentation if the combo's documentation is actually derived + // from that getter. + bool _comboDocsAreIndependent() { + if (isSetter && definingCombo.hasGetter) { + if (definingCombo.getter.isSynthetic || + !definingCombo.documentationFrom.contains(this)) { + return true; + } + } + return false; + } + @override bool get hasDocumentationComment => isSynthetic - ? _syntheticDocumentationComment != null + ? _hasSyntheticDocumentationComment : element.documentationComment != null; @override diff --git a/lib/src/model/documentation_comment.dart b/lib/src/model/documentation_comment.dart index 63a4ac429b..1351febb35 100644 --- a/lib/src/model/documentation_comment.dart +++ b/lib/src/model/documentation_comment.dart @@ -52,7 +52,7 @@ mixin DocumentationComment @override List get documentationFrom => _documentationFrom ??= () { - if (documentationComment == null && + if (!hasDocumentationComment && this is Inheritable && (this as Inheritable).overriddenElement != null) { return (this as Inheritable).overriddenElement.documentationFrom; @@ -81,7 +81,7 @@ mixin DocumentationComment return _elementDocumentation; } - String get documentationComment; + String /*!*/ get documentationComment; /// True if [this] has a synthetic/inherited or local documentation /// comment. False otherwise. @@ -89,7 +89,7 @@ mixin DocumentationComment /// Returns true if the raw documentation comment has a nodoc indication. bool get hasNodoc { - if (documentationComment != null && + if (hasDocumentationComment && (documentationComment.contains('@nodoc') || documentationComment.contains(''))) { return true; diff --git a/lib/src/model/getter_setter_combo.dart b/lib/src/model/getter_setter_combo.dart index 630c2d3714..3cce011981 100644 --- a/lib/src/model/getter_setter_combo.dart +++ b/lib/src/model/getter_setter_combo.dart @@ -161,47 +161,48 @@ mixin GetterSetterCombo on ModelElement { bool _documentationCommentComputed = false; String _documentationComment; @override - String get documentationComment => _documentationCommentComputed + String /*!*/ get documentationComment => _documentationCommentComputed ? _documentationComment : _documentationComment ??= () { _documentationCommentComputed = true; var docs = _getterSetterDocumentationComment; - if (docs.isEmpty) return element.documentationComment; + if (docs.isEmpty) return element.documentationComment ?? ''; return docs; }(); @override bool get hasDocumentationComment => - _getterSetterDocumentationComment.isEmpty && - element.documentationComment == null; + _getterSetterDocumentationComment.isNotEmpty || + element.documentationComment != null; String __getterSetterDocumentationComment; - /// Derive a synthetic documentation comment using the documentation from - String get _getterSetterDocumentationComment => + /// Derive a documentation comment for the combo by copying documentation + /// from the [getter] and/or [setter]. + String /*!*/ get _getterSetterDocumentationComment => __getterSetterDocumentationComment ??= () { var buffer = StringBuffer(); // Check for synthetic before public, always, or stack overflow. if (hasGetter && !getter.isSynthetic && getter.isPublic) { assert(getter.documentationFrom.length == 1); + var fromGetter = getter.documentationFrom.first; // We have to check against dropTextFrom here since documentationFrom // doesn't yield the real elements for GetterSetterCombos. - if (!config.dropTextFrom - .contains(getter.documentationFrom.first.element.library.name)) { - var docs = getter.documentationFrom.first.documentationComment; - if (docs != null) buffer.write(docs); + if (!config.dropTextFrom.contains(fromGetter.element.library.name)) { + if (fromGetter.hasDocumentationComment) { + buffer.write(fromGetter.documentationComment); + } } } if (hasSetter && !setter.isSynthetic && setter.isPublic) { assert(setter.documentationFrom.length == 1); - if (!config.dropTextFrom - .contains(setter.documentationFrom.first.element.library.name)) { - var docs = setter.documentationFrom.first.documentationComment; - if (docs != null) { + var fromSetter = setter.documentationFrom.first; + if (!config.dropTextFrom.contains(fromSetter.element.library.name)) { + if (fromSetter.hasDocumentationComment) { if (buffer.isNotEmpty) buffer.write('\n\n'); - buffer.write(docs); + buffer.write(fromSetter.documentationComment); } } } diff --git a/lib/src/model/model_element.dart b/lib/src/model/model_element.dart index f79402c3b1..c18fad8cbd 100644 --- a/lib/src/model/model_element.dart +++ b/lib/src/model/model_element.dart @@ -917,10 +917,10 @@ abstract class ModelElement extends Canonicalization } @override - String get documentationComment => element.documentationComment; + String /*!*/ get documentationComment => element.documentationComment ?? ''; @override - bool get hasDocumentationComment => element.documentationComment == null; + bool get hasDocumentationComment => element.documentationComment != null; String _sourceCode; @override diff --git a/lib/src/model/package_graph.dart b/lib/src/model/package_graph.dart index 26210a2d7d..d4f0bd0749 100644 --- a/lib/src/model/package_graph.dart +++ b/lib/src/model/package_graph.dart @@ -134,7 +134,7 @@ class PackageGraph with CommentReferable, Nameable { Iterable> precacheOneElement(ModelElement m) sync* { for (var d - in m.documentationFrom.where((d) => d.documentationComment != null)) { + in m.documentationFrom.where((d) => d.hasDocumentationComment)) { if (d.needsPrecache && !precachedElements.contains(d)) { precachedElements.add(d); yield d.precacheLocalDocs(); diff --git a/test/end2end/model_test.dart b/test/end2end/model_test.dart index 1a64fafc9a..871cba9c59 100644 --- a/test/end2end/model_test.dart +++ b/test/end2end/model_test.dart @@ -630,7 +630,7 @@ void main() { () { // Verify setup of the test is correct. expect(invokeToolParentDoc.isCanonical, isTrue); - expect(invokeToolParentDoc.documentationComment, isNull); + expect(invokeToolParentDoc.hasDocumentationComment, isFalse); // Error message here might look strange due to toString() on Methods, but if this // fails that means we don't have the correct invokeToolParentDoc instance. expect(invokeToolParentDoc.documentationFrom, From fb2e28f0565f127901e6cfead3e17dd4277eee56 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Thu, 30 Sep 2021 16:59:43 -0700 Subject: [PATCH 13/15] Update test.yaml to delete sdk check from beta branch --- .github/workflows/test.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 79119acbc9..d940d8fa6a 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -36,6 +36,9 @@ jobs: job: flutter - sdk: beta job: sdk-analyzer + # TODO(jcollins-g): Delete exception as 2.15 beta 2 gets underway + - sdk: beta + job: sdk steps: - name: Store date From 91ea1d5de26bc118db5a52de197cacc28500034e Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 1 Oct 2021 10:28:46 -0700 Subject: [PATCH 14/15] tab conversion error --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d940d8fa6a..2a090e23d6 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -37,7 +37,7 @@ jobs: - sdk: beta job: sdk-analyzer # TODO(jcollins-g): Delete exception as 2.15 beta 2 gets underway - - sdk: beta + - sdk: beta job: sdk steps: From f68a999c6654622ad4a57ce2cc5037f5f682d980 Mon Sep 17 00:00:00 2001 From: Janice Collins Date: Fri, 1 Oct 2021 11:07:09 -0700 Subject: [PATCH 15/15] correct name --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 2a090e23d6..ecc351c991 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -38,7 +38,7 @@ jobs: job: sdk-analyzer # TODO(jcollins-g): Delete exception as 2.15 beta 2 gets underway - sdk: beta - job: sdk + job: sdk-docs steps: - name: Store date