Skip to content

Commit b353c7b

Browse files
authored
eliminate crash on warnings generated by README.md (#1410)
* Fix readme warnings * Update test to generate warnings from the readme * dartfmt * Shift around abstract classes to make this more understandable * dartfmt
1 parent 2d88c17 commit b353c7b

File tree

9 files changed

+83
-52
lines changed

9 files changed

+83
-52
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 0.11.2
2+
* Fix regression where warnings generated by the README could result in a fatal exception. #1409
3+
14
## 0.11.1
25
* Fix regression where a property or top level variable can be listed twice
36
under some conditions. #1401

bin/dartdoc.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,10 @@ main(List<String> arguments) async {
177177
print('\nSuccess! Docs generated into ${results.outDir.absolute.path}');
178178
}, onError: (e, Chain chain) {
179179
if (e is DartDocFailure) {
180-
stderr.writeln('Generation failed: ${e}.');
180+
stderr.writeln('\nGeneration failed: ${e}.');
181181
exit(1);
182182
} else {
183-
stderr.writeln('Generation failed: ${e}\n${chain.terse}');
183+
stderr.writeln('\nGeneration failed: ${e}\n${chain.terse}');
184184
exit(255);
185185
}
186186
});

lib/dartdoc.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export 'src/sdk.dart';
4444

4545
const String name = 'dartdoc';
4646
// Update when pubspec version changes.
47-
const String version = '0.11.1';
47+
const String version = '0.11.2';
4848

4949
final String defaultOutDir = path.join('doc', 'api');
5050

@@ -241,7 +241,7 @@ class DartDoc {
241241
}
242242
if (referenceElement == null && source == 'index.html')
243243
referenceElement = package;
244-
package.warn(referenceElement, kind, p);
244+
package.warnOnElement(referenceElement, kind, p);
245245
}
246246

247247
void _doOrphanCheck(Package package, String origin, Set<String> visited) {

lib/src/html/html_generator_instance.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ class HtmlGeneratorInstance implements HtmlOptions {
189189
stdout
190190
.write('\ngenerating docs for library ${lib.name} from ${lib.path}...');
191191
if (!lib.isAnonymous && !lib.hasDocumentation) {
192-
package.warn(lib, PackageWarning.noLibraryLevelDocs);
192+
package.warnOnElement(lib, PackageWarning.noLibraryLevelDocs);
193193
}
194194
TemplateData data =
195195
new LibraryTemplateData(this, package, lib, useCategories);

lib/src/markdown_processor.dart

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,11 @@ ModelElement _getPreferredClass(ModelElement modelElement) {
164164
}
165165

166166
// TODO: this is in the wrong place
167-
NodeList<CommentReference> _getCommentRefs(ModelElement modelElement) {
167+
NodeList<CommentReference> _getCommentRefs(Documentable documentable) {
168+
// Documentable items that aren't related to analyzer elements have no
169+
// CommentReference list.
170+
if (documentable is! ModelElement) return null;
171+
ModelElement modelElement = documentable;
168172
Class preferredClass = _getPreferredClass(modelElement);
169173
ModelElement cModelElement = modelElement.package
170174
.findCanonicalModelElementFor(modelElement.element,
@@ -219,7 +223,7 @@ NodeList<CommentReference> _getCommentRefs(ModelElement modelElement) {
219223

220224
/// Returns null if element is a parameter.
221225
MatchingLinkResult _getMatchingLinkElement(
222-
String codeRef, ModelElement element, List<CommentReference> commentRefs) {
226+
String codeRef, Documentable element, List<CommentReference> commentRefs) {
223227
// By debugging inspection, it seems correct to not warn when we don't have
224228
// CommentReferences; there's actually nothing that needs resolving in
225229
// that case.
@@ -244,19 +248,16 @@ MatchingLinkResult _getMatchingLinkElement(
244248
// dartdoc-canonicalization-aware?
245249
if (refElement == null) {
246250
refElement = _getRefElementFromCommentRefs(commentRefs, codeRef);
251+
} else {
252+
assert(refElement is! PropertyAccessorElement);
253+
assert(refElement is! PrefixElement);
247254
}
248255

249256
// Did not find it anywhere.
250257
if (refElement == null) {
251258
return new MatchingLinkResult(null, null);
252259
}
253260

254-
if (refElement is PropertyAccessorElement) {
255-
// yay we found an accessor that wraps a const, but we really
256-
// want the top-level field itself
257-
refElement = (refElement as PropertyAccessorElement).variable;
258-
}
259-
260261
// Ignore all parameters.
261262
if (refElement is ParameterElement || refElement is TypeParameterElement)
262263
return new MatchingLinkResult(null, null, warn: false);
@@ -300,7 +301,17 @@ Element _getRefElementFromCommentRefs(
300301
bool isConstrElement = ref.identifier.staticElement is ConstructorElement;
301302
// Constructors are now handled by library search.
302303
if (!isConstrElement) {
303-
return ref.identifier.staticElement;
304+
Element refElement = ref.identifier.staticElement;
305+
if (refElement is PropertyAccessorElement) {
306+
// yay we found an accessor that wraps a const, but we really
307+
// want the top-level field itself
308+
refElement = (refElement as PropertyAccessorElement).variable;
309+
}
310+
if (refElement is PrefixElement) {
311+
// We found a prefix element, but what we really want is the library element.
312+
refElement = (refElement as PrefixElement).enclosingElement;
313+
}
314+
return refElement;
304315
}
305316
}
306317
}
@@ -340,6 +351,7 @@ Map<String, Set<ModelElement>> _findRefElementCache;
340351
// TODO(jcollins-g): A complex package winds up spending a lot of cycles in here. Optimize.
341352
Element _findRefElementInLibrary(
342353
String codeRef, ModelElement element, List<CommentReference> commentRefs) {
354+
assert(element != null);
343355
assert(element.package.allLibrariesAdded);
344356

345357
String codeRefChomped = codeRef.replaceFirst(isConstructor, '');
@@ -625,14 +637,13 @@ void _getResultsForClass(Class tryClass, String codeRefChomped,
625637
}
626638
}
627639

628-
String _linkDocReference(String codeRef, ModelElement element,
640+
String _linkDocReference(String codeRef, Documentable documentable,
629641
NodeList<CommentReference> commentRefs) {
630642
// TODO(jcollins-g): Refactor so that doc operations work on the
631643
// documented element.
632-
element = element.overriddenDocumentedElement;
633-
644+
documentable = documentable.overriddenDocumentedElement;
634645
MatchingLinkResult result;
635-
result = _getMatchingLinkElement(codeRef, element, commentRefs);
646+
result = _getMatchingLinkElement(codeRef, documentable, commentRefs);
636647
final ModelElement linkedElement = result.element;
637648
final String label = result.label ?? codeRef;
638649
if (linkedElement != null) {
@@ -649,18 +660,19 @@ String _linkDocReference(String codeRef, ModelElement element,
649660
}
650661
} else {
651662
if (result.warn) {
652-
element.warn(PackageWarning.unresolvedDocReference, codeRef);
663+
documentable.warn(PackageWarning.unresolvedDocReference, codeRef);
653664
}
654665
return '<code>${HTML_ESCAPE.convert(label)}</code>';
655666
}
656667
}
657668

658-
String _renderMarkdownToHtml(String text, [ModelElement element]) {
669+
String _renderMarkdownToHtml(Documentable element) {
659670
md.Node _linkResolver(String name) {
660671
NodeList<CommentReference> commentRefs = _getCommentRefs(element);
661672
return new md.Text(_linkDocReference(name, element, commentRefs));
662673
}
663674

675+
String text = element.documentation;
664676
_showWarningsForGenericsOutsideSquareBracketsBlocks(text, element);
665677
return md.markdownToHtml(text,
666678
inlineSyntaxes: _markdown_syntaxes, linkResolver: _linkResolver);
@@ -676,7 +688,7 @@ const maxPostContext = 30;
676688
// like a non HTML tag (a generic?) outside of a `[]` block.
677689
// https://github.com/dart-lang/dartdoc/issues/1250#issuecomment-269257942
678690
void _showWarningsForGenericsOutsideSquareBracketsBlocks(
679-
String text, ModelElement element) {
691+
String text, Warnable element) {
680692
List<int> tagPositions = findFreeHangingGenericsPositions(text);
681693
if (tagPositions.isNotEmpty) {
682694
tagPositions.forEach((int position) {
@@ -732,13 +744,8 @@ class Documentation {
732744
final String asHtml;
733745
final String asOneLiner;
734746

735-
factory Documentation(String markdown) {
736-
String tempHtml = _renderMarkdownToHtml(markdown);
737-
return new Documentation._internal(markdown, tempHtml);
738-
}
739-
740-
factory Documentation.forElement(ModelElement element) {
741-
String tempHtml = _renderMarkdownToHtml(element.documentation, element);
747+
factory Documentation.forElement(Documentable element) {
748+
String tempHtml = _renderMarkdownToHtml(element);
742749
return new Documentation._internal(element.documentation, tempHtml);
743750
}
744751

lib/src/model.dart

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -895,11 +895,13 @@ class Constructor extends ModelElement
895895

896896
/// Bridges the gap between model elements and packages,
897897
/// both of which have documentation.
898-
abstract class Documentable {
898+
abstract class Documentable implements Warnable {
899899
String get documentation;
900900
String get documentationAsHtml;
901901
bool get hasDocumentation;
902902
String get oneLineDoc;
903+
Documentable get overriddenDocumentedElement;
904+
Package get package;
903905
}
904906

905907
class Dynamic extends ModelElement {
@@ -1709,8 +1711,7 @@ class Method extends ModelElement
17091711
/// helps prevent subtle bugs as generated output for a non-canonical
17101712
/// ModelElement will reference itself as part of the "wrong" [Library]
17111713
/// from the public interface perspective.
1712-
abstract class ModelElement
1713-
implements Comparable, Nameable, Documentable, Locatable {
1714+
abstract class ModelElement implements Comparable, Nameable, Documentable {
17141715
final Element _element;
17151716
final Library _library;
17161717

@@ -2152,6 +2153,7 @@ abstract class ModelElement
21522153
bool _overriddenDocumentedElementIsSet = false;
21532154
// TODO(jcollins-g): This method prefers canonical elements, but it isn't
21542155
// guaranteed and is probably the source of bugs or confusing warnings.
2156+
@override
21552157
ModelElement get overriddenDocumentedElement {
21562158
if (!_overriddenDocumentedElementIsSet) {
21572159
ModelElement found = this;
@@ -2180,6 +2182,7 @@ abstract class ModelElement
21802182
return _overriddenDepth;
21812183
}
21822184

2185+
@override
21832186
Package get package =>
21842187
(this is Library) ? (this as Library).package : this.library.package;
21852188

@@ -2236,14 +2239,15 @@ abstract class ModelElement
22362239
return _parameters;
22372240
}
22382241

2242+
@override
22392243
void warn(PackageWarning kind, [String message]) {
22402244
if (kind == PackageWarning.unresolvedDocReference &&
22412245
overriddenElement != null) {
22422246
// The documentation we're using for this element came from somewhere else.
22432247
// Attach the warning to that element to deduplicate.
22442248
overriddenElement.warn(kind, message);
22452249
} else {
2246-
library.package.warn(this, kind, message);
2250+
library.package.warnOnElement(this, kind, message);
22472251
}
22482252
}
22492253

@@ -2763,6 +2767,11 @@ Map<PackageWarning, List<String>> packageWarningText = {
27632767
],
27642768
};
27652769

2770+
// Something that package warnings can be called on.
2771+
abstract class Warnable implements Locatable {
2772+
void warn(PackageWarning warning, [String message]);
2773+
}
2774+
27662775
// Something that can be located for warning purposes.
27672776
abstract class Locatable {
27682777
String get fullyQualifiedName;
@@ -2889,7 +2898,7 @@ class PackageWarningCounter {
28892898
}
28902899
}
28912900

2892-
class Package implements Nameable, Documentable, Locatable {
2901+
class Package implements Nameable, Documentable {
28932902
// Library objects serving as entry points for documentation.
28942903
final List<Library> _libraries = [];
28952904
// All library objects related to this package; a superset of _libraries.
@@ -2911,6 +2920,12 @@ class Package implements Nameable, Documentable, Locatable {
29112920

29122921
final PackageMeta packageMeta;
29132922

2923+
@override
2924+
Package get package => this;
2925+
2926+
@override
2927+
Documentable get overriddenDocumentedElement => this;
2928+
29142929
final Map<Element, Library> _elementToLibrary = {};
29152930
String _docsAsHtml;
29162931
final Map<String, String> _macros = {};
@@ -2958,29 +2973,33 @@ class Package implements Nameable, Documentable, Locatable {
29582973

29592974
PackageWarningCounter get packageWarningCounter => _packageWarningCounter;
29602975

2961-
void warn(Locatable modelElement, PackageWarning kind, [String message]) {
2962-
if (modelElement != null) {
2976+
@override
2977+
void warn(PackageWarning kind, [String message]) {
2978+
warnOnElement(this, kind, message);
2979+
}
2980+
2981+
void warnOnElement(Warnable warnable, PackageWarning kind, [String message]) {
2982+
if (warnable != null) {
29632983
// This sort of warning is only applicable to top level elements.
29642984
if (kind == PackageWarning.ambiguousReexport) {
2965-
Element topLevelElement = modelElement.element;
2985+
Element topLevelElement = warnable.element;
29662986
while (topLevelElement.enclosingElement is! CompilationUnitElement) {
29672987
topLevelElement = topLevelElement.enclosingElement;
29682988
}
2969-
modelElement = new ModelElement.from(
2989+
warnable = new ModelElement.from(
29702990
topLevelElement, findOrCreateLibraryFor(topLevelElement));
29712991
}
2972-
if (modelElement is Accessor) {
2992+
if (warnable is Accessor) {
29732993
// This might be part of a Field, if so, assign this warning to the field
29742994
// rather than the Accessor.
2975-
if ((modelElement as Accessor).enclosingCombo != null)
2976-
modelElement = (modelElement as Accessor).enclosingCombo;
2995+
if ((warnable as Accessor).enclosingCombo != null)
2996+
warnable = (warnable as Accessor).enclosingCombo;
29772997
}
29782998
} else {
29792999
// If we don't have an element, we need a message to disambiguate.
29803000
assert(message != null);
29813001
}
2982-
if (_packageWarningCounter.hasWarning(
2983-
modelElement?.element, kind, message)) {
3002+
if (_packageWarningCounter.hasWarning(warnable?.element, kind, message)) {
29843003
return;
29853004
}
29863005
// Elements that are part of the Dart SDK can have colons in their FQNs.
@@ -2991,9 +3010,9 @@ class Package implements Nameable, Documentable, Locatable {
29913010
// them out doesn't work as well there since it might confuse
29923011
// the user, yet we still want IntelliJ to link properly.
29933012
String nameSplitFromColonPieces;
2994-
if (modelElement != null) {
3013+
if (warnable != null) {
29953014
nameSplitFromColonPieces =
2996-
modelElement.fullyQualifiedName.replaceFirst(':', '-');
3015+
warnable.fullyQualifiedName.replaceFirst(':', '-');
29973016
}
29983017
String warningMessage;
29993018
switch (kind) {
@@ -3014,7 +3033,7 @@ class Package implements Nameable, Documentable, Locatable {
30143033
break;
30153034
case PackageWarning.noLibraryLevelDocs:
30163035
warningMessage =
3017-
"${modelElement.fullyQualifiedName} has no library level documentation comments";
3036+
"${warnable.fullyQualifiedName} has no library level documentation comments";
30183037
break;
30193038
case PackageWarning.ambiguousDocReference:
30203039
warningMessage =
@@ -3047,9 +3066,9 @@ class Package implements Nameable, Documentable, Locatable {
30473066
break;
30483067
}
30493068
String fullMessage =
3050-
"${warningMessage} ${modelElement != null ? modelElement.elementLocation : ''}";
3069+
"${warningMessage} ${warnable != null ? warnable.elementLocation : ''}";
30513070
packageWarningCounter.addWarning(
3052-
modelElement?.element, kind, message, fullMessage);
3071+
warnable?.element, kind, message, fullMessage);
30533072
}
30543073

30553074
static Package _withAutoIncludedDependencies(
@@ -3110,7 +3129,7 @@ class Package implements Nameable, Documentable, Locatable {
31103129
// Help the user if they pass us a category that doesn't exist.
31113130
for (String categoryName in config.categoryOrder) {
31123131
if (!result.containsKey(categoryName))
3113-
warn(null, PackageWarning.categoryOrderGivesMissingPackageName,
3132+
warnOnElement(null, PackageWarning.categoryOrderGivesMissingPackageName,
31143133
"${categoryName}, categories: ${result.keys.join(',')}");
31153134
}
31163135
List<PackageCategory> packageCategories = result.values.toList()..sort();
@@ -3167,8 +3186,7 @@ class Package implements Nameable, Documentable, Locatable {
31673186
@override
31683187
String get documentationAsHtml {
31693188
if (_docsAsHtml != null) return _docsAsHtml;
3170-
3171-
_docsAsHtml = new Documentation(documentation).asHtml;
3189+
_docsAsHtml = new Documentation.forElement(this).asHtml;
31723190

31733191
return _docsAsHtml;
31743192
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: dartdoc
22
# Also update the `version` field in lib/dartdoc.dart.
3-
version: 0.11.1
3+
version: 0.11.2
44
author: Dart Team <[email protected]>
55
description: A documentation generator for Dart.
66
homepage: https://github.com/dart-lang/dartdoc

testing/test_package/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ and_yaml:
2323
- 3.14
2424
```
2525
26+
It sometimes generates warnings in commentRefs like this: [unknownThingy.FromSomewhere]
27+
2628
Be sure to check out other awesome packages on [pub][].
2729
2830
[pub]: https://pub.dartlang.org

0 commit comments

Comments
 (0)