@@ -26,7 +26,6 @@ import 'package:dartdoc/src/render/renderer_factory.dart';
26
26
import 'package:dartdoc/src/special_elements.dart' ;
27
27
import 'package:dartdoc/src/tool_definition.dart' ;
28
28
import 'package:dartdoc/src/tool_runner.dart' ;
29
- import 'package:dartdoc/src/tuple.dart' ;
30
29
import 'package:dartdoc/src/warnings.dart' ;
31
30
import 'package:meta/meta.dart' ;
32
31
@@ -219,12 +218,11 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
219
218
220
219
/// All [ModelElement] s constructed for this package; a superset of
221
220
/// [_allModelElements] .
222
- final Map <Tuple3 < Element , Library , Container ?>, ModelElement ?>
223
- allConstructedModelElements = {};
221
+ final Map <( Element element , Library ? library , Container ? enclosingElement),
222
+ ModelElement ?> allConstructedModelElements = {};
224
223
225
224
/// Anything that might be inheritable, place here for later lookup.
226
- final Map <Tuple2 <Element , Library >, Set <ModelElement >>
227
- allInheritableElements = {};
225
+ final Map <(Element , Library ), Set <ModelElement >> allInheritableElements = {};
228
226
229
227
/// A mapping of the list of classes which implement each class.
230
228
final Map <InheritingContainer , List <InheritingContainer >> _implementors =
@@ -287,18 +285,19 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
287
285
late final PackageWarningCounter packageWarningCounter =
288
286
PackageWarningCounter (this );
289
287
290
- final Set <Tuple3 <Element ?, PackageWarning , String ?>> _warnAlreadySeen = {};
288
+ final Set <(Element ? element, PackageWarning packageWarning, String ? message)>
289
+ _warnAlreadySeen = {};
291
290
292
291
void warnOnElement (Warnable ? warnable, PackageWarning kind,
293
292
{String ? message,
294
293
Iterable <Locatable > referredFrom = const [],
295
294
Iterable <String > extendedDebug = const []}) {
296
- var newEntry = Tuple3 (warnable? .element, kind, message);
295
+ var newEntry = (warnable? .element, kind, message);
297
296
if (_warnAlreadySeen.contains (newEntry)) {
298
297
return ;
299
298
}
300
- // Warnings can cause other warnings. Queue them up via the stack but
301
- // don't allow warnings we're already working on to get in there.
299
+ // Warnings can cause other warnings. Queue them up via the stack but don't
300
+ // allow warnings we're already working on to get in there.
302
301
_warnAlreadySeen.add (newEntry);
303
302
_warnOnElement (warnable, kind,
304
303
message: message ?? '' ,
@@ -417,12 +416,12 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
417
416
Map <LibraryElement , Set <Library >> _libraryElementReexportedBy = {};
418
417
419
418
/// Prevent cycles from breaking our stack.
420
- Set <Tuple2 < Library , LibraryElement ?> > _reexportsTagged = {};
419
+ Set <( Library , LibraryElement ?) > _reexportsTagged = {};
421
420
422
421
void _tagReexportsFor (
423
422
final Library topLevelLibrary, final LibraryElement ? libraryElement,
424
423
[LibraryExportElement ? lastExportedElement]) {
425
- var key = Tuple2 < Library , LibraryElement ?> (topLevelLibrary, libraryElement);
424
+ var key = (topLevelLibrary, libraryElement);
426
425
if (_reexportsTagged.contains (key)) {
427
426
return ;
428
427
}
@@ -625,35 +624,36 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
625
624
626
625
final Map <Element ?, Library ?> _canonicalLibraryFor = {};
627
626
627
+ @Deprecated ('Not public API; will be removed' )
628
+ Library ? findCanonicalLibraryFor (Element e) => _findCanonicalLibraryFor (e);
629
+
628
630
/// Tries to find a top level library that references this element.
629
- Library ? findCanonicalLibraryFor (Element ? e) {
631
+ Library ? _findCanonicalLibraryFor (Element e) {
630
632
assert (allLibrariesAdded);
631
- var searchElement = e;
632
- if (e is PropertyAccessorElement ) {
633
- searchElement = e.variable;
634
- }
635
- if (e is GenericFunctionTypeElement ) {
636
- searchElement = e.enclosingElement;
637
- }
638
-
639
633
if (_canonicalLibraryFor.containsKey (e)) {
640
634
return _canonicalLibraryFor[e];
641
635
}
642
636
_canonicalLibraryFor[e] = null ;
637
+
638
+ var searchElement = switch (e) {
639
+ PropertyAccessorElement () => e.variable,
640
+ GenericFunctionTypeElement () => e.enclosingElement,
641
+ _ => e,
642
+ };
643
+ if (searchElement == null ) return null ;
643
644
for (var library in publicLibraries) {
644
- if (library.modelElementsMap.containsKey (searchElement)) {
645
- for (var modelElement in library.modelElementsMap[searchElement! ]! ) {
646
- if (modelElement.isCanonical) {
647
- return _canonicalLibraryFor[e] = library;
648
- }
645
+ var modelElements = library.modelElementsMap[searchElement];
646
+ if (modelElements != null ) {
647
+ if (modelElements.any ((element) => element.isCanonical)) {
648
+ return _canonicalLibraryFor[e] = library;
649
649
}
650
650
}
651
651
}
652
652
return _canonicalLibraryFor[e];
653
653
}
654
654
655
- /// Tries to find a canonical ModelElement for this [e] . If we know
656
- /// this element is related to a particular class, pass a [preferredClass] to
655
+ /// Tries to find a canonical [ ModelElement] for this [e] . If we know this
656
+ /// element is related to a particular class, pass a [preferredClass] to
657
657
/// disambiguate.
658
658
///
659
659
/// This doesn't know anything about [PackageGraph.inheritThrough] and
@@ -662,107 +662,35 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
662
662
ModelElement ? findCanonicalModelElementFor (Element ? e,
663
663
{Container ? preferredClass}) {
664
664
assert (allLibrariesAdded);
665
- var lib = findCanonicalLibraryFor (e) ;
665
+ if (e == null ) return null ;
666
666
if (preferredClass != null ) {
667
667
var canonicalClass =
668
668
findCanonicalModelElementFor (preferredClass.element) as Container ? ;
669
669
if (canonicalClass != null ) preferredClass = canonicalClass;
670
670
}
671
+ var lib = _findCanonicalLibraryFor (e);
671
672
if (lib == null && preferredClass != null ) {
672
- lib = findCanonicalLibraryFor (preferredClass.element);
673
+ lib = _findCanonicalLibraryFor (preferredClass.element);
673
674
}
674
675
// For elements defined in extensions, they are canonical.
675
- var enclosingElement = e? .enclosingElement;
676
+ var enclosingElement = e.enclosingElement;
676
677
if (enclosingElement is ExtensionElement ) {
677
678
lib ?? = modelBuilder.fromElement (enclosingElement.library) as Library ? ;
678
- // ( TODO: keertip) Find a better way to exclude members of extensions
679
- // when libraries are specified using the "--include" flag
679
+ // TODO( keertip): Find a better way to exclude members of extensions
680
+ // when libraries are specified using the "--include" flag.
680
681
if (lib? .isDocumented == true ) {
681
- return modelBuilder.from (e! , lib! );
682
+ return modelBuilder.from (e, lib! );
682
683
}
683
684
}
685
+ // TODO(jcollins-g): The data structures should be changed to eliminate
686
+ // guesswork with member elements.
687
+ var declaration = e.declaration;
684
688
ModelElement ? modelElement;
685
- // TODO(jcollins-g): Special cases are pretty large here. Refactor to split
686
- // out into helpers.
687
- // TODO(jcollins-g): The data structures should be changed to eliminate guesswork
688
- // with member elements.
689
- var declaration = e? .declaration;
690
689
if (declaration != null &&
691
690
(e is ClassMemberElement || e is PropertyAccessorElement )) {
692
691
e = declaration;
693
- var candidates = < ModelElement > {};
694
- var iKey = Tuple2 <Element , Library ?>(e, lib);
695
- var key = Tuple3 <Element , Library ?, Class ?>(e, lib, null );
696
- var keyWithClass = Tuple3 <Element , Library ?, InheritingContainer ?>(
697
- e, lib, preferredClass as InheritingContainer ? );
698
- var constructedWithKey = allConstructedModelElements[key];
699
- if (constructedWithKey != null ) {
700
- candidates.add (constructedWithKey);
701
- }
702
- var constructedWithKeyWithClass =
703
- allConstructedModelElements[keyWithClass];
704
- if (constructedWithKeyWithClass != null ) {
705
- candidates.add (constructedWithKeyWithClass);
706
- }
707
- if (candidates.isEmpty && allInheritableElements.containsKey (iKey)) {
708
- candidates.addAll (
709
- allInheritableElements[iKey as Tuple2 <Element , Library >]!
710
- .where ((me) => me.isCanonical));
711
- }
712
-
713
- var canonicalClass = findCanonicalModelElementFor (e.enclosingElement);
714
- if (canonicalClass is InheritingContainer ) {
715
- candidates.addAll (canonicalClass.allCanonicalModelElements.where ((m) {
716
- return m.element == e;
717
- }));
718
- }
719
-
720
- var matches = {...candidates.where ((me) => me.isCanonical)};
721
-
722
- // It's possible to find accessors but no combos. Be sure that if we
723
- // have Accessors, we find their combos too.
724
- if (matches.any ((me) => me is Accessor )) {
725
- var combos = matches
726
- .whereType <Accessor >()
727
- .map ((a) => a.enclosingCombo)
728
- .toList (growable: false );
729
- matches.addAll (combos);
730
- assert (combos.every ((c) => c.isCanonical));
731
- }
732
-
733
- // This is for situations where multiple classes may actually be canonical
734
- // for an inherited element whose defining Class is not canonical.
735
- if (matches.length > 1 && preferredClass != null ) {
736
- // Search for matches inside our superchain.
737
- var superChain = [
738
- for (final elementType in preferredClass.superChain)
739
- elementType.modelElement as InheritingContainer ,
740
- preferredClass,
741
- ];
742
-
743
- matches.removeWhere ((me) => ! superChain.contains (me.enclosingElement));
744
- // Assumed all matches are EnclosedElement because we've been told about a
745
- // preferredClass.
746
- var enclosingElements = {
747
- ...matches.map ((me) => me.enclosingElement as Class ? )
748
- };
749
- for (var c in superChain.reversed) {
750
- if (enclosingElements.contains (c)) {
751
- matches.removeWhere ((me) => me.enclosingElement != c);
752
- }
753
- if (matches.length <= 1 ) break ;
754
- }
755
- }
756
-
757
- // Prefer a GetterSetterCombo to Accessors.
758
- if (matches.any ((me) => me is GetterSetterCombo )) {
759
- matches.removeWhere ((me) => me is Accessor );
760
- }
761
-
762
- assert (matches.length <= 1 );
763
- if (matches.isNotEmpty) {
764
- modelElement = matches.first;
765
- }
692
+ modelElement = _findCanonicalModelElementForAmbiguous (e, lib,
693
+ preferredClass: preferredClass as InheritingContainer ? );
766
694
} else {
767
695
if (lib != null ) {
768
696
if (e is PropertyInducingElement ) {
@@ -773,7 +701,7 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
773
701
modelElement = modelBuilder.fromPropertyInducingElement (e, lib,
774
702
getter: getter as Accessor ? , setter: setter as Accessor ? );
775
703
} else {
776
- modelElement = modelBuilder.from (e! , lib);
704
+ modelElement = modelBuilder.from (e, lib);
777
705
}
778
706
}
779
707
assert (modelElement is ! Inheritable );
@@ -788,6 +716,76 @@ class PackageGraph with CommentReferable, Nameable, ModelBuilder {
788
716
return modelElement;
789
717
}
790
718
719
+ ModelElement ? _findCanonicalModelElementForAmbiguous (Element e, Library ? lib,
720
+ {InheritingContainer ? preferredClass}) {
721
+ var candidates = < ModelElement ? > {};
722
+ var constructedWithKey = allConstructedModelElements[(e, lib, null )];
723
+ if (constructedWithKey != null ) {
724
+ candidates.add (constructedWithKey);
725
+ }
726
+ var constructedWithKeyWithClass =
727
+ allConstructedModelElements[(e, lib, preferredClass)];
728
+ if (constructedWithKeyWithClass != null ) {
729
+ candidates.add (constructedWithKeyWithClass);
730
+ }
731
+ if (candidates.isEmpty) {
732
+ candidates = {
733
+ ...? allInheritableElements[(e, lib)]? .where ((me) => me.isCanonical),
734
+ };
735
+ }
736
+
737
+ var canonicalClass = findCanonicalModelElementFor (e.enclosingElement);
738
+ if (canonicalClass is InheritingContainer ) {
739
+ candidates.addAll (canonicalClass.allCanonicalModelElements
740
+ .where ((m) => m.element == e));
741
+ }
742
+
743
+ var matches = {...candidates.whereNotNull ().where ((me) => me.isCanonical)};
744
+
745
+ // It's possible to find [Accessor]s but no combos. Be sure that if we
746
+ // have accessors, we find their combos too.
747
+ if (matches.any ((me) => me is Accessor )) {
748
+ var combos = matches
749
+ .whereType <Accessor >()
750
+ .map ((a) => a.enclosingCombo)
751
+ .toList (growable: false );
752
+ matches.addAll (combos);
753
+ assert (combos.every ((c) => c.isCanonical));
754
+ }
755
+
756
+ // This is for situations where multiple classes may actually be canonical
757
+ // for an inherited element whose defining Class is not canonical.
758
+ if (matches.length > 1 && preferredClass != null ) {
759
+ // Search for matches inside our superchain.
760
+ var superChain = [
761
+ ...preferredClass.superChain.map ((e) => e.modelElement),
762
+ preferredClass,
763
+ ];
764
+
765
+ matches.removeWhere ((me) => ! superChain.contains (me.enclosingElement));
766
+ // Assumed all matches are EnclosedElement because we've been told about a
767
+ // preferredClass.
768
+ var enclosingElements = {...matches.map ((me) => me.enclosingElement)};
769
+ for (var c in superChain.reversed) {
770
+ if (enclosingElements.contains (c)) {
771
+ matches.removeWhere ((me) => me.enclosingElement != c);
772
+ }
773
+ if (matches.length <= 1 ) break ;
774
+ }
775
+ }
776
+
777
+ // Prefer a GetterSetterCombo to Accessors.
778
+ if (matches.any ((me) => me is GetterSetterCombo )) {
779
+ matches.removeWhere ((me) => me is Accessor );
780
+ }
781
+
782
+ assert (matches.length <= 1 );
783
+ if (matches.isNotEmpty) {
784
+ return matches.first;
785
+ }
786
+ return null ;
787
+ }
788
+
791
789
/// This is used when we might need a Library object that isn't actually
792
790
/// a documentation entry point (for elements that have no Library within the
793
791
/// set of canonical Libraries).
0 commit comments