elementFor method

Element? elementFor(
  1. AstNode node
)

For a given AstNode, returns the correlating Element type that should be used to generate the symbol

Implementation

Element? elementFor(AstNode node) {
  if (node is Declaration) {
    return node.declaredFragment?.element;
  } else if (node is FormalParameter) {
    // if this parameter is a child of a GenericFunctionType (can be a
    // typedef, or a function as a parameter), we don't want to index it
    // as a definition (nothing is defined, just referenced). Return false
    // and let the [_visitSimpleIdentifier] declare the reference
    final parentParameter = node.parent
        ?.thisOrAncestorOfType<GenericFunctionType>();
    if (parentParameter != null) return null;

    return node.declaredFragment?.element;
  } else if (node is NamedType) {
    // `Foo()` constructor invocations reference the (unnamed) constructor,
    // whereas `Foo.bar()` references the class via `Foo`, and the
    // constructor via `bar`
    final parent = node.parent;
    if (parent is ConstructorName && parent.name == null) {
      return parent.element;
    }

    final element = node.element;
    if (element?.source == null) return null;
    return element;
  } else if (node is ImportPrefixReference) {
    return node.element;
  } else if (node is NamedArgument) {
    final element = node.correspondingParameter;
    if (element?.source == null) return null;
    return element;
  } else if (node is SimpleIdentifier) {
    var element = node.element;

    // A SimpleIdentifier with a direct parent of a ConstructorDeclaration
    // is the reference to the class itself. Skip this declaration
    if (node.parent is ConstructorDeclaration) {
      return null;
    }

    // Named constructors: `Foo.bar()`, `bar` is the SimpleIdentifier
    // referencing the constructor
    final parent = node.parent;
    if (parent is ConstructorName && parent.name == node) {
      return parent.element;
    }

    // Both `.loadLibrary()`, and `.call()` are synthetic functions that
    // have no definition. These should therefore should not be indexed.
    if (element is TopLevelFunctionElement && element.isOriginLoadLibrary) {
      return null;
    }
    if (element is MethodElement &&
        !element.isOriginDeclaration &&
        element.name == MethodElement.CALL_METHOD_NAME) {
      return null;
    }

    // [element] for assignment fields is null. If the parent node
    // is a `CompoundAssignmentExpression`, we know this node is referring
    // to an assignment line. In that case, use the read/write element attached
    // to this node instead of the [node]'s element
    if (element == null) {
      final assignmentExpr = node
          .thisOrAncestorOfType<CompoundAssignmentExpression>();
      if (assignmentExpr == null) return null;

      element = assignmentExpr.readElement ?? assignmentExpr.writeElement;
    }

    // When the identifier is a field, the analyzer creates synthetic getters/
    // setters for it. We need to get the backing field.
    if (element is PropertyAccessorElement && element.isOriginVariable) {
      // The values field on enums is synthetic, and has no explicit definition like
      // other fields do. Skip indexing for this case.
      final variable = element.variable;
      if (variable is FieldElement && variable.isOriginEnumValues) {
        return null;
      }

      element = variable;
    }

    // element is null if there's nothing really to do for this node. Example: `void`
    // TODO: One weird issue found: named parameters of external symbols were element.source
    //       EX: `color(path, front: Styles.YELLOW);` where `color` comes from the chalk-dart package
    if (element?.source == null) return null;

    return element;
  }

  display(
    'WARN: Received unknown ast node type in elementFor: '
    '${node.runtimeType} ($node). Skipping',
  );

  return null;
}