Skip to content

Commit e486b13

Browse files
authored
Fix regression in canonicalization from extension methods (#2179)
* Return the canonical element we bothered to spend time looking for. * Fix enums too * Add test for canonicalization edge case
1 parent 086815c commit e486b13

File tree

7 files changed

+65
-18
lines changed

7 files changed

+65
-18
lines changed

lib/src/model/container_member.dart

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,6 @@ import 'package:dartdoc/src/model/model.dart';
66

77
/// A [ModelElement] that is a [Container] member.
88
mixin ContainerMember on ModelElement implements EnclosedElement {
9-
/// True if this [ContainerMember] is inherited from a different class.
10-
bool get isInherited;
11-
12-
/// True if this [ContainerMember] is overriding a superclass.
13-
bool get isOverride;
14-
15-
/// True if this [ContainerMember] has a parameter whose type is overridden
16-
/// by a subtype.
17-
bool get isCovariant;
18-
199
/// True if this [ContainerMember] is from an applicable [Extension].
2010
/// False otherwise, including if this [ContainerMember]'s [enclosingElement]
2111
/// is the extension it was declared in.
@@ -39,9 +29,6 @@ mixin ContainerMember on ModelElement implements EnclosedElement {
3929
@override
4030
Set<String> get features {
4131
Set<String> _features = super.features;
42-
if (isOverride) _features.add('override');
43-
if (isInherited) _features.add('inherited');
44-
if (isCovariant) _features.add('covariant');
4532
if (isExtended) _features.add('extended');
4633
return _features;
4734
}
@@ -61,11 +48,14 @@ mixin ContainerMember on ModelElement implements EnclosedElement {
6148

6249
Container computeCanonicalEnclosingContainer() {
6350
// TODO(jcollins-g): move Extension specific code to [Extendable]
64-
if (enclosingElement is! Extension ||
65-
(enclosingElement is Extension && enclosingElement.isDocumented)) {
51+
if (enclosingElement is Extension && enclosingElement.isDocumented) {
6652
return packageGraph
6753
.findCanonicalModelElementFor(enclosingElement.element);
6854
}
55+
if (enclosingElement is! Extension) {
56+
return packageGraph
57+
.findCanonicalModelElementFor(element.enclosingElement);
58+
}
6959
return null;
7060
}
7161
}

lib/src/model/inheritable.dart

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,28 @@ import 'package:dartdoc/src/special_elements.dart';
2121
/// place in the documentation, and we pick a canonical class because that's
2222
/// the one in the public namespace that will be documented.
2323
mixin Inheritable on ContainerMember {
24+
/// True if this [Inheritable] is inherited from a different class.
25+
bool get isInherited;
26+
27+
/// True if this [Inheritable] has a parameter whose type is overridden
28+
/// by a subtype.
29+
bool get isCovariant;
30+
31+
@override
32+
Set<String> get features {
33+
Set<String> _features = super.features;
34+
if (isOverride) _features.add('override');
35+
if (isInherited) _features.add('inherited');
36+
if (isCovariant) _features.add('covariant');
37+
return _features;
38+
}
39+
40+
@override
41+
Library get canonicalLibrary => canonicalEnclosingContainer?.canonicalLibrary;
42+
2443
@override
2544
ModelElement buildCanonicalModelElement() {
45+
// TODO(jcollins-g): factor out extension logic into [Extendable]
2646
if (canonicalEnclosingContainer is Extension) {
2747
return this;
2848
}
@@ -34,6 +54,9 @@ mixin Inheritable on ContainerMember {
3454
m.name == name && m.isPropertyAccessor == isPropertyAccessor,
3555
orElse: () => null);
3656
}
57+
if (canonicalEnclosingContainer != null) {
58+
throw UnimplementedError('${canonicalEnclosingContainer}: unknown type');
59+
}
3760
return null;
3861
}
3962

@@ -77,8 +100,14 @@ mixin Inheritable on ContainerMember {
77100
if (definingEnclosingContainer.isCanonical &&
78101
definingEnclosingContainer.isPublic) {
79102
assert(definingEnclosingContainer == found);
103+
}
104+
if (found != null) {
80105
return found;
81106
}
107+
} else if (!isInherited && definingEnclosingContainer is! Extension) {
108+
// TODO(jcollins-g): factor out extension logic into [Extendable].
109+
return packageGraph
110+
.findCanonicalModelElementFor(element.enclosingElement);
82111
}
83112
return super.computeCanonicalEnclosingContainer();
84113
}
@@ -104,7 +133,7 @@ mixin Inheritable on ContainerMember {
104133

105134
bool _isOverride;
106135

107-
@override
136+
/// True if this [Inheritable] is overriding a superclass.
108137
bool get isOverride {
109138
if (_isOverride == null) {
110139
// The canonical version of the enclosing element -- not canonicalEnclosingElement,

lib/src/model/model_element.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,7 @@ abstract class ModelElement extends Canonicalization
647647
if (!_canonicalLibraryIsSet) {
648648
// This is not accurate if we are constructing the Package.
649649
assert(packageGraph.allLibrariesAdded);
650-
// Since we're may be looking for a library, find the [Element] immediately
650+
// Since we're looking for a library, find the [Element] immediately
651651
// contained by a [CompilationUnitElement] in the tree.
652652
Element topLevelElement = element;
653653
while (topLevelElement != null &&

test/model_test.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,17 @@ void main() {
13891389
});
13901390

13911391
group('Class edge cases', () {
1392+
test('Inherit from private class across private library to public library',
1393+
() {
1394+
Class GadgetExtender = packageGraph.localPublicLibraries
1395+
.firstWhere((l) => l.name == 'gadget_extender')
1396+
.allClasses
1397+
.firstWhere((c) => c.name == 'GadgetExtender');
1398+
Field gadgetGetter =
1399+
GadgetExtender.allFields.firstWhere((f) => f.name == 'gadgetGetter');
1400+
expect(gadgetGetter.isCanonical, isTrue);
1401+
});
1402+
13921403
test(
13931404
'ExecutableElements from private classes and from public interfaces (#1561)',
13941405
() {

test/src/utils.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import 'package:path/path.dart' as path;
1717
/// The number of public libraries in testing/test_package, minus 2 for
1818
/// the excluded libraries listed in the initializers for _testPackageGraphMemo
1919
/// and minus 1 for the <nodoc> tag in the 'excluded' library.
20-
const int kTestPackagePublicLibraries = 15;
20+
const int kTestPackagePublicLibraries = 16;
2121

2222
final RegExp quotables = RegExp(r'[ "\r\n\$]');
2323
final RegExp observatoryPortRegexp =
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'src/gadget.dart';
6+
7+
class GadgetExtender extends Gadget {}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
class _GadgetBase {
6+
int get gadgetGetter => 5;
7+
}
8+
9+
10+
class Gadget extends _GadgetBase {}

0 commit comments

Comments
 (0)