Skip to content

Commit 99f45ab

Browse files
authored
Add package global and graph global lookups to new lookup code (#2684)
* Handle different name styles in constructor * dartfmt * Fixes seem to work. * Rebuild * rebuild post-merge * fix analysis error in fake * Package globals on * Implement package global and graph global lookups
1 parent 9ef58f2 commit 99f45ab

File tree

8 files changed

+150
-50
lines changed

8 files changed

+150
-50
lines changed

lib/src/comment_references/parser.dart

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ class CommentReferenceParser {
142142
}
143143

144144
static const _constructorHintPrefix = 'new';
145-
146145
static const _ignorePrefixes = ['const', 'final', 'var'];
147146

148147
/// Implement parsing a prefix to a comment reference.
@@ -153,17 +152,19 @@ class CommentReferenceParser {
153152
///
154153
/// <constructorPrefixHint> ::= 'new '
155154
///
156-
/// <leadingJunk> ::= ('const' | 'final' | 'var' | 'operator')(' '+)
155+
/// <leadingJunk> ::= ('const' | 'final' | 'var')(' '+)
157156
/// ```
158157
_PrefixParseResult _parsePrefix() {
159158
if (_atEnd) {
160159
return _PrefixParseResult.endOfFile;
161160
}
162-
if (_tryMatchLiteral(_constructorHintPrefix)) {
161+
if (_tryMatchLiteral(_constructorHintPrefix,
162+
requireTrailingNonidentifier: true)) {
163163
return _PrefixParseResult.ok(
164164
ConstructorHintStartNode(_constructorHintPrefix));
165165
}
166-
if (_ignorePrefixes.any((p) => _tryMatchLiteral(p))) {
166+
if (_ignorePrefixes
167+
.any((p) => _tryMatchLiteral(p, requireTrailingNonidentifier: true))) {
167168
return _PrefixParseResult.junk;
168169
}
169170

@@ -278,10 +279,12 @@ class CommentReferenceParser {
278279

279280
/// Advances [_index] on match, preserves on non-match.
280281
bool _tryMatchLiteral(String characters,
281-
{bool acceptTrailingWhitespace = true}) {
282+
{bool acceptTrailingWhitespace = true,
283+
bool requireTrailingNonidentifier = false}) {
282284
assert(acceptTrailingWhitespace != null);
283285
if (characters.length + _index > _referenceLength) return false;
284-
for (var startIndex = _index;
286+
int startIndex;
287+
for (startIndex = _index;
285288
_index - startIndex < characters.length;
286289
_index++) {
287290
if (codeRef.codeUnitAt(_index) !=
@@ -290,6 +293,12 @@ class CommentReferenceParser {
290293
return false;
291294
}
292295
}
296+
if (requireTrailingNonidentifier) {
297+
if (_atEnd || !_nonIdentifierChars.contains(_thisChar)) {
298+
_index = startIndex;
299+
return false;
300+
}
301+
}
293302
if (acceptTrailingWhitespace) _walkPastWhitespace();
294303
return true;
295304
}

lib/src/markdown_processor.dart

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -191,23 +191,34 @@ class MatchingLinkResult {
191191

192192
bool isEquivalentTo(MatchingLinkResult other) {
193193
if (this == other) return true;
194-
if (modelElement?.canonicalModelElement ==
195-
other.modelElement?.canonicalModelElement) return true;
194+
var compareThis = modelElement;
195+
var compareOther = other.modelElement;
196+
197+
if (compareThis is Accessor) {
198+
compareThis = (compareThis as Accessor).enclosingCombo;
199+
}
200+
201+
if (compareOther is Accessor) {
202+
compareOther = (compareOther as Accessor).enclosingCombo;
203+
}
204+
205+
if (compareThis?.canonicalModelElement ==
206+
compareOther?.canonicalModelElement) return true;
196207
// The old implementation just throws away Parameter matches to avoid
197208
// problems with warning unnecessarily at higher levels of the code.
198209
// I'd like to fix this at a different layer with the new lookup, so treat
199210
// this as equivalent to a null type.
200-
if (other.modelElement is Parameter && modelElement == null) {
211+
if (compareOther is Parameter && compareThis == null) {
201212
return true;
202213
}
203-
if (modelElement is Parameter && other.modelElement == null) {
214+
if (compareThis is Parameter && compareOther == null) {
204215
return true;
205216
}
206217
// Same with TypeParameter.
207-
if (other.modelElement is TypeParameter && modelElement == null) {
218+
if (compareOther is TypeParameter && compareThis == null) {
208219
return true;
209220
}
210-
if (modelElement is TypeParameter && other.modelElement == null) {
221+
if (compareThis is TypeParameter && compareOther == null) {
211222
return true;
212223
}
213224
return false;
@@ -290,6 +301,10 @@ bool _rejectDefaultConstructors(CommentReferable referable) {
290301
referable.name == referable.enclosingElement.name) {
291302
return false;
292303
}
304+
// Avoid accidentally preferring arguments of the default constructor.
305+
if (referable is ModelElement && referable.enclosingElement is Constructor) {
306+
return false;
307+
}
293308
return true;
294309
}
295310

lib/src/model/library.dart

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -662,9 +662,21 @@ class Library extends ModelElement with Categorization, TopLevelContainer {
662662
Map<String, CommentReferable> _referenceChildren;
663663
@override
664664
Map<String, CommentReferable> get referenceChildren {
665-
return _referenceChildren ??= Map.fromEntries(
666-
element.exportNamespace.definedNames.entries.map((entry) => MapEntry(
667-
entry.key, ModelElement.fromElement(entry.value, packageGraph))));
665+
if (_referenceChildren == null) {
666+
_referenceChildren = Map.fromEntries(
667+
element.exportNamespace.definedNames.entries.map((entry) => MapEntry(
668+
entry.key, ModelElement.fromElement(entry.value, packageGraph))));
669+
// TODO(jcollins-g): warn and get rid of this case where it shows up.
670+
// If a user is hiding parts of a prefix import, the user should not
671+
// refer to hidden members via the prefix, because that can be
672+
// ambiguous. dart-lang/dartdoc#2683.
673+
for (var prefixEntry in prefixToLibrary.entries) {
674+
if (!_referenceChildren.containsKey(prefixEntry.key)) {
675+
_referenceChildren[prefixEntry.key] = prefixEntry.value.first;
676+
}
677+
}
678+
}
679+
return _referenceChildren;
668680
}
669681

670682
@override

lib/src/model/package.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,18 @@ class Package extends LibraryContainer
408408
_referenceChildren = {};
409409
_referenceChildren
410410
.addEntries(allLibraries.map((l) => MapEntry(l.name, l)));
411+
// Do not override any preexisting data, and insert based on the
412+
// public library sort order.
413+
// TODO(jcollins-g): warn when results require package-global
414+
// lookups like this.
415+
for (var lib in publicLibrariesSorted) {
416+
for (var referableEntry in lib.referenceChildren.entries) {
417+
// Avoiding tearoffs for performance reasons.
418+
if (!_referenceChildren.containsKey(referableEntry.key)) {
419+
_referenceChildren[referableEntry.key] = referableEntry.value;
420+
}
421+
}
422+
}
411423
}
412424
return _referenceChildren;
413425
}

lib/src/model/package_graph.dart

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,26 +1030,39 @@ class PackageGraph with CommentReferable, Nameable {
10301030
Map<String, CommentReferable> get referenceChildren {
10311031
if (_referenceChildren == null) {
10321032
_referenceChildren = {};
1033-
1033+
// Packages are the top priority.
10341034
_referenceChildren.addEntries(packages.map((p) => MapEntry(p.name, p)));
1035-
// TODO(jcollins-g): deprecate and start warning for anything needing these
1036-
// elements.
1037-
var librariesWithCanonicals =
1038-
packages.expand((p) => referenceChildren.entries.where((e) {
1039-
var v = e.value;
1040-
return v is ModelElement
1041-
? v.canonicalModelElement != null
1042-
: true;
1043-
}));
1044-
var topLevelsWithCanonicals = librariesWithCanonicals
1045-
.expand((p) => referenceChildren.entries.where((e) {
1046-
var v = e.value;
1047-
return v is ModelElement
1048-
? v.canonicalModelElement != null
1049-
: true;
1050-
}));
1051-
_referenceChildren.addEntries(librariesWithCanonicals);
1052-
_referenceChildren.addEntries(topLevelsWithCanonicals);
1035+
1036+
// Libraries are next.
1037+
// TODO(jcollins-g): Warn about directly referencing libraries out of
1038+
// scope?
1039+
for (var p in documentedPackages) {
1040+
for (var lib in p.publicLibrariesSorted) {
1041+
if (!_referenceChildren.containsKey(lib.name)) {
1042+
_referenceChildren[lib.name] = lib;
1043+
}
1044+
}
1045+
}
1046+
// TODO(jcollins-g): Warn about directly referencing top level items
1047+
// out of scope?
1048+
for (var p in documentedPackages) {
1049+
for (var lib in p.publicLibrariesSorted) {
1050+
for (var me in [
1051+
...lib.publicConstants,
1052+
...lib.publicFunctions,
1053+
...lib.publicProperties,
1054+
...lib.publicTypedefs,
1055+
...lib.publicExtensions,
1056+
...lib.publicClasses,
1057+
...lib.publicEnums,
1058+
...lib.publicMixins
1059+
]) {
1060+
if (!_referenceChildren.containsKey(me.name)) {
1061+
_referenceChildren[me.name] = me;
1062+
}
1063+
}
1064+
}
1065+
}
10531066
}
10541067
return _referenceChildren;
10551068
}

test/comment_referable/parser_test.dart

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,36 @@ import 'package:test/test.dart';
77

88
void main() {
99
void expectParseEquivalent(String codeRef, List<String> parts,
10-
{bool constructorHint = false}) {
10+
{bool constructorHint = false, bool callableHint = false}) {
1111
var result = CommentReferenceParser(codeRef).parse();
12-
var hasHint = result.isNotEmpty &&
13-
(result.first is ConstructorHintStartNode ||
14-
result.last is CallableHintEndNode);
12+
var hasConstructorHint =
13+
result.isNotEmpty && result.first is ConstructorHintStartNode;
14+
var hasCallableHint =
15+
result.isNotEmpty && result.last is CallableHintEndNode;
1516
var stringParts = result.whereType<IdentifierNode>().map((i) => i.text);
1617
expect(stringParts, equals(parts));
17-
expect(hasHint, equals(constructorHint));
18+
expect(hasConstructorHint, equals(constructorHint));
19+
expect(hasCallableHint, equals(callableHint));
1820
}
1921

2022
void expectParsePassthrough(String codeRef) =>
2123
expectParseEquivalent(codeRef, [codeRef]);
2224

2325
void expectParseError(String codeRef) {
24-
expect(CommentReferenceParser(codeRef).parse(), isEmpty);
26+
expect(CommentReferenceParser(codeRef).parse().whereType<IdentifierNode>(),
27+
isEmpty);
2528
}
2629

2730
group('Basic comment reference parsing', () {
2831
test('Check that basic references parse', () {
2932
expectParseEquivalent('valid', ['valid']);
3033
expectParseEquivalent('new valid', ['valid'], constructorHint: true);
31-
expectParseEquivalent('valid()', ['valid'], constructorHint: true);
32-
expectParseEquivalent('const valid()', ['valid'], constructorHint: true);
34+
expectParseEquivalent('valid()', ['valid'], callableHint: true);
35+
expectParseEquivalent('const valid()', ['valid'], callableHint: true);
3336
expectParseEquivalent('final valid', ['valid']);
3437
expectParseEquivalent('this.is.valid', ['this', 'is', 'valid']);
3538
expectParseEquivalent('this.is.valid()', ['this', 'is', 'valid'],
36-
constructorHint: true);
39+
callableHint: true);
3740
expectParseEquivalent('new this.is.valid', ['this', 'is', 'valid'],
3841
constructorHint: true);
3942
expectParseEquivalent('const this.is.valid', ['this', 'is', 'valid']);
@@ -46,6 +49,19 @@ void main() {
4649
expectParseEquivalent('this.is.valid(things)', ['this', 'is', 'valid']);
4750
});
4851

52+
test('Check that cases dependent on prefix resolution not firing parse',
53+
() {
54+
expectParsePassthrough('constant');
55+
expectParsePassthrough('newThingy');
56+
expectParsePassthrough('operatorThingy');
57+
expectParseEquivalent('operator+', ['+']);
58+
expectParseError('const()');
59+
// TODO(jcollins-g): might need to revisit these two with constructor
60+
// tearoffs?
61+
expectParsePassthrough('new');
62+
expectParseError('new()');
63+
});
64+
4965
test('Check that operator references parse', () {
5066
expectParsePassthrough('[]');
5167
expectParsePassthrough('<=');

test/end2end/model_test.dart

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,12 +2137,17 @@ void main() {
21372137
nameWithSingleUnderscore,
21382138
theOnlyThingInTheLibrary;
21392139
Constructor aNonDefaultConstructor, defaultConstructor;
2140-
Class Apple, BaseClass, baseForDocComments, ExtraSpecialList, string;
2140+
Class Apple,
2141+
BaseClass,
2142+
baseForDocComments,
2143+
ExtraSpecialList,
2144+
string,
2145+
metaUseResult;
21412146
Method doAwesomeStuff, anotherMethod;
21422147
// ignore: unused_local_variable
21432148
Operator bracketOperator, bracketOperatorOtherClass;
21442149
Parameter doAwesomeStuffParam;
2145-
Field forInheriting, action, initializeMe;
2150+
Field forInheriting, action, initializeMe, somethingShadowy;
21462151

21472152
setUpAll(() async {
21482153
nameWithTwoUnderscores = fakeLibrary.constants
@@ -2153,6 +2158,10 @@ void main() {
21532158
.firstWhere((e) => e.name == 'dart:core')
21542159
.allClasses
21552160
.firstWhere((c) => c.name == 'String');
2161+
metaUseResult = packageGraph.allLibraries.values
2162+
.firstWhere((e) => e.name == 'meta')
2163+
.allClasses
2164+
.firstWhere((c) => c.name == 'UseResult');
21562165
baseForDocComments =
21572166
fakeLibrary.classes.firstWhere((c) => c.name == 'BaseForDocComments');
21582167
aNonDefaultConstructor = baseForDocComments.constructors.firstWhere(
@@ -2161,6 +2170,8 @@ void main() {
21612170
.firstWhere((c) => c.name == 'BaseForDocComments');
21622171
initializeMe = baseForDocComments.allFields
21632172
.firstWhere((f) => f.name == 'initializeMe');
2173+
somethingShadowy = baseForDocComments.allFields
2174+
.firstWhere((f) => f.name == 'somethingShadowy');
21642175
doAwesomeStuff = baseForDocComments.instanceMethods
21652176
.firstWhere((m) => m.name == 'doAwesomeStuff');
21662177
anotherMethod = baseForDocComments.instanceMethods
@@ -2248,12 +2259,23 @@ void main() {
22482259
equals(MatchingLinkResult(aNonDefaultConstructor)));
22492260
});
22502261

2262+
test('Deprecated lookup styles still function', () {
2263+
// dart-lang/dartdoc#2683
2264+
expect(bothLookup(baseForDocComments, 'aPrefix.UseResult'),
2265+
equals(MatchingLinkResult(metaUseResult)));
2266+
});
2267+
22512268
test('Verify basic linking inside class', () {
22522269
expect(
22532270
bothLookup(
22542271
baseForDocComments, 'BaseForDocComments.BaseForDocComments'),
22552272
equals(MatchingLinkResult(defaultConstructor)));
22562273

2274+
// We don't want the parameter on the default constructor, here.
2275+
expect(
2276+
bothLookup(baseForDocComments, 'BaseForDocComments.somethingShadowy'),
2277+
equals(MatchingLinkResult(somethingShadowy)));
2278+
22572279
expect(bothLookup(doAwesomeStuff, 'aNonDefaultConstructor'),
22582280
equals(MatchingLinkResult(aNonDefaultConstructor)));
22592281

@@ -2311,8 +2333,7 @@ void main() {
23112333
equals(MatchingLinkResult(theOnlyThingInTheLibrary)));
23122334

23132335
// A name that exists in this package but is not imported.
2314-
// TODO(jcollins-g): package-wide lookups are not yet implemented with the new lookup code.
2315-
expect(originalLookup(doAwesomeStuff, 'doesStuff'),
2336+
expect(bothLookup(doAwesomeStuff, 'doesStuff'),
23162337
equals(MatchingLinkResult(doesStuff)));
23172338

23182339
// A name of a class from an import of a library that exported that name.
@@ -2339,8 +2360,7 @@ void main() {
23392360
equals(MatchingLinkResult(forInheriting)));
23402361

23412362
// Reference to an inherited member in another library via class name.
2342-
// TODO(jcollins-g): reference to non-imported symbols isn't implemented yet in new lookup.
2343-
expect(originalLookup(doAwesomeStuff, 'ExtendedBaseReexported.action'),
2363+
expect(bothLookup(doAwesomeStuff, 'ExtendedBaseReexported.action'),
23442364
equals(MatchingLinkResult(action)));
23452365
});
23462366
});

testing/test_package/lib/fake.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import 'dart:collection';
5555
// ignore: uri_does_not_exist
5656
//import 'dart:json' as invalidPrefix;
5757
import 'package:meta/meta.dart' show Required;
58+
import 'package:meta/meta.dart' as aPrefix show Immutable;
5859
import 'csspub.dart' as css;
5960
import 'csspub.dart' as renamedLib2;
6061
import 'package:test_package/src//import_unusual.dart';
@@ -962,7 +963,9 @@ class BaseForDocComments {
962963

963964
final bool initializeMe;
964965

965-
BaseForDocComments(this.initializeMe);
966+
int somethingShadowy;
967+
968+
BaseForDocComments(this.initializeMe, [bool somethingShadowy]);
966969

967970
BaseForDocComments.aNonDefaultConstructor(this.initializeMe);
968971

0 commit comments

Comments
 (0)