ModelElement findCanonicalModelElementFor(Element e, { Class preferredClass })

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;
}