elementFor method
Element?
elementFor(
- 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;
}