findCanonicalModelElementFor method

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

Tries to find a canonical ModelElement for modelElement.

If we know the element is related to a particular class, pass a preferredClass to disambiguate.

This can return null in a few ways: if modelElement is null, or if it has no canonical library, or if a possible canonical model element has a false value for isCanonical.

Implementation

ModelElement? findCanonicalModelElementFor(ModelElement? modelElement,
    {Container? preferredClass}) {
  assert(allLibrariesAdded);
  if (modelElement == null) return null;
  var e = modelElement.element;
  if (preferredClass != null) {
    var canonicalClass =
        findCanonicalModelElementFor(preferredClass) as Container?;
    if (canonicalClass != null) preferredClass = canonicalClass;
  }
  var library = modelElement.canonicalLibrary;
  if (modelElement is Library) return library;

  if (library == null && preferredClass != null) {
    library = preferredClass.canonicalLibrary;
  }
  // For elements defined in extensions, they are canonical.
  var enclosingElement = e.enclosingElement;
  if (enclosingElement is ExtensionElement) {
    library ??= 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 (library != null && library.isDocumented) {
      return getModelFor(e, library, enclosingContainer: preferredClass);
    }
  }
  // TODO(jcollins-g): The data structures should be changed to eliminate
  // guesswork with member elements.
  var declaration = e.baseElement;
  ModelElement? canonicalModelElement;
  if (e is ConstructorElement ||
      e is MethodElement ||
      e is FieldElement ||
      e is PropertyAccessorElement) {
    var declarationModelElement = getModelForElement(declaration);
    e = declarationModelElement.element;
    canonicalModelElement = _findCanonicalModelElementForAmbiguous(
        declarationModelElement, library,
        preferredClass: preferredClass as InheritingContainer?);
  } else {
    if (library != null) {
      if (e case PropertyInducingElement(:var getter, :var setter)) {
        var getterElement =
            getter == null ? null : getModelFor(getter, library) as Accessor;
        var setterElement =
            setter == null ? null : getModelFor(setter, library) as Accessor;
        canonicalModelElement = getModelForPropertyInducingElement(e, library,
            getter: getterElement, setter: setterElement);
      } else {
        canonicalModelElement = getModelFor(e, library);
      }
    }
    assert(canonicalModelElement is! Inheritable);
    if (canonicalModelElement != null && !canonicalModelElement.isCanonical) {
      canonicalModelElement = null;
    }
  }
  // Prefer fields and top-level variables.
  if (e is PropertyAccessorElement && canonicalModelElement is Accessor) {
    canonicalModelElement = canonicalModelElement.enclosingCombo;
  }
  return canonicalModelElement;
}