@@ -473,13 +473,14 @@ abstract class ModelElement extends Canonicalization
473
473
return _config;
474
474
}
475
475
476
+ Set <String > _locationPieces;
477
+
476
478
@override
477
- Set <String > get locationPieces {
478
- return Set .from (element.location
479
- .toString ()
480
- .split (locationSplitter)
481
- .where ((s) => s.isNotEmpty));
482
- }
479
+ Set <String > get locationPieces =>
480
+ _locationPieces ?? = Set .from (element.location
481
+ .toString ()
482
+ .split (locationSplitter)
483
+ .where ((s) => s.isNotEmpty));
483
484
484
485
Set <String > get features {
485
486
var allFeatures = < String > {};
@@ -648,81 +649,13 @@ abstract class ModelElement extends Canonicalization
648
649
if (! _canonicalLibraryIsSet) {
649
650
// This is not accurate if we are constructing the Package.
650
651
assert (packageGraph.allLibrariesAdded);
651
- // Since we're looking for a library, find the [Element] immediately
652
- // contained by a [CompilationUnitElement] in the tree.
653
- var topLevelElement = element;
654
- while (topLevelElement != null &&
655
- topLevelElement.enclosingElement is ! LibraryElement &&
656
- topLevelElement.enclosingElement is ! CompilationUnitElement &&
657
- topLevelElement.enclosingElement != null ) {
658
- topLevelElement = topLevelElement.enclosingElement;
659
- }
660
652
661
653
// Privately named elements can never have a canonical library, so
662
654
// just shortcut them out.
663
655
if (! utils.hasPublicName (element)) {
664
656
_canonicalLibrary = null ;
665
- } else if (definingLibrary != null &&
666
- ! packageGraph.localPublicLibraries.contains (definingLibrary)) {
667
- var candidateLibraries = definingLibrary.exportedInLibraries
668
- ? .where ((l) =>
669
- l.isPublic &&
670
- l.package.documentedWhere != DocumentLocation .missing)
671
- ? .toList ();
672
-
673
- if (candidateLibraries != null ) {
674
- candidateLibraries = candidateLibraries.where ((l) {
675
- var lookup =
676
- l.element.exportNamespace.definedNames[topLevelElement? .name];
677
- if (lookup is PropertyAccessorElement ) {
678
- lookup = (lookup as PropertyAccessorElement ).variable;
679
- }
680
- if (topLevelElement == lookup) return true ;
681
- return false ;
682
- }).toList ();
683
-
684
- // Avoid claiming canonicalization for elements outside of this element's
685
- // defining package.
686
- // TODO(jcollins-g): Make the else block unconditional.
687
- if (candidateLibraries.isNotEmpty &&
688
- ! candidateLibraries
689
- .any ((l) => l.package == definingLibrary.package)) {
690
- warn (PackageWarning .reexportedPrivateApiAcrossPackages,
691
- message: definingLibrary.package.fullyQualifiedName,
692
- referredFrom: candidateLibraries);
693
- } else {
694
- candidateLibraries
695
- .removeWhere ((l) => l.package != definingLibrary.package);
696
- }
697
-
698
- // Start with our top-level element.
699
- var warnable =
700
- ModelElement .fromElement (topLevelElement, packageGraph);
701
- if (candidateLibraries.length > 1 ) {
702
- // Heuristic scoring to determine which library a human likely
703
- // considers this element to be primarily 'from', and therefore,
704
- // canonical. Still warn if the heuristic isn't that confident.
705
- var scoredCandidates =
706
- warnable.scoreCanonicalCandidates (candidateLibraries);
707
- candidateLibraries =
708
- scoredCandidates.map ((s) => s.library).toList ();
709
- var secondHighestScore =
710
- scoredCandidates[scoredCandidates.length - 2 ].score;
711
- var highestScore = scoredCandidates.last.score;
712
- var confidence = highestScore - secondHighestScore;
713
- var message =
714
- '${candidateLibraries .map ((l ) => l .name )} -> ${candidateLibraries .last .name } (confidence ${confidence .toStringAsPrecision (4 )})' ;
715
-
716
- if (confidence < config.ambiguousReexportScorerMinConfidence) {
717
- warnable.warn (PackageWarning .ambiguousReexport,
718
- message: message,
719
- extendedDebug: scoredCandidates.map ((s) => '$s ' ));
720
- }
721
- }
722
- if (candidateLibraries.isNotEmpty) {
723
- _canonicalLibrary = candidateLibraries.last;
724
- }
725
- }
657
+ } else if (! packageGraph.localPublicLibraries.contains (definingLibrary)) {
658
+ _canonicalLibrary = _searchForCanonicalLibrary ();
726
659
} else {
727
660
_canonicalLibrary = definingLibrary;
728
661
}
@@ -743,6 +676,79 @@ abstract class ModelElement extends Canonicalization
743
676
return _canonicalLibrary;
744
677
}
745
678
679
+ Library _searchForCanonicalLibrary () {
680
+ var thisAndExported = definingLibrary.exportedInLibraries;
681
+
682
+ if (thisAndExported == null ) {
683
+ return null ;
684
+ }
685
+
686
+ // Since we're looking for a library, find the [Element] immediately
687
+ // contained by a [CompilationUnitElement] in the tree.
688
+ var topLevelElement = element;
689
+ while (topLevelElement != null &&
690
+ topLevelElement.enclosingElement is ! LibraryElement &&
691
+ topLevelElement.enclosingElement is ! CompilationUnitElement &&
692
+ topLevelElement.enclosingElement != null ) {
693
+ topLevelElement = topLevelElement.enclosingElement;
694
+ }
695
+
696
+ var candidateLibraries = thisAndExported
697
+ .where ((l) =>
698
+ l.isPublic && l.package.documentedWhere != DocumentLocation .missing)
699
+ .where ((l) {
700
+ var lookup =
701
+ l.element.exportNamespace.definedNames[topLevelElement? .name];
702
+ if (lookup is PropertyAccessorElement ) {
703
+ lookup = (lookup as PropertyAccessorElement ).variable;
704
+ }
705
+ return topLevelElement == lookup;
706
+ }).toList ();
707
+
708
+ // Avoid claiming canonicalization for elements outside of this element's
709
+ // defining package.
710
+ // TODO(jcollins-g): Make the else block unconditional.
711
+ if (candidateLibraries.isNotEmpty &&
712
+ ! candidateLibraries.any ((l) => l.package == definingLibrary.package)) {
713
+ warn (PackageWarning .reexportedPrivateApiAcrossPackages,
714
+ message: definingLibrary.package.fullyQualifiedName,
715
+ referredFrom: candidateLibraries);
716
+ } else {
717
+ candidateLibraries
718
+ .removeWhere ((l) => l.package != definingLibrary.package);
719
+ }
720
+
721
+ if (candidateLibraries.isEmpty) {
722
+ return null ;
723
+ }
724
+ if (candidateLibraries.length == 1 ) {
725
+ return candidateLibraries.single;
726
+ }
727
+
728
+ // Start with our top-level element.
729
+ var warnable = ModelElement .fromElement (topLevelElement, packageGraph);
730
+ // Heuristic scoring to determine which library a human likely
731
+ // considers this element to be primarily 'from', and therefore,
732
+ // canonical. Still warn if the heuristic isn't that confident.
733
+ var scoredCandidates =
734
+ warnable.scoreCanonicalCandidates (candidateLibraries);
735
+ candidateLibraries = scoredCandidates.map ((s) => s.library).toList ();
736
+ var secondHighestScore =
737
+ scoredCandidates[scoredCandidates.length - 2 ].score;
738
+ var highestScore = scoredCandidates.last.score;
739
+ var confidence = highestScore - secondHighestScore;
740
+
741
+ if (confidence < config.ambiguousReexportScorerMinConfidence) {
742
+ var libraryNames = candidateLibraries.map ((l) => l.name);
743
+ var message = '$libraryNames -> ${candidateLibraries .last .name } '
744
+ '(confidence ${confidence .toStringAsPrecision (4 )})' ;
745
+ warnable.warn (PackageWarning .ambiguousReexport,
746
+ message: message, extendedDebug: scoredCandidates.map ((s) => '$s ' ));
747
+ }
748
+
749
+ return candidateLibraries.last;
750
+ }
751
+
746
752
@override
747
753
bool get isCanonical {
748
754
if (! isPublic) return false ;
@@ -1072,6 +1078,9 @@ abstract class ModelElement extends Canonicalization
1072
1078
1073
1079
String computeDocumentationComment () => element.documentationComment;
1074
1080
1081
+ /// The documentation comment on the Element may be null, so memoization
1082
+ /// cannot rely on the null-ness of [_documentationComment] , it must be
1083
+ /// more explicit.
1075
1084
bool _documentationCommentComputed = false ;
1076
1085
String _documentationComment;
1077
1086
0 commit comments