Skip to content

Commit c851212

Browse files
authored
Basic .new support for constructors (#2766)
* partial * Delete the lookup code itself * obliterate all the 'everything' tables that supported the old lookup code * dartfmt * dartfmt * revert erroneous/non-working const stuff for a later PR * Remove some broken tests and tweak the grinder slightly
1 parent b22cd23 commit c851212

File tree

6 files changed

+64
-43
lines changed

6 files changed

+64
-43
lines changed

lib/src/comment_references/model_comment_reference.dart

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,10 @@ import 'package:analyzer/file_system/file_system.dart';
88
import 'package:dartdoc/src/comment_references/parser.dart';
99

1010
abstract class ModelCommentReference {
11-
/// Does the structure of the reference itself imply a possible default
11+
/// Does the structure of the reference itself imply a possible unnamed
1212
/// constructor?
13-
// TODO(jcollins-g): rewrite/discard this once default constructor tear-off
14-
// design process is complete.
15-
bool get allowDefaultConstructor;
16-
bool get allowDefaultConstructorParameter;
13+
bool get allowUnnamedConstructor;
14+
bool get allowUnnamedConstructorParameter;
1715
String get codeRef;
1816
bool get hasConstructorHint;
1917
bool get hasCallableHint;
@@ -34,42 +32,45 @@ abstract class ModelCommentReference {
3432
/// information needed for Dartdoc. Drops link to the [CommentReference]
3533
/// and [ResourceProvider] after construction.
3634
class _ModelCommentReferenceImpl implements ModelCommentReference {
37-
bool _allowDefaultConstructor;
35+
bool _allowUnnamedConstructor;
3836

3937
void _initAllowCache() {
4038
var referencePieces = parsed.whereType<IdentifierNode>().toList();
41-
_allowDefaultConstructor = false;
42-
_allowDefaultConstructorParameter = false;
39+
_allowUnnamedConstructor = false;
40+
_allowUnnamedConstructorParameter = false;
4341
if (referencePieces.length >= 2) {
4442
IdentifierNode nodeLast;
4543
for (var f in referencePieces) {
4644
if (f.text == nodeLast?.text) {
4745
if (identical(referencePieces.last, f)) {
48-
_allowDefaultConstructor = true;
46+
_allowUnnamedConstructor = true;
4947
} else {
50-
_allowDefaultConstructorParameter = true;
48+
_allowUnnamedConstructorParameter = true;
5149
}
5250
}
5351
nodeLast = f;
5452
}
53+
if (referencePieces.last.text == 'new') {
54+
_allowUnnamedConstructor = true;
55+
}
5556
}
5657
}
5758

5859
@override
59-
bool get allowDefaultConstructor {
60-
if (_allowDefaultConstructor == null) {
60+
bool get allowUnnamedConstructor {
61+
if (_allowUnnamedConstructor == null) {
6162
_initAllowCache();
6263
}
63-
return _allowDefaultConstructor;
64+
return _allowUnnamedConstructor;
6465
}
6566

66-
bool _allowDefaultConstructorParameter;
67+
bool _allowUnnamedConstructorParameter;
6768
@override
68-
bool get allowDefaultConstructorParameter {
69-
if (_allowDefaultConstructorParameter == null) {
69+
bool get allowUnnamedConstructorParameter {
70+
if (_allowUnnamedConstructorParameter == null) {
7071
_initAllowCache();
7172
}
72-
return _allowDefaultConstructorParameter;
73+
return _allowUnnamedConstructorParameter;
7374
}
7475

7576
@override

lib/src/markdown_processor.dart

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,14 +157,12 @@ class _IterableBlockParser extends md.BlockParser {
157157
}
158158
}
159159

160-
/// Return false if the passed [referable] is a default [Constructor],
160+
/// Return false if the passed [referable] is an unnamed [Constructor],
161161
/// or if it is shadowing another type of element, or is a parameter of
162162
/// one of the above.
163-
bool _rejectDefaultAndShadowingConstructors(CommentReferable referable) {
163+
bool _rejectUnnamedAndShadowingConstructors(CommentReferable referable) {
164164
if (referable is Constructor) {
165-
if (referable.name == referable.enclosingElement.name) {
166-
return false;
167-
}
165+
if (referable.isUnnamedConstructor) return false;
168166
if (referable.enclosingElement
169167
.referenceChildren[referable.name.split('.').last] is! Constructor) {
170168
return false;
@@ -191,12 +189,12 @@ MatchingLinkResult _getMatchingLinkElementCommentReferable(
191189
bool Function(CommentReferable) filter;
192190
bool Function(CommentReferable) allowTree;
193191

194-
// Constructor references are pretty ambiguous by nature since they are
192+
// Constructor references are pretty ambiguous by nature since they can be
195193
// declared with the same name as the class they are constructing, and even
196194
// if they don't use field-formal parameters, sometimes have parameters
197195
// named the same as members.
198196
// Maybe clean this up with inspiration from constructor tear-off syntax?
199-
if (commentReference.allowDefaultConstructor) {
197+
if (commentReference.allowUnnamedConstructor) {
200198
// Neither reject, nor require, a default constructor in the event
201199
// the comment reference structure implies one. (We can not require it
202200
// in case a library name is the same as a member class name and the class
@@ -212,12 +210,12 @@ MatchingLinkResult _getMatchingLinkElementCommentReferable(
212210
// Trailing parens indicate we are looking for a callable.
213211
filter = _requireCallable;
214212
} else {
215-
// Without hints, reject default constructors and their parameters to force
213+
// Without hints, reject unnamed constructors and their parameters to force
216214
// resolution to the class.
217-
filter = _rejectDefaultAndShadowingConstructors;
215+
filter = _rejectUnnamedAndShadowingConstructors;
218216

219-
if (!commentReference.allowDefaultConstructorParameter) {
220-
allowTree = _rejectDefaultAndShadowingConstructors;
217+
if (!commentReference.allowUnnamedConstructorParameter) {
218+
allowTree = _rejectUnnamedAndShadowingConstructors;
221219
}
222220
}
223221

lib/src/model/class.dart

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,15 @@ class Class extends Container
7070
return _unnamedConstructor;
7171
}
7272

73-
@Deprecated(
74-
'Renamed to `unnamedConstructor`; this getter with the old name will be '
75-
'removed as early as Dartdoc 1.0.0')
76-
Constructor get defaultConstructor => unnamedConstructor;
73+
Constructor _defaultConstructor;
74+
75+
/// With constructor tearoffs, this is no longer equivalent to the unnamed
76+
/// constructor and assumptions based on that are incorrect.
77+
Constructor get defaultConstructor {
78+
_defaultConstructor ??= unnamedConstructor ??
79+
constructors.firstWhere((c) => c.isDefaultConstructor);
80+
return _defaultConstructor;
81+
}
7782

7883
@override
7984
Iterable<Method> get instanceMethods =>
@@ -613,8 +618,11 @@ class Class extends Container
613618
for (var constructor in source) {
614619
yield MapEntry(constructor.referenceName, constructor);
615620
yield MapEntry(
616-
'${constructor.enclosingElement.name}.${constructor.referenceName}',
621+
'${constructor.enclosingElement.referenceName}.${constructor.referenceName}',
617622
constructor);
623+
if (constructor.isDefaultConstructor) {
624+
yield MapEntry('new', constructor);
625+
}
618626
}
619627
}
620628

lib/src/model/constructor.dart

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,16 +67,10 @@ class Constructor extends ModelElement
6767
@override
6868
bool get isConst => element.isConst;
6969

70-
bool get isUnnamedConstructor =>
71-
name == enclosingElement.name || name == '${enclosingElement.name}.new';
72-
73-
@Deprecated(
74-
// TODO(jcollins-g): This, in retrospect, seems like a bad idea.
75-
// We should disambiguate the two concepts (default and unnamed) and
76-
// allow both if useful.
77-
'Renamed to `isUnnamedConstructor`; this getter with the old name will '
78-
'be removed as early as Dartdoc 1.0.0')
79-
bool get isDefaultConstructor => isUnnamedConstructor;
70+
bool get isUnnamedConstructor => name == enclosingElement.name;
71+
72+
bool get isDefaultConstructor =>
73+
name == '${enclosingElement.name}.new' || isUnnamedConstructor;
8074

8175
bool get isFactory => element.isFactory;
8276

test/end2end/model_special_cases_test.dart

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,21 @@ void main() {
171171
expect(referenceLookup(constructorTearoffs, 'F()'),
172172
equals(MatchingLinkResult(Fnew)));
173173
});
174+
175+
test('.new works on classes', () {
176+
expect(referenceLookup(constructorTearoffs, 'A.new'),
177+
equals(MatchingLinkResult(Anew)));
178+
expect(referenceLookup(constructorTearoffs, 'B.new'),
179+
equals(MatchingLinkResult(Bnew)));
180+
expect(referenceLookup(constructorTearoffs, 'C.new'),
181+
equals(MatchingLinkResult(Cnew)));
182+
expect(referenceLookup(constructorTearoffs, 'D.new'),
183+
equals(MatchingLinkResult(Dnew)));
184+
expect(referenceLookup(constructorTearoffs, 'E.new'),
185+
equals(MatchingLinkResult(Enew)));
186+
expect(referenceLookup(constructorTearoffs, 'F.new'),
187+
equals(MatchingLinkResult(Fnew)));
188+
});
174189
}, skip: !_constructorTearoffsAllowed.allows(utils.platformVersion));
175190
});
176191

tool/grind.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,11 +232,16 @@ void updateThirdParty() async {
232232
}
233233

234234
@Task('Analyze dartdoc to ensure there are no errors and warnings')
235+
@Depends(analyzeTestPackages)
235236
void analyze() async {
236237
await SubprocessLauncher('analyze').runStreamed(
237238
sdkBin('dartanalyzer'),
238239
['--fatal-infos', '--options', 'analysis_options_presubmit.yaml', '.'],
239240
);
241+
}
242+
243+
@Task('Analyze the test packages')
244+
void analyzeTestPackages() async {
240245
var testPackagePaths = [testPackage.path];
241246
if (Platform.version.contains('dev')) {
242247
testPackagePaths.add(testPackageExperiments.path);

0 commit comments

Comments
 (0)