Skip to content

Commit e7f3694

Browse files
authored
Start using docImport resolution when resolving references (#3805)
1 parent 9d756dc commit e7f3694

File tree

7 files changed

+73
-46
lines changed

7 files changed

+73
-46
lines changed

lib/src/model/comment_referable.dart

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import 'dart:core';
1010
import 'package:analyzer/dart/element/element.dart';
1111
import 'package:analyzer/dart/element/scope.dart';
1212
import 'package:collection/collection.dart';
13-
import 'package:dartdoc/src/model/container.dart';
1413
import 'package:dartdoc/src/model/library.dart';
1514
import 'package:dartdoc/src/model/model_element.dart';
1615
import 'package:dartdoc/src/model/nameable.dart';
@@ -53,12 +52,13 @@ mixin CommentReferable implements Nameable {
5352
return tryParents ? null : this;
5453
}
5554
for (var referenceLookup in _childLookups(reference)) {
56-
if (scope != null) {
57-
var result = _lookupViaScope(referenceLookup, filter: filter);
58-
if (result != null) {
59-
return result;
60-
}
55+
// First attempt: Ask analyzer's `Scope.lookup` API.
56+
var result = _lookupViaScope(referenceLookup, filter: filter);
57+
if (result != null) {
58+
return result;
6159
}
60+
61+
// Second attempt: Look through `referenceChildren`.
6262
final referenceChildren = this.referenceChildren;
6363
final childrenResult = referenceChildren[referenceLookup.lookup];
6464
if (childrenResult != null) {
@@ -97,27 +97,40 @@ mixin CommentReferable implements Nameable {
9797
_ReferenceChildrenLookup referenceLookup, {
9898
required bool Function(CommentReferable?) filter,
9999
}) {
100-
final resultElement = scope!.lookupPreferGetter(referenceLookup.lookup);
101-
if (resultElement == null) return null;
100+
Element? resultElement;
101+
final scope = this.scope;
102+
if (scope != null) {
103+
resultElement = scope.lookupPreferGetter(referenceLookup.lookup);
104+
if (resultElement == null) return null;
105+
}
106+
107+
if (this case ModelElement(:var modelNode?) when resultElement == null) {
108+
var references = modelNode.commentData?.references;
109+
if (references != null) {
110+
resultElement = references[referenceLookup.lookup]?.element;
111+
}
112+
}
113+
114+
if (resultElement == null) {
115+
return null;
116+
}
117+
102118
ModelElement result;
103119
if (resultElement is PropertyAccessorElement) {
104120
final variable = resultElement.variable2!;
105121
if (variable.isSynthetic) {
122+
// First, cache the synthetic variable, so that the
123+
// PropertyAccessorElement getter and/or setter are set (see
124+
// `Field.new` regarding `enclosingCombo`).
125+
packageGraph.getModelForElement(variable);
126+
// Then, use the result for the PropertyAccessorElement.
106127
result = packageGraph.getModelForElement(resultElement);
107128
} else {
108129
result = packageGraph.getModelForElement(variable);
109130
}
110131
} else {
111132
result = packageGraph.getModelForElement(resultElement);
112133
}
113-
if (result.enclosingElement is Container) {
114-
assert(
115-
false,
116-
'[Container] member detected, support not implemented for analyzer '
117-
'scope inside containers',
118-
);
119-
return null;
120-
}
121134
return _recurseChildrenAndFilter(referenceLookup, result, filter: filter);
122135
}
123136

lib/src/model/extension.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ class Extension extends Container {
7575
setter = ContainerAccessor(fieldSetter, library, packageGraph);
7676
}
7777
return getModelForPropertyInducingElement(field, library,
78-
getter: getter, setter: setter) as Field;
78+
getter: getter, setter: setter, enclosingContainer: this) as Field;
7979
}).toList(growable: false);
8080

8181
@override

lib/src/model/inheriting_container.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@ abstract class InheritingContainer extends Container {
566566
(setter == null || setter.isInherited)) {
567567
// Field is 100% inherited.
568568
return getModelForPropertyInducingElement(field, library,
569-
enclosingContainer: this, getter: getter, setter: setter) as Field;
569+
getter: getter, setter: setter, enclosingContainer: this) as Field;
570570
} else {
571571
// Field is <100% inherited (could be half-inherited).
572572
// TODO(jcollins-g): Navigation is probably still confusing for

lib/src/model/model_element.dart

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,15 @@ abstract class ModelElement
133133
}
134134

135135
ModelElement newModelElement;
136-
if (e is FieldElement) {
137-
if (enclosingContainer == null) {
136+
if (e is TopLevelVariableElement) {
137+
assert(getter != null || setter != null);
138+
newModelElement =
139+
TopLevelVariable(e, library, packageGraph, getter, setter);
140+
} else if (e is FieldElement) {
141+
if (enclosingContainer is Extension) {
142+
newModelElement = Field(e, library, packageGraph,
143+
getter as ContainerAccessor?, setter as ContainerAccessor?);
144+
} else if (enclosingContainer == null) {
138145
if (e.isEnumConstant) {
139146
var constantValue = e.computeConstantValue();
140147
if (constantValue == null) {
@@ -157,7 +164,6 @@ abstract class ModelElement
157164
getter as ContainerAccessor?, setter as ContainerAccessor?);
158165
}
159166
} else {
160-
// EnumFields can't be inherited, so this case is simpler.
161167
newModelElement = Field.inherited(
162168
e,
163169
enclosingContainer,
@@ -167,16 +173,11 @@ abstract class ModelElement
167173
setter as ContainerAccessor?,
168174
);
169175
}
170-
} else if (e is TopLevelVariableElement) {
171-
assert(getter != null || setter != null);
172-
newModelElement =
173-
TopLevelVariable(e, library, packageGraph, getter, setter);
174176
} else {
175177
throw UnimplementedError(
176178
'Unrecognized property inducing element: $e (${e.runtimeType})');
177179
}
178180

179-
if (enclosingContainer != null) assert(newModelElement is Inheritable);
180181
_cacheNewModelElement(e, newModelElement, library,
181182
enclosingContainer: enclosingContainer);
182183

@@ -193,8 +194,6 @@ abstract class ModelElement
193194
// clean that up.
194195
// TODO(jcollins-g): Enforce construction restraint.
195196
// TODO(jcollins-g): Allow e to be null and drop extraneous null checks.
196-
// TODO(jcollins-g): Auto-vivify element's defining library for library
197-
// parameter when given a null.
198197
factory ModelElement.for_(
199198
Element e, Library library, PackageGraph packageGraph,
200199
{Container? enclosingContainer}) {

test/end2end/model_test.dart

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2317,8 +2317,7 @@ void main() async {
23172317
late final Class TypeParameterThings,
23182318
TypeParameterThingsExtended,
23192319
TypeParameterThingsExtendedQ;
2320-
late final Extension UnboundTypeTargetExtension;
2321-
late final Field aName, aThing, doesNotCrash;
2320+
late final Field aName, aThing;
23222321
late final TypeParameter ATypeParam,
23232322
BTypeParam,
23242323
CTypeParam,
@@ -2329,11 +2328,6 @@ void main() async {
23292328
late final ModelFunction aTopLevelTypeParameterFunction;
23302329

23312330
setUpAll(() {
2332-
UnboundTypeTargetExtension =
2333-
fakeLibrary.extensions.named('UnboundTypeTargetExtension');
2334-
doesNotCrash =
2335-
UnboundTypeTargetExtension.instanceFields.named('doesNotCrash');
2336-
23372331
aTopLevelTypeParameterFunction =
23382332
fakeLibrary.functions.named('aTopLevelTypeParameterFunction');
23392333
// TODO(jcollins-g): dart-lang/dartdoc#2704, HTML and type parameters
@@ -2368,11 +2362,6 @@ void main() async {
23682362
QTypeParam = aMethodExtendedQ.typeParameters.named('QTypeParam');
23692363
});
23702364

2371-
test('on extension targeting an unbound type', () {
2372-
expect(referenceLookup(UnboundTypeTargetExtension, 'doesNotCrash'),
2373-
equals(MatchingLinkResult(doesNotCrash)));
2374-
});
2375-
23762365
test('on inherited documentation', () {
23772366
expect(referenceLookup(aMethodExtended, 'ATypeParam'),
23782367
equals(MatchingLinkResult(ATypeParam)));

test/extensions_test.dart

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,38 @@ var f() {}
5353
);
5454
}
5555

56+
void test_referenceToExtensionGetter() async {
57+
var library = await bootPackageWithLibrary('''
58+
extension Ex on int {
59+
bool get b => true;
60+
}
61+
62+
/// Text [Ex.b].
63+
var f() {}
64+
''');
65+
66+
expect(
67+
library.functions.named('f').documentationAsHtml,
68+
contains('<a href="$linkPrefix/Ex/b.html">Ex.b</a>'),
69+
);
70+
}
71+
72+
void test_referenceToExtensionSetter() async {
73+
var library = await bootPackageWithLibrary('''
74+
extension Ex on int {
75+
set b(int value) {}
76+
}
77+
78+
/// Text [Ex.b].
79+
var f() {}
80+
''');
81+
82+
expect(
83+
library.functions.named('f').documentationAsHtml,
84+
contains('<a href="$linkPrefix/Ex/b.html">Ex.b</a>'),
85+
);
86+
}
87+
5688
// TODO(srawlins): Test everything else about extensions.
5789
}
5890

testing/test_package/lib/fake.dart

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1076,12 +1076,6 @@ extension Leg on Megatron<String> {
10761076
bool get hasRightLeg => true;
10771077
}
10781078

1079-
/// Refer to [doesNotCrash] here.
1080-
extension UnboundTypeTargetExtension<T> on T {
1081-
/// We hope so!
1082-
bool get doesNotCrash => true;
1083-
}
1084-
10851079
class Megatron<T> {}
10861080

10871081
class SuperMegaTron<T extends String> extends Megatron<String> {}

0 commit comments

Comments
 (0)