@@ -127,8 +127,8 @@ final RegExp trailingIgnoreStuff = new RegExp(r'(<.*>|\(.*\))$');
127
127
final RegExp leadingIgnoreStuff =
128
128
new RegExp (r'^(const|final|var)[\s]+' , multiLine: true );
129
129
130
- // This is explicitly intended as a reference to a constructor.
131
- final RegExp isConstructor = new RegExp (r'^new[\s]+' , multiLine: true );
130
+ // If found, this may be intended as a reference to a constructor.
131
+ final RegExp isConstructor = new RegExp (r'( ^new[\s]+|\(\)$) ' , multiLine: true );
132
132
133
133
// This is probably not really intended as a doc reference, so don't try or
134
134
// warn about them.
@@ -299,12 +299,45 @@ class _MarkdownCommentReference {
299
299
assert (element != null );
300
300
assert (element.packageGraph.allLibrariesAdded);
301
301
302
- codeRefChomped = codeRef.replaceFirst (isConstructor, '' );
302
+ codeRefChomped = codeRef.replaceAll (isConstructor, '' );
303
303
library =
304
304
element is ModelElement ? (element as ModelElement ).library : null ;
305
305
packageGraph = library.packageGraph;
306
306
}
307
307
308
+ String __impliedDefaultConstructor;
309
+ bool __impliedDefaultConstructorIsSet = false ;
310
+
311
+ /// Returns the name of the implied default constructor if there is one, or
312
+ /// null if not.
313
+ ///
314
+ /// Default constructors are a special case in dartdoc. If we look up a name
315
+ /// within a class of that class itself, the first thing we find is the
316
+ /// default constructor. But we determine whether that's what they actually
317
+ /// intended (vs. the enclosing class) by context -- whether they seem
318
+ /// to be calling it with () or have a 'new' in front of it, or
319
+ /// whether the name is repeated.
320
+ ///
321
+ /// Similarly, referencing a class by itself might actually refer to its
322
+ /// constructor based on these same heuristics.
323
+ ///
324
+ /// With the name of the implied default constructor, other methods can
325
+ /// determine whether or not the constructor and/or class we resolved to
326
+ /// is actually matching the user's intent.
327
+ String get _impliedDefaultConstructor {
328
+ if (! __impliedDefaultConstructorIsSet) {
329
+ __impliedDefaultConstructorIsSet = true ;
330
+ if (codeRef.contains (isConstructor) ||
331
+ (codeRefChompedParts.length >= 2 &&
332
+ codeRefChompedParts[codeRefChompedParts.length - 1 ] ==
333
+ codeRefChompedParts[codeRefChompedParts.length - 2 ])) {
334
+ // If the last two parts of the code reference are equal, this is probably a default constructor.
335
+ __impliedDefaultConstructor = codeRefChompedParts.last;
336
+ }
337
+ }
338
+ return __impliedDefaultConstructor;
339
+ }
340
+
308
341
/// Calculate reference to a ModelElement.
309
342
///
310
343
/// Uses a series of calls to the _find* methods in this class to get one
@@ -318,8 +351,6 @@ class _MarkdownCommentReference {
318
351
for (void Function () findMethod in [
319
352
// This might be an operator. Strip the operator prefix and try again.
320
353
_findWithoutOperatorPrefix,
321
- // Oh, and someone might have some type parameters or other garbage.
322
- _findWithoutTrailingIgnoreStuff,
323
354
// Oh, and someone might have thrown on a 'const' or 'final' in front.
324
355
_findWithoutLeadingIgnoreStuff,
325
356
// Maybe this ModelElement has parameters, and this is one of them.
@@ -330,6 +361,8 @@ class _MarkdownCommentReference {
330
361
_findTypeParameters,
331
362
// This could be local to the class, look there first.
332
363
_findWithinTryClasses,
364
+ // This could be a reference to a renamed library.
365
+ _findReferenceFromPrefixes,
333
366
// We now need the ref element cache to keep from repeatedly searching [Package.allModelElements].
334
367
// But if not, look for a fully qualified match. (That only makes sense
335
368
// if the codeRef might be qualified, and contains periods.)
@@ -340,8 +373,12 @@ class _MarkdownCommentReference {
340
373
_findGlobalWithinRefElementCache,
341
374
// This could conceivably be a reference to an enum member. They don't show up in allModelElements.
342
375
_findEnumReferences,
376
+ // Oh, and someone might have some type parameters or other garbage.
377
+ // After finding within classes because sometimes parentheses are used
378
+ // to imply constructors.
379
+ _findWithoutTrailingIgnoreStuff,
343
380
// Use the analyzer to resolve a comment reference.
344
- _findAnalyzerReferences
381
+ _findAnalyzerReferences,
345
382
]) {
346
383
findMethod ();
347
384
// Remove any "null" objects after each step of trying to add to results.
@@ -355,8 +392,6 @@ class _MarkdownCommentReference {
355
392
// This isn't C++. References to class methods are slightly expensive
356
393
// in Dart so don't build that list unless you need to.
357
394
for (void Function () reduceMethod in [
358
- // If this name could refer to a class or a constructor, prefer the class.
359
- _reducePreferClass,
360
395
// If a result is actually in this library, prefer that.
361
396
_reducePreferResultsInSameLibrary,
362
397
// If a result is accessible in this library, prefer that.
@@ -404,30 +439,6 @@ class _MarkdownCommentReference {
404
439
List <String > get codeRefChompedParts =>
405
440
_codeRefChompedParts ?? = codeRefChomped.split ('.' );
406
441
407
- /// Returns true if this is a constructor we should consider due to its
408
- /// name and the code reference, or if this isn't a constructor. False
409
- /// otherwise.
410
- bool _ConsiderIfConstructor (ModelElement modelElement) {
411
- // TODO(jcollins-g): Rewrite this to handle constructors in a less hacky way
412
- if (modelElement is ! Constructor ) return true ;
413
- if (codeRef.contains (isConstructor)) return true ;
414
- Constructor aConstructor = modelElement;
415
- if (codeRefParts.length > 1 ) {
416
- // Pick the last two parts, in case a specific library was part of the
417
- // codeRef.
418
- if (codeRefParts[codeRefParts.length - 1 ] ==
419
- codeRefParts[codeRefParts.length - 2 ]) {
420
- // Foobar.Foobar -- assume they really do mean the constructor for this class.
421
- return true ;
422
- }
423
- }
424
- if (aConstructor.name != aConstructor.enclosingElement.name) {
425
- // This isn't a default constructor so treat it like any other member.
426
- return true ;
427
- }
428
- return false ;
429
- }
430
-
431
442
void _reducePreferAnalyzerResolution () {
432
443
Element refElement = _getRefElementFromCommentRefs (commentRefs, codeRef);
433
444
if (results.any ((me) => me.element == refElement)) {
@@ -471,12 +482,6 @@ class _MarkdownCommentReference {
471
482
}
472
483
}
473
484
474
- void _reducePreferClass () {
475
- if (results.any ((r) => r is Class )) {
476
- results.removeWhere ((r) => r is Constructor );
477
- }
478
- }
479
-
480
485
void _findTypeParameters () {
481
486
if (element is TypeParameters ) {
482
487
results.addAll ((element as TypeParameters ).typeParameters.where ((p) =>
@@ -540,14 +545,51 @@ class _MarkdownCommentReference {
540
545
}
541
546
}
542
547
548
+ /// Transform members of [toConvert] that are classes to their default constructor,
549
+ /// if a constructor is implied. If not, do the reverse conversion for default
550
+ /// constructors.
551
+ ModelElement _convertConstructors (ModelElement toConvert) {
552
+ if (_impliedDefaultConstructor != null ) {
553
+ if (toConvert is Class && toConvert.name == _impliedDefaultConstructor) {
554
+ return toConvert.defaultConstructor;
555
+ }
556
+ return toConvert;
557
+ } else {
558
+ if (toConvert is Constructor &&
559
+ (toConvert.enclosingElement as Class ).defaultConstructor ==
560
+ toConvert) {
561
+ return toConvert.enclosingElement;
562
+ }
563
+ return toConvert;
564
+ }
565
+ }
566
+
567
+ void _findReferenceFromPrefixes () {
568
+ if (element is ! ModelElement ) return ;
569
+ Map <String , Set <Library >> prefixToLibrary =
570
+ (element as ModelElement ).definingLibrary.prefixToLibrary;
571
+ if (prefixToLibrary.containsKey (codeRefChompedParts.first)) {
572
+ if (codeRefChompedParts.length == 1 ) {
573
+ results.addAll (prefixToLibrary[codeRefChompedParts.first]);
574
+ } else {
575
+ String lookup = codeRefChompedParts.sublist (1 ).join ('.' );
576
+ prefixToLibrary[codeRefChompedParts.first]? .forEach ((l) => l
577
+ .modelElementsNameMap[lookup]
578
+ ? .map (_convertConstructors)
579
+ ? .forEach ((m) => _addCanonicalResult (m, _getPreferredClass (m))));
580
+ }
581
+ }
582
+ }
583
+
543
584
void _findGlobalWithinRefElementCache () {
544
585
if (packageGraph.findRefElementCache.containsKey (codeRefChomped)) {
545
586
for (final modelElement
546
587
in packageGraph.findRefElementCache[codeRefChomped]) {
547
588
if (codeRefChomped == modelElement.fullyQualifiedNameWithoutLibrary ||
548
589
(modelElement is Library &&
549
590
codeRefChomped == modelElement.fullyQualifiedName)) {
550
- _addCanonicalResult (modelElement, null );
591
+ _addCanonicalResult (
592
+ _convertConstructors (modelElement), preferredClass);
551
593
}
552
594
}
553
595
}
@@ -557,8 +599,7 @@ class _MarkdownCommentReference {
557
599
// Only look for partially qualified matches if we didn't find a fully qualified one.
558
600
if (library.modelElementsNameMap.containsKey (codeRefChomped)) {
559
601
for (final modelElement in library.modelElementsNameMap[codeRefChomped]) {
560
- if (! _ConsiderIfConstructor (modelElement)) continue ;
561
- _addCanonicalResult (modelElement, preferredClass);
602
+ _addCanonicalResult (_convertConstructors (modelElement), preferredClass);
562
603
}
563
604
}
564
605
}
@@ -571,13 +612,12 @@ class _MarkdownCommentReference {
571
612
packageGraph.findRefElementCache.containsKey (codeRefChomped)) {
572
613
for (final ModelElement modelElement
573
614
in packageGraph.findRefElementCache[codeRefChomped]) {
574
- if (! _ConsiderIfConstructor (modelElement)) continue ;
575
615
// For fully qualified matches, the original preferredClass passed
576
616
// might make no sense. Instead, use the enclosing class from the
577
617
// element in [packageGraph.findRefElementCache], because that element's
578
618
// enclosing class will be preferred from [codeRefChomped]'s perspective.
579
619
_addCanonicalResult (
580
- modelElement,
620
+ _convertConstructors ( modelElement) ,
581
621
modelElement.enclosingElement is Class
582
622
? modelElement.enclosingElement
583
623
: null );
@@ -678,26 +718,17 @@ class _MarkdownCommentReference {
678
718
/// Get any possible results for this class in the superChain. Returns
679
719
/// true if we found something.
680
720
void _getResultsForSuperChainElement (Class c, Class tryClass) {
681
- Iterable <ModelElement > membersToCheck;
682
- membersToCheck = (c.allModelElementsByNamePart[codeRefChomped] ?? [])
683
- . where ((m) => _ConsiderIfConstructor (m) );
721
+ Iterable <ModelElement > membersToCheck =
722
+ (c.allModelElementsByNamePart[codeRefChomped] ?? [])
723
+ . map (_convertConstructors );
684
724
for (final ModelElement modelElement in membersToCheck) {
685
725
// [thing], a member of this class
686
726
_addCanonicalResult (modelElement, tryClass);
687
727
}
688
728
membersToCheck = (c.allModelElementsByNamePart[codeRefChompedParts.last] ??
689
729
< ModelElement > [])
690
- .where ((m) => _ConsiderIfConstructor (m));
691
- if (codeRefChompedParts.first == c.name) {
692
- // [Foo...thing], a member of this class (possibly a parameter).
693
- membersToCheck.forEach ((m) => _addCanonicalResult (m, tryClass));
694
- } else if (codeRefChompedParts.length > 1 &&
695
- codeRefChompedParts[codeRefChompedParts.length - 2 ] == c.name) {
696
- // [....Foo.thing], a member of this class partially specified.
697
- membersToCheck
698
- .whereType <Constructor >()
699
- .forEach ((m) => _addCanonicalResult (m, tryClass));
700
- }
730
+ .map (_convertConstructors);
731
+ membersToCheck.forEach ((m) => _addCanonicalResult (m, tryClass));
701
732
results.remove (null );
702
733
if (results.isNotEmpty) return ;
703
734
if (c.fullyQualifiedNameWithoutLibrary == codeRefChomped) {
0 commit comments