Tries to find a canonical ModelElement for this element. If we know this element is related to a particular class, pass preferredClass to disambiguate.
Source
ModelElement findCanonicalModelElementFor(Element e, {Class preferredClass}) {
assert(allLibrariesAdded);
Library lib = findCanonicalLibraryFor(e);
if (lib == null && preferredClass != null) {
lib = findCanonicalLibraryFor(preferredClass.element);
}
ModelElement modelElement;
// TODO(jcollins-g): The data structures should be changed to eliminate guesswork
// with member elements.
if (e is ClassMemberElement || e is PropertyAccessorElement) {
// Prefer Fields over Accessors.
if (e is PropertyAccessorElement)
e = (e as PropertyAccessorElement).variable;
if (e is Member) e = getBasestElement(e);
Set<ModelElement> candidates = new Set();
Tuple2<Element, Library> iKey = new Tuple2(e, lib);
Tuple4<Element, Library, Class, ModelElement> key =
new Tuple4(e, lib, null, null);
Tuple4<Element, Library, Class, ModelElement> keyWithClass =
new Tuple4(e, lib, preferredClass, null);
if (_allConstructedModelElements.containsKey(key)) {
candidates.add(_allConstructedModelElements[key]);
}
if (_allConstructedModelElements.containsKey(keyWithClass)) {
candidates.add(_allConstructedModelElements[keyWithClass]);
}
if (candidates.isEmpty && _allInheritableElements.containsKey(iKey)) {
candidates.addAll(
_allInheritableElements[iKey].where((me) => me.isCanonical));
}
Class canonicalClass = findCanonicalModelElementFor(e.enclosingElement);
if (canonicalClass != null) {
candidates.addAll(canonicalClass.allCanonicalModelElements.where((m) {
if (m.element is FieldElement) {
FieldElement fieldElement = m.element as FieldElement;
Element getter;
Element setter;
if (fieldElement.getter?.isSynthetic == true) {
getter = fieldElement.getter.variable;
} else {
getter = fieldElement.getter;
}
if (fieldElement.setter?.isSynthetic == true) {
setter = fieldElement.setter.variable;
} else {
setter = fieldElement.setter;
}
if (setter == e || getter == e) return true;
}
if (m.element == e) return true;
return false;
}));
}
Set<ModelElement> matches = new Set()
..addAll(candidates.where((me) => me.isCanonical));
// This is for situations where multiple classes may actually be canonical
// for an inherited element whose defining Class is not canonical.
if (matches.length > 1 && preferredClass != null) {
// Search for matches inside our superchain.
List<Class> superChain =
preferredClass.superChainRaw.map((et) => et.element).toList();
superChain.add(preferredClass);
matches.removeWhere((me) =>
!superChain.contains((me as EnclosedElement).enclosingElement));
}
assert(matches.length <= 1);
if (!matches.isEmpty) modelElement = matches.first;
} else {
if (lib != null) modelElement = new ModelElement.from(e, lib);
assert(modelElement is! Inheritable);
if (modelElement != null && !modelElement.isCanonical) {
modelElement = null;
}
}
return modelElement;
}