Skip to content

Commit fabd65a

Browse files
authored
Warn "not yet implemented" for comment reference resolution for extension methods (dart-lang#2040)
* Add some tests to trigger crash bug * Add warning for not yet implemented and seal off comment resolution to avoid type errors * Extend a timeout
1 parent 3375875 commit fabd65a

File tree

6 files changed

+67
-10
lines changed

6 files changed

+67
-10
lines changed

lib/src/markdown_processor.dart

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,13 @@ MatchingLinkResult _getMatchingLinkElement(
205205
// Try expensive not-scoped lookup.
206206
if (refModelElement == null && element is ModelElement) {
207207
Container preferredClass = _getPreferredClass(element);
208-
refModelElement =
209-
_MarkdownCommentReference(codeRef, element, commentRefs, preferredClass)
210-
.computeReferredElement();
208+
if (preferredClass is Extension) {
209+
element.warn(PackageWarning.notImplemented, message: 'Comment reference resolution inside extension methods is not yet implemented');
210+
} else {
211+
refModelElement =
212+
_MarkdownCommentReference(codeRef, element, commentRefs, preferredClass)
213+
.computeReferredElement();
214+
}
211215
}
212216

213217
// Did not find it anywhere.

lib/src/model.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5271,6 +5271,9 @@ class PackageGraph {
52715271
warningMessage =
52725272
"private API of ${message} is reexported by libraries in other packages: ";
52735273
break;
5274+
case PackageWarning.notImplemented:
5275+
warningMessage = message;
5276+
break;
52745277
case PackageWarning.unresolvedDocReference:
52755278
warningMessage = "unresolved doc reference [${message}]";
52765279
referredFromPrefix = 'in documentation inherited from';

lib/src/warnings.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ final Map<PackageWarning, PackageWarningDefinition> packageWarningDefinitions =
135135
PackageWarning.noCanonicalFound,
136136
"no-canonical-found",
137137
"A symbol is part of the public interface for this package, but no library documented with this package documents it so dartdoc can not link to it"),
138+
PackageWarning.notImplemented: PackageWarningDefinition(
139+
PackageWarning.notImplemented,
140+
"not-implemented",
141+
"The code makes use of a feature that is not yet implemented in dartdoc"),
138142
PackageWarning.noLibraryLevelDocs: PackageWarningDefinition(
139143
PackageWarning.noLibraryLevelDocs,
140144
"no-library-level-docs",
@@ -226,6 +230,7 @@ enum PackageWarning {
226230
ambiguousReexport,
227231
ignoredCanonicalFor,
228232
noCanonicalFound,
233+
notImplemented,
229234
noLibraryLevelDocs,
230235
packageOrderGivesMissingPackageName,
231236
reexportedPrivateApiAcrossPackages,

test/dartdoc_integration_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ void main() {
6969
expect(outputLines, contains(matches('^ warning:')));
7070
expect(outputLines.last, matches(r'^found \d+ warnings and \d+ errors'));
7171
expect(outputDir.listSync(), isNotEmpty);
72-
}, timeout: new Timeout.factor(2));
72+
}, timeout: Timeout.factor(2));
7373

7474
test('invalid parameters return non-zero and print a fatal-error',
7575
() async {
@@ -229,7 +229,7 @@ void main() {
229229

230230
File outFile = File(path.join(tempDir.path, 'index.html'));
231231
expect(outFile.readAsStringSync(), contains('footer text include'));
232-
});
232+
}, timeout: Timeout.factor(2));
233233

234234
test('--footer-text excludes version', () async {
235235
String _testPackagePath =

test/model_test.dart

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1904,7 +1904,7 @@ void main() {
19041904
});
19051905

19061906
test('correctly finds all the classes', () {
1907-
expect(classes, hasLength(31));
1907+
expect(classes, hasLength(33));
19081908
});
19091909

19101910
test('abstract', () {
@@ -2114,15 +2114,37 @@ void main() {
21142114

21152115
group('Extension', () {
21162116
Extension ext, fancyList;
2117-
Method s;
2117+
Class extensionReferencer;
2118+
Method doSomeStuff, doStuff, s;
21182119
List<Extension> extensions;
21192120

21202121
setUpAll(() {
21212122
ext = exLibrary.extensions.firstWhere((e) => e.name == 'AppleExtension');
2123+
extensionReferencer = exLibrary.classes.firstWhere((c) => c.name == 'ExtensionReferencer');
21222124
fancyList = exLibrary.extensions.firstWhere((e) => e.name == 'FancyList');
2125+
doSomeStuff = exLibrary.classes.firstWhere((c) => c.name == 'ExtensionUser')
2126+
.allInstanceMethods.firstWhere((m) => m.name == 'doSomeStuff');
2127+
doStuff = exLibrary.extensions.firstWhere((e) => e.name == 'SimpleStringExtension')
2128+
.instanceMethods.firstWhere((m) => m.name == 'doStuff');
21232129
extensions = exLibrary.publicExtensions.toList();
21242130
});
21252131

2132+
// TODO(jcollins-g): implement feature and update tests
2133+
test('documentation links do not crash in base cases', () {
2134+
packageGraph.packageWarningCounter.hasWarning(doStuff, PackageWarning.notImplemented,
2135+
'Comment reference resolution inside extension methods is not yet implemented');
2136+
packageGraph.packageWarningCounter.hasWarning(doSomeStuff, PackageWarning.notImplemented,
2137+
'Comment reference resolution inside extension methods is not yet implemented');
2138+
expect(doStuff.documentationAsHtml, contains('<code>another</code>'));
2139+
expect(doSomeStuff.documentationAsHtml, contains('<code>String.extensionNumber</code>'));
2140+
});
2141+
2142+
test('references from outside an extension refer correctly to the extension', () {
2143+
expect(extensionReferencer.documentationAsHtml, contains('<code>_Shhh</code>'));
2144+
expect(extensionReferencer.documentationAsHtml, contains('<a href="ex/FancyList.html">FancyList</a>'));
2145+
expect(extensionReferencer.documentationAsHtml, contains('<a href="ex/AnExtension/call.html">AnExtension.call</a>'));
2146+
});
2147+
21262148
test('has a fully qualified name', () {
21272149
expect(ext.fullyQualifiedName, 'ex.AppleExtension');
21282150
});
@@ -2179,11 +2201,11 @@ void main() {
21792201
});
21802202

21812203
test('correctly finds all the extensions', () {
2182-
expect(exLibrary.extensions, hasLength(7));
2204+
expect(exLibrary.extensions, hasLength(8));
21832205
});
21842206

21852207
test('correctly finds all the public extensions', () {
2186-
expect(extensions, hasLength(5));
2208+
expect(extensions, hasLength(6));
21872209
});
21882210
});
21892211

testing/test_package/lib/example.dart

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,24 @@ extension AnExtension<Q> on WithGeneric<Q> {
627627
int call(String s) => 0;
628628
}
629629

630+
extension SimpleStringExtension on String {
631+
/// Print this and [another].
632+
/// Refer to [indexOf], from [String].
633+
/// Also refer to [extensionNumber].
634+
void doStuff(String another) {
635+
print(this + another);
636+
}
637+
638+
int get extensionNumber => 3;
639+
}
640+
641+
class ExtensionUser {
642+
/// Refer to [String.extensionNumber], which we use here.
643+
void doSomeStuff(String things) {
644+
print(things.extensionNumber + 1);
645+
}
646+
}
647+
630648
/// Extension on List
631649
extension FancyList<Z> on List<Z> {
632650
int get doubleLength => this.length * 2;
@@ -654,4 +672,9 @@ extension _Shhh on Object {
654672
// Extension with no name
655673
extension on Object {
656674
void bar() { }
657-
}
675+
}
676+
677+
678+
/// This class has nothing to do with [_Shhh], [FancyList], or [AnExtension.call],
679+
/// but should not crash because we referenced them.
680+
class ExtensionReferencer {}

0 commit comments

Comments
 (0)