findCanonicalModelElementFor method

ModelElement? findCanonicalModelElementFor(
  1. Element? e, {
  2. Container? preferredClass,
})

Tries to find a canonical ModelElement for this e. If we know this element is related to a particular class, pass a preferredClass to disambiguate.

This doesn't know anything about PackageGraph.inheritThrough and probably shouldn't, so using it with Inheritables without special casing is not advised.

Implementation

ModelElement? findCanonicalModelElementFor(Element? e,
    {Container? preferredClass}) {
  assert(allLibrariesAdded);
  if (e == null) return null;
  if (preferredClass != null) {
    var canonicalClass =
        findCanonicalModelElementFor(preferredClass.element) as Container?;
    if (canonicalClass != null) preferredClass = canonicalClass;
  }
  var lib = _findCanonicalLibraryFor(e);
  if (lib == null && preferredClass != null) {
    lib = _findCanonicalLibraryFor(preferredClass.element);
  }
  // For elements defined in extensions, they are canonical.
  var enclosingElement = e.enclosingElement;
  if (enclosingElement is ExtensionElement) {
    lib ??= getModelForElement(enclosingElement.library) as Library?;
    // TODO(keertip): Find a better way to exclude members of extensions
    // when libraries are specified using the "--include" flag.
    if (lib != null && lib.isDocumented) {
      return getModelFor(e, lib);
    }
  }
  // TODO(jcollins-g): The data structures should be changed to eliminate
  // guesswork with member elements.
  var declaration = e.declaration;
  ModelElement? modelElement;
  if (declaration != null &&
      (e is ClassMemberElement || e is PropertyAccessorElement)) {
    e = declaration;
    modelElement = _findCanonicalModelElementForAmbiguous(e, lib,
        preferredClass: preferredClass as InheritingContainer?);
  } else {
    if (lib != null) {
      if (e is PropertyInducingElement) {
        var getter = e.getter != null ? getModelFor(e.getter!, lib) : null;
        var setter = e.setter != null ? getModelFor(e.setter!, lib) : null;
        modelElement = getModelForPropertyInducingElement(e, lib,
            getter: getter as Accessor?, setter: setter as Accessor?);
      } else {
        modelElement = getModelFor(e, lib);
      }
    }
    assert(modelElement is! Inheritable);
    if (modelElement != null && !modelElement.isCanonical) {
      modelElement = null;
    }
  }
  // Prefer fields and top-level variables.
  if (e is PropertyAccessorElement && modelElement is Accessor) {
    modelElement = modelElement.enclosingCombo;
  }
  return modelElement;
}