blob: 7e910a3b90f00eace356e82efa0d6bee95462912 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'dart:math' show min;
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/constant/compute.dart';
import 'package:analyzer/src/dart/constant/evaluation.dart';
import 'package:analyzer/src/dart/constant/value.dart';
import 'package:analyzer/src/dart/element/handle.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine, AnalysisOptionsImpl;
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/summary/idl.dart';
import 'package:analyzer/src/summary2/linked_unit_context.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/util/comment.dart';
/// Assert that the given [object] is null, which in the places where this
/// function is called means that the element is not resynthesized.
void _assertNotResynthesized(Object object) {
// TODO(scheglov) I comment this check for now.
// When we make a decision about switch to the new analysis driver,
// we will need to rework the analysis code to don't call the setters
// or restore / inline it.
// assert(object == null);
}
/// A concrete implementation of a [ClassElement].
abstract class AbstractClassElementImpl extends ElementImpl
implements ClassElement {
/// A list containing all of the accessors (getters and setters) contained in
/// this class.
List<PropertyAccessorElement> _accessors;
/// A list containing all of the fields contained in this class.
List<FieldElement> _fields;
/// A list containing all of the methods contained in this class.
List<MethodElement> _methods;
/// Initialize a newly created class element to have the given [name] at the
/// given [offset] in the file that contains the declaration of this element.
AbstractClassElementImpl(String name, int offset) : super(name, offset);
AbstractClassElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created class element to have the given [name].
AbstractClassElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
AbstractClassElementImpl.forSerialized(
CompilationUnitElementImpl enclosingUnit)
: super.forSerialized(enclosingUnit);
@override
List<PropertyAccessorElement> get accessors {
return _accessors ?? const <PropertyAccessorElement>[];
}
/// Set the accessors contained in this class to the given [accessors].
void set accessors(List<PropertyAccessorElement> accessors) {
for (PropertyAccessorElement accessor in accessors) {
(accessor as PropertyAccessorElementImpl).enclosingElement = this;
}
this._accessors = accessors;
}
@override
String get displayName => name;
@override
List<FieldElement> get fields => _fields ?? const <FieldElement>[];
/// Set the fields contained in this class to the given [fields].
void set fields(List<FieldElement> fields) {
for (FieldElement field in fields) {
(field as FieldElementImpl).enclosingElement = this;
}
this._fields = fields;
}
@override
bool get isEnum => false;
@override
bool get isMixin => false;
@override
ElementKind get kind => ElementKind.CLASS;
@override
List<InterfaceType> get superclassConstraints => const <InterfaceType>[];
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitClassElement(this);
@deprecated
@override
NamedCompilationUnitMember computeNode() {
if (isEnum) {
return getNodeMatching((node) => node is EnumDeclaration);
} else {
return getNodeMatching(
(node) => node is ClassDeclaration || node is ClassTypeAlias);
}
}
@override
ElementImpl getChild(String identifier) {
//
// The casts in this method are safe because the set methods would have
// thrown a CCE if any of the elements in the arrays were not of the
// expected types.
//
for (PropertyAccessorElement accessor in accessors) {
PropertyAccessorElementImpl accessorImpl = accessor;
if (accessorImpl.identifier == identifier) {
return accessorImpl;
}
}
for (FieldElement field in fields) {
FieldElementImpl fieldImpl = field;
if (fieldImpl.identifier == identifier) {
return fieldImpl;
}
}
return null;
}
@override
FieldElement getField(String name) {
for (FieldElement fieldElement in fields) {
if (name == fieldElement.name) {
return fieldElement;
}
}
return null;
}
@override
PropertyAccessorElement getGetter(String getterName) {
int length = accessors.length;
for (int i = 0; i < length; i++) {
PropertyAccessorElement accessor = accessors[i];
if (accessor.isGetter && accessor.name == getterName) {
return accessor;
}
}
return null;
}
@override
MethodElement getMethod(String methodName) {
int length = methods.length;
for (int i = 0; i < length; i++) {
MethodElement method = methods[i];
if (method.name == methodName) {
return method;
}
}
return null;
}
@override
PropertyAccessorElement getSetter(String setterName) {
return getSetterFromAccessors(setterName, accessors);
}
@override
MethodElement lookUpConcreteMethod(
String methodName, LibraryElement library) =>
_first(getImplementationsOfMethod(this, methodName).where(
(MethodElement method) =>
!method.isAbstract && method.isAccessibleIn(library)));
@override
PropertyAccessorElement lookUpGetter(
String getterName, LibraryElement library) =>
_first(_implementationsOfGetter(getterName).where(
(PropertyAccessorElement getter) => getter.isAccessibleIn(library)));
@override
PropertyAccessorElement lookUpInheritedConcreteGetter(
String getterName, LibraryElement library) =>
_first(_implementationsOfGetter(getterName).where(
(PropertyAccessorElement getter) =>
!getter.isAbstract &&
getter.isAccessibleIn(library) &&
getter.enclosingElement != this));
ExecutableElement lookUpInheritedConcreteMember(
String name, LibraryElement library) {
if (name.endsWith('=')) {
return lookUpInheritedConcreteSetter(name, library);
} else {
return lookUpInheritedConcreteMethod(name, library) ??
lookUpInheritedConcreteGetter(name, library);
}
}
@override
MethodElement lookUpInheritedConcreteMethod(
String methodName, LibraryElement library) =>
_first(getImplementationsOfMethod(this, methodName).where(
(MethodElement method) =>
!method.isAbstract &&
method.isAccessibleIn(library) &&
method.enclosingElement != this));
@override
PropertyAccessorElement lookUpInheritedConcreteSetter(
String setterName, LibraryElement library) =>
_first(_implementationsOfSetter(setterName).where(
(PropertyAccessorElement setter) =>
!setter.isAbstract &&
setter.isAccessibleIn(library) &&
setter.enclosingElement != this));
@override
MethodElement lookUpInheritedMethod(
String methodName, LibraryElement library) =>
_first(getImplementationsOfMethod(this, methodName).where(
(MethodElement method) =>
method.isAccessibleIn(library) &&
method.enclosingElement != this));
@override
MethodElement lookUpMethod(String methodName, LibraryElement library) =>
lookUpMethodInClass(this, methodName, library);
@override
PropertyAccessorElement lookUpSetter(
String setterName, LibraryElement library) =>
_first(_implementationsOfSetter(setterName).where(
(PropertyAccessorElement setter) => setter.isAccessibleIn(library)));
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(accessors, visitor);
safelyVisitChildren(fields, visitor);
}
/// Return an iterable containing all of the implementations of a getter with
/// the given [getterName] that are defined in this class any any superclass
/// of this class (but not in interfaces).
///
/// The getters that are returned are not filtered in any way. In particular,
/// they can include getters that are not visible in some context. Clients
/// must perform any necessary filtering.
///
/// The getters are returned based on the depth of their defining class; if
/// this class contains a definition of the getter it will occur first, if
/// Object contains a definition of the getter it will occur last.
Iterable<PropertyAccessorElement> _implementationsOfGetter(
String getterName) sync* {
ClassElement classElement = this;
HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
while (classElement != null && visitedClasses.add(classElement)) {
PropertyAccessorElement getter = classElement.getGetter(getterName);
if (getter != null) {
yield getter;
}
for (InterfaceType mixin in classElement.mixins.reversed) {
getter = mixin.element?.getGetter(getterName);
if (getter != null) {
yield getter;
}
}
classElement = classElement.supertype?.element;
}
}
/// Return an iterable containing all of the implementations of a setter with
/// the given [setterName] that are defined in this class any any superclass
/// of this class (but not in interfaces).
///
/// The setters that are returned are not filtered in any way. In particular,
/// they can include setters that are not visible in some context. Clients
/// must perform any necessary filtering.
///
/// The setters are returned based on the depth of their defining class; if
/// this class contains a definition of the setter it will occur first, if
/// Object contains a definition of the setter it will occur last.
Iterable<PropertyAccessorElement> _implementationsOfSetter(
String setterName) sync* {
ClassElement classElement = this;
HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
while (classElement != null && visitedClasses.add(classElement)) {
PropertyAccessorElement setter = classElement.getSetter(setterName);
if (setter != null) {
yield setter;
}
for (InterfaceType mixin in classElement.mixins.reversed) {
setter = mixin.element?.getSetter(setterName);
if (setter != null) {
yield setter;
}
}
classElement = classElement.supertype?.element;
}
}
/// Return the [AbstractClassElementImpl] of the given [classElement]. May
/// throw an exception if the [AbstractClassElementImpl] cannot be provided
/// (should not happen though).
static AbstractClassElementImpl getImpl(ClassElement classElement) {
if (classElement is ClassElementHandle) {
return getImpl(classElement.actualElement);
}
return classElement as AbstractClassElementImpl;
}
/// Return an iterable containing all of the implementations of a method with
/// the given [methodName] that are defined in this class any any superclass
/// of this class (but not in interfaces).
///
/// The methods that are returned are not filtered in any way. In particular,
/// they can include methods that are not visible in some context. Clients
/// must perform any necessary filtering.
///
/// The methods are returned based on the depth of their defining class; if
/// this class contains a definition of the method it will occur first, if
/// Object contains a definition of the method it will occur last.
static Iterable<MethodElement> getImplementationsOfMethod(
ClassElement classElement, String methodName) sync* {
HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
while (classElement != null && visitedClasses.add(classElement)) {
MethodElement method = classElement.getMethod(methodName);
if (method != null) {
yield method;
}
for (InterfaceType mixin in classElement.mixins.reversed) {
method = mixin.element?.getMethod(methodName);
if (method != null) {
yield method;
}
}
classElement = classElement.supertype?.element;
}
}
static PropertyAccessorElement getSetterFromAccessors(
String setterName, List<PropertyAccessorElement> accessors) {
// TODO (jwren) revisit- should we append '=' here or require clients to
// include it?
// Do we need the check for isSetter below?
if (!StringUtilities.endsWithChar(setterName, 0x3D)) {
setterName += '=';
}
for (PropertyAccessorElement accessor in accessors) {
if (accessor.isSetter && accessor.name == setterName) {
return accessor;
}
}
return null;
}
static MethodElement lookUpMethodInClass(
ClassElement classElement, String methodName, LibraryElement library) {
return _first(getImplementationsOfMethod(classElement, methodName)
.where((MethodElement method) => method.isAccessibleIn(library)));
}
/// Return the first element from the given [iterable], or `null` if the
/// iterable is empty.
static E _first<E>(Iterable<E> iterable) {
if (iterable.isEmpty) {
return null;
}
return iterable.first;
}
}
/// For AST nodes that could be in both the getter and setter contexts
/// ([IndexExpression]s and [SimpleIdentifier]s), the additional resolved
/// elements are stored in the AST node, in an [AuxiliaryElements]. Because
/// resolved elements are either statically resolved or resolved using
/// propagated type information, this class is a wrapper for a pair of
/// [ExecutableElement]s, not just a single [ExecutableElement].
class AuxiliaryElements {
/// The element based on static type information, or `null` if the AST
/// structure has not been resolved or if the node could not be resolved.
final ExecutableElement staticElement;
/// Initialize a newly created pair to have both the [staticElement] and
/// `null`.
AuxiliaryElements(this.staticElement, ExecutableElement propagatedElement);
/// The element based on propagated type information, or `null` if the AST
/// structure has not been resolved or if the node could not be resolved.
ExecutableElement get propagatedElement => null;
}
/// An [AbstractClassElementImpl] which is a class.
class ClassElementImpl extends AbstractClassElementImpl
with TypeParameterizedElementMixin, SimplyBoundableMixin {
/// The unlinked representation of the class in the summary.
final UnlinkedClass _unlinkedClass;
/// If this class is resynthesized, whether it has a constant constructor.
bool _hasConstConstructorCached;
/// The superclass of the class, or `null` for [Object].
InterfaceType _supertype;
/// The type defined by the class.
InterfaceType _type;
/// A list containing all of the mixins that are applied to the class being
/// extended in order to derive the superclass of this class.
List<InterfaceType> _mixins;
/// A list containing all of the interfaces that are implemented by this
/// class.
List<InterfaceType> _interfaces;
/// For classes which are not mixin applications, a list containing all of the
/// constructors contained in this class, or `null` if the list of
/// constructors has not yet been built.
///
/// For classes which are mixin applications, the list of constructors is
/// computed on the fly by the [constructors] getter, and this field is
/// `null`.
List<ConstructorElement> _constructors;
/// A flag indicating whether the types associated with the instance members
/// of this class have been inferred.
bool _hasBeenInferred = false;
/// The version of this element. The version is changed when the element is
/// incrementally updated, so that its lists of constructors, accessors and
/// methods might be different.
int version = 0;
/// Initialize a newly created class element to have the given [name] at the
/// given [offset] in the file that contains the declaration of this element.
ClassElementImpl(String name, int offset)
: _unlinkedClass = null,
super(name, offset);
ClassElementImpl.forLinkedNode(CompilationUnitElementImpl enclosing,
Reference reference, AstNode linkedNode)
: _unlinkedClass = null,
super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created class element to have the given [name].
ClassElementImpl.forNode(Identifier name)
: _unlinkedClass = null,
super.forNode(name);
/// Initialize using the given serialized information.
ClassElementImpl.forSerialized(
this._unlinkedClass, CompilationUnitElementImpl enclosingUnit)
: super.forSerialized(enclosingUnit);
/// Set whether this class is abstract.
void set abstract(bool isAbstract) {
_assertNotResynthesized(_unlinkedClass);
setModifier(Modifier.ABSTRACT, isAbstract);
}
@override
List<PropertyAccessorElement> get accessors {
if (_accessors != null) return _accessors;
if (linkedNode != null) {
if (linkedNode is ClassOrMixinDeclaration) {
_createPropertiesAndAccessors();
assert(_accessors != null);
return _accessors;
} else {
return _accessors = const [];
}
}
if (_accessors == null) {
if (_unlinkedClass != null) {
_resynthesizeFieldsAndPropertyAccessors();
}
}
return _accessors ??= const <PropertyAccessorElement>[];
}
@override
void set accessors(List<PropertyAccessorElement> accessors) {
_assertNotResynthesized(_unlinkedClass);
super.accessors = accessors;
}
@override
List<InterfaceType> get allSupertypes {
List<InterfaceType> list = new List<InterfaceType>();
collectAllSupertypes(list, type, type);
return list;
}
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (_unlinkedClass != null) {
return _unlinkedClass.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (_unlinkedClass != null) {
return _unlinkedClass.codeRange?.offset;
}
return super.codeOffset;
}
@override
List<ConstructorElement> get constructors {
if (_constructors != null) {
return _constructors;
}
if (isMixinApplication) {
return _constructors = _computeMixinAppConstructors();
}
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var containerRef = reference.getChild('@constructor');
_constructors = context.getConstructors(linkedNode).map((node) {
var name = node.name?.name ?? '';
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as ConstructorElement;
}
return ConstructorElementImpl.forLinkedNode(this, reference, node);
}).toList();
if (_constructors.isEmpty) {
return _constructors = [
ConstructorElementImpl.forLinkedNode(
this,
containerRef.getChild(''),
null,
)
..isSynthetic = true
..name = ''
..nameOffset = -1,
];
}
}
if (_unlinkedClass != null) {
var unlinkedExecutables = _unlinkedClass.executables;
var length = unlinkedExecutables.length;
if (length != 0) {
var count = 0;
for (var i = 0; i < length; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.constructor) {
count++;
}
}
if (count != 0) {
var constructors = new List<ConstructorElement>(count);
var index = 0;
for (var i = 0; i < length; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.constructor) {
constructors[index++] =
new ConstructorElementImpl.forSerialized(e, this);
}
}
return _constructors = constructors;
}
}
_constructors = const <ConstructorElement>[];
}
if (_constructors.isEmpty) {
var constructor = new ConstructorElementImpl('', -1);
constructor.isSynthetic = true;
constructor.enclosingElement = this;
_constructors = <ConstructorElement>[constructor];
}
return _constructors;
}
/// Set the constructors contained in this class to the given [constructors].
///
/// Should only be used for class elements that are not mixin applications.
void set constructors(List<ConstructorElement> constructors) {
_assertNotResynthesized(_unlinkedClass);
assert(!isMixinApplication);
for (ConstructorElement constructor in constructors) {
(constructor as ConstructorElementImpl).enclosingElement = this;
}
this._constructors = constructors;
}
@override
String get documentationComment {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var comment = context.getDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (_unlinkedClass != null) {
return _unlinkedClass.documentationComment?.text;
}
return super.documentationComment;
}
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@override
List<FieldElement> get fields {
if (_fields != null) return _fields;
if (linkedNode != null) {
if (linkedNode is ClassOrMixinDeclaration) {
_createPropertiesAndAccessors();
assert(_fields != null);
return _fields;
} else {
_fields = const [];
}
}
if (_fields == null) {
if (_unlinkedClass != null) {
_resynthesizeFieldsAndPropertyAccessors();
}
}
return _fields ?? const <FieldElement>[];
}
@override
void set fields(List<FieldElement> fields) {
_assertNotResynthesized(_unlinkedClass);
super.fields = fields;
}
bool get hasBeenInferred {
if (linkedNode != null) {
return linkedContext.hasOverrideInferenceDone(linkedNode);
}
return _unlinkedClass != null || _hasBeenInferred;
}
void set hasBeenInferred(bool hasBeenInferred) {
if (linkedNode != null) {
return linkedContext.setOverrideInferenceDone(linkedNode);
}
_assertNotResynthesized(_unlinkedClass);
_hasBeenInferred = hasBeenInferred;
}
@override
bool get hasNonFinalField {
List<ClassElement> classesToVisit = new List<ClassElement>();
HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
classesToVisit.add(this);
while (!classesToVisit.isEmpty) {
ClassElement currentElement = classesToVisit.removeAt(0);
if (visitedClasses.add(currentElement)) {
// check fields
for (FieldElement field in currentElement.fields) {
if (!field.isFinal &&
!field.isConst &&
!field.isStatic &&
!field.isSynthetic) {
return true;
}
}
// check mixins
for (InterfaceType mixinType in currentElement.mixins) {
ClassElement mixinElement = mixinType.element;
classesToVisit.add(mixinElement);
}
// check super
InterfaceType supertype = currentElement.supertype;
if (supertype != null) {
ClassElement superElement = supertype.element;
if (superElement != null) {
classesToVisit.add(superElement);
}
}
}
}
// not found
return false;
}
/// Return `true` if the class has a concrete `noSuchMethod()` method distinct
/// from the one declared in class `Object`, as per the Dart Language
/// Specification (section 10.4).
bool get hasNoSuchMethod {
MethodElement method = lookUpConcreteMethod(
FunctionElement.NO_SUCH_METHOD_METHOD_NAME, library);
ClassElement definingClass = method?.enclosingElement;
return definingClass != null && !definingClass.type.isObject;
}
@override
bool get hasReferenceToSuper => hasModifier(Modifier.REFERENCES_SUPER);
/// Set whether this class references 'super'.
void set hasReferenceToSuper(bool isReferencedSuper) {
setModifier(Modifier.REFERENCES_SUPER, isReferencedSuper);
}
@override
bool get hasStaticMember {
for (MethodElement method in methods) {
if (method.isStatic) {
return true;
}
}
for (PropertyAccessorElement accessor in accessors) {
if (accessor.isStatic) {
return true;
}
}
return false;
}
@override
List<InterfaceType> get interfaces {
if (_interfaces != null) {
return _interfaces;
}
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var implementsClause = context.getImplementsClause(linkedNode);
if (implementsClause != null) {
return _interfaces = implementsClause.interfaces
.map((node) => node.type)
.whereType<InterfaceType>()
.where(_isInterfaceTypeInterface)
.toList();
} else {
return _interfaces = const [];
}
} else if (_unlinkedClass != null) {
var unlinkedInterfaces = _unlinkedClass.interfaces;
var length = unlinkedInterfaces.length;
if (length == 0) {
return _interfaces = const <InterfaceType>[];
}
ResynthesizerContext context = enclosingUnit.resynthesizerContext;
var interfaces = new List<InterfaceType>(length);
var index = 0;
var hasNonInterfaceType = false;
for (var i = 0; i < length; i++) {
var t = unlinkedInterfaces[i];
var type = context.resolveTypeRef(this, t);
if (_isInterfaceTypeInterface(type)) {
interfaces[index++] = type;
} else {
hasNonInterfaceType = true;
}
}
if (hasNonInterfaceType) {
interfaces = interfaces.sublist(0, index);
}
return _interfaces = interfaces;
}
return _interfaces = const <InterfaceType>[];
}
void set interfaces(List<InterfaceType> interfaces) {
_assertNotResynthesized(_unlinkedClass);
_interfaces = interfaces;
}
@override
bool get isAbstract {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isAbstract(linkedNode);
}
if (_unlinkedClass != null) {
return _unlinkedClass.isAbstract;
}
return hasModifier(Modifier.ABSTRACT);
}
@override
bool get isMixinApplication {
if (linkedNode != null) {
return linkedNode is ClassTypeAlias;
}
if (_unlinkedClass != null) {
return _unlinkedClass.isMixinApplication;
}
return hasModifier(Modifier.MIXIN_APPLICATION);
}
@override
bool get isOrInheritsProxy =>
_safeIsOrInheritsProxy(this, new HashSet<ClassElement>());
@override
bool get isProxy {
for (ElementAnnotation annotation in metadata) {
if (annotation.isProxy) {
return true;
}
}
return false;
}
@override
bool get isSimplyBounded {
if (linkedNode != null) {
return linkedContext.isSimplyBounded(linkedNode);
}
return super.isSimplyBounded;
}
@override
bool get isValidMixin {
if (hasReferenceToSuper) {
return false;
}
if (!supertype.isObject) {
return false;
}
for (ConstructorElement constructor in constructors) {
if (!constructor.isSynthetic && !constructor.isFactory) {
return false;
}
}
return true;
}
@override
List<ElementAnnotation> get metadata {
if (_unlinkedClass != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, _unlinkedClass.annotations);
}
return super.metadata;
}
@override
List<MethodElement> get methods {
if (_methods != null) {
return _methods;
}
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var containerRef = reference.getChild('@method');
return _methods = context
.getMethods(linkedNode)
.where((node) => node.propertyKeyword == null)
.map((node) {
var name = node.name.name;
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as MethodElement;
}
return MethodElementImpl.forLinkedNode(this, reference, node);
}).toList();
}
if (_unlinkedClass != null) {
var unlinkedExecutables = _unlinkedClass.executables;
var length = unlinkedExecutables.length;
if (length == 0) {
return _methods = const <MethodElement>[];
}
var count = 0;
for (var i = 0; i < length; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
count++;
}
}
if (count == 0) {
return _methods = const <MethodElement>[];
}
var methods = new List<MethodElement>(count);
var index = 0;
for (var i = 0; i < length; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.functionOrMethod) {
methods[index++] = new MethodElementImpl.forSerialized(e, this);
}
}
return _methods = methods;
}
return _methods = const <MethodElement>[];
}
/// Set the methods contained in this class to the given [methods].
void set methods(List<MethodElement> methods) {
_assertNotResynthesized(_unlinkedClass);
for (MethodElement method in methods) {
(method as MethodElementImpl).enclosingElement = this;
}
_methods = methods;
}
/// Set whether this class is a mixin application.
void set mixinApplication(bool isMixinApplication) {
_assertNotResynthesized(_unlinkedClass);
setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
}
@override
List<InterfaceType> get mixins {
if (_mixins != null) {
return _mixins;
}
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var withClause = context.getWithClause(linkedNode);
if (withClause != null) {
return _mixins = withClause.mixinTypes
.map((node) => node.type)
.whereType<InterfaceType>()
.where(_isInterfaceTypeInterface)
.toList();
} else {
return _mixins = const [];
}
} else if (_unlinkedClass != null) {
var unlinkedMixins = _unlinkedClass.mixins;
var length = unlinkedMixins.length;
if (length == 0) {
return _mixins = const <InterfaceType>[];
}
ResynthesizerContext context = enclosingUnit.resynthesizerContext;
var mixins = new List<InterfaceType>(length);
var index = 0;
var hasNonInterfaceType = false;
for (var i = 0; i < length; i++) {
var t = unlinkedMixins[i];
var type = context.resolveTypeRef(this, t);
if (_isInterfaceTypeInterface(type)) {
mixins[index++] = type;
} else {
hasNonInterfaceType = true;
}
}
if (hasNonInterfaceType) {
mixins = mixins.sublist(0, index);
}
return _mixins = mixins;
}
return _mixins = const <InterfaceType>[];
}
void set mixins(List<InterfaceType> mixins) {
_assertNotResynthesized(_unlinkedClass);
// Note: if we are using the analysis driver, the set of mixins has already
// been computed, and it's more accurate (since mixin arguments have been
// inferred). So we only store mixins if we are using the old task model.
if (_unlinkedClass == null) {
_mixins = mixins;
}
}
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (_unlinkedClass != null) {
return _unlinkedClass.name;
}
return super.name;
}
@override
int get nameOffset {
int offset = super.nameOffset;
if (offset == 0 && _unlinkedClass != null) {
return _unlinkedClass.nameOffset;
}
return offset;
}
/// Names of methods, getters, setters, and operators that this mixin
/// declaration super-invokes. For setters this includes the trailing "=".
/// The list will be empty if this class is not a mixin declaration.
List<String> get superInvokedNames => const <String>[];
@override
InterfaceType get supertype {
if (_supertype != null) return _supertype;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var coreTypes = context.bundleContext.elementFactory.coreTypes;
if (identical(this, coreTypes.objectClass)) {
return null;
}
var type = context.getSuperclass(linkedNode)?.type;
if (_isInterfaceTypeClass(type)) {
return _supertype = type;
}
return _supertype = this.context.typeProvider.objectType;
} else if (_unlinkedClass != null) {
if (_unlinkedClass.supertype != null) {
DartType type = enclosingUnit.resynthesizerContext
.resolveTypeRef(this, _unlinkedClass.supertype);
if (_isInterfaceTypeClass(type)) {
_supertype = type;
} else {
_supertype = context.typeProvider.objectType;
}
} else if (_unlinkedClass.hasNoSupertype) {
return null;
} else {
_supertype = context.typeProvider.objectType;
}
}
return _supertype;
}
void set supertype(InterfaceType supertype) {
_assertNotResynthesized(_unlinkedClass);
_supertype = supertype;
}
@override
InterfaceType get type {
if (_type == null) {
InterfaceTypeImpl type = new InterfaceTypeImpl(this);
type.typeArguments = typeParameterTypes;
_type = type;
}
return _type;
}
/// Set the type parameters defined for this class to the given
/// [typeParameters].
void set typeParameters(List<TypeParameterElement> typeParameters) {
_assertNotResynthesized(_unlinkedClass);
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
this._typeParameterElements = typeParameters;
}
@override
List<UnlinkedTypeParam> get unlinkedTypeParams =>
_unlinkedClass?.typeParameters;
@override
ConstructorElement get unnamedConstructor {
for (ConstructorElement element in constructors) {
String name = element.displayName;
if (name == null || name.isEmpty) {
return element;
}
}
return null;
}
/// Return whether the class is resynthesized and has a constant constructor.
bool get _hasConstConstructor {
if (_hasConstConstructorCached == null) {
_hasConstConstructorCached = false;
if (_unlinkedClass != null) {
_hasConstConstructorCached = _unlinkedClass.executables.any(
(c) => c.kind == UnlinkedExecutableKind.constructor && c.isConst);
}
}
return _hasConstConstructorCached;
}
@override
int get _notSimplyBoundedSlot => _unlinkedClass?.notSimplyBoundedSlot;
@override
void appendTo(StringBuffer buffer) {
if (isAbstract) {
buffer.write('abstract ');
}
buffer.write('class ');
String name = displayName;
if (name == null) {
buffer.write("{unnamed class}");
} else {
buffer.write(name);
}
int variableCount = typeParameters.length;
if (variableCount > 0) {
buffer.write("<");
for (int i = 0; i < variableCount; i++) {
if (i > 0) {
buffer.write(", ");
}
(typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
}
buffer.write(">");
}
if (supertype != null && !supertype.isObject) {
buffer.write(' extends ');
buffer.write(supertype.displayName);
}
if (mixins.isNotEmpty) {
buffer.write(' with ');
buffer.write(mixins.map((t) => t.displayName).join(', '));
}
if (interfaces.isNotEmpty) {
buffer.write(' implements ');
buffer.write(interfaces.map((t) => t.displayName).join(', '));
}
}
@override
ElementImpl getChild(String identifier) {
ElementImpl child = super.getChild(identifier);
if (child != null) {
return child;
}
//
// The casts in this method are safe because the set methods would have
// thrown a CCE if any of the elements in the arrays were not of the
// expected types.
//
for (ConstructorElement constructor in constructors) {
ConstructorElementImpl constructorImpl = constructor;
if (constructorImpl.identifier == identifier) {
return constructorImpl;
}
}
for (MethodElement method in methods) {
MethodElementImpl methodImpl = method;
if (methodImpl.identifier == identifier) {
return methodImpl;
}
}
for (TypeParameterElement typeParameter in typeParameters) {
TypeParameterElementImpl typeParameterImpl = typeParameter;
if (typeParameterImpl.identifier == identifier) {
return typeParameterImpl;
}
}
return null;
}
@override
ConstructorElement getNamedConstructor(String name) =>
getNamedConstructorFromList(name, constructors);
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(constructors, visitor);
safelyVisitChildren(methods, visitor);
safelyVisitChildren(typeParameters, visitor);
}
/// Compute a list of constructors for this class, which is a mixin
/// application. If specified, [visitedClasses] is a list of the other mixin
/// application classes which have been visited on the way to reaching this
/// one (this is used to detect circularities).
List<ConstructorElement> _computeMixinAppConstructors(
[List<ClassElementImpl> visitedClasses = null]) {
// First get the list of constructors of the superclass which need to be
// forwarded to this class.
Iterable<ConstructorElement> constructorsToForward;
if (supertype == null) {
// Shouldn't ever happen, since the only classes with no supertype are
// Object and mixins, and they aren't a mixin application. But for
// safety's sake just assume an empty list.
assert(false);
constructorsToForward = <ConstructorElement>[];
} else if (!supertype.element.isMixinApplication) {
var library = this.library;
constructorsToForward = supertype.element.constructors
.where((constructor) => constructor.isAccessibleIn(library));
} else {
if (visitedClasses == null) {
visitedClasses = <ClassElementImpl>[this];
} else {
if (visitedClasses.contains(this)) {
// Loop in the class hierarchy. Don't try to forward any
// constructors.
return <ConstructorElement>[];
}
visitedClasses.add(this);
}
try {
ClassElementImpl superElement =
AbstractClassElementImpl.getImpl(supertype.element)
as ClassElementImpl;
constructorsToForward =
superElement._computeMixinAppConstructors(visitedClasses);
} finally {
visitedClasses.removeLast();
}
}
// Figure out the type parameter substitution we need to perform in order
// to produce constructors for this class. We want to be robust in the
// face of errors, so drop any extra type arguments and fill in any missing
// ones with `dynamic`.
List<DartType> parameterTypes =
TypeParameterTypeImpl.getTypes(supertype.typeParameters);
List<DartType> argumentTypes = new List<DartType>.filled(
parameterTypes.length, DynamicTypeImpl.instance);
for (int i = 0; i < supertype.typeArguments.length; i++) {
if (i >= argumentTypes.length) {
break;
}
argumentTypes[i] = supertype.typeArguments[i];
}
// Now create an implicit constructor for every constructor found above,
// substituting type parameters as appropriate.
return constructorsToForward
.map((ConstructorElement superclassConstructor) {
ConstructorElementImpl implicitConstructor =
new ConstructorElementImpl(superclassConstructor.name, -1);
implicitConstructor.isSynthetic = true;
implicitConstructor.redirectedConstructor = superclassConstructor;
List<ParameterElement> superParameters = superclassConstructor.parameters;
int count = superParameters.length;
if (count > 0) {
List<ParameterElement> implicitParameters =
new List<ParameterElement>(count);
for (int i = 0; i < count; i++) {
ParameterElement superParameter = superParameters[i];
ParameterElementImpl implicitParameter;
if (superParameter is DefaultParameterElementImpl) {
implicitParameter =
new DefaultParameterElementImpl(superParameter.name, -1)
..constantInitializer = superParameter.constantInitializer;
} else {
implicitParameter =
new ParameterElementImpl(superParameter.name, -1);
}
implicitParameter.isConst = superParameter.isConst;
implicitParameter.isFinal = superParameter.isFinal;
// ignore: deprecated_member_use_from_same_package
implicitParameter.parameterKind = superParameter.parameterKind;
implicitParameter.isSynthetic = true;
implicitParameter.type =
superParameter.type.substitute2(argumentTypes, parameterTypes);
implicitParameters[i] = implicitParameter;
}
implicitConstructor.parameters = implicitParameters;
}
implicitConstructor.enclosingElement = this;
return implicitConstructor;
}).toList(growable: false);
}
void _createPropertiesAndAccessors() {
assert(_accessors == null);
assert(_fields == null);
var context = enclosingUnit.linkedContext;
var accessorList = <PropertyAccessorElementImpl>[];
var fieldList = <FieldElementImpl>[];
var fields = context.getFields(linkedNode);
for (var field in fields) {
var name = field.name.name;
var fieldElement = FieldElementImpl.forLinkedNodeFactory(
this,
reference.getChild('@field').getChild(name),
field,
);
fieldList.add(fieldElement);
accessorList.add(fieldElement.getter);
if (fieldElement.setter != null) {
accessorList.add(fieldElement.setter);
}
}
var methods = context.getMethods(linkedNode);
for (var method in methods) {
var isGetter = method.isGetter;
var isSetter = method.isSetter;
if (!isGetter && !isSetter) continue;
var name = method.name.name;
var containerRef = isGetter
? reference.getChild('@getter')
: reference.getChild('@setter');
var accessorElement = PropertyAccessorElementImpl.forLinkedNode(
this,
containerRef.getChild(name),
method,
);
accessorList.add(accessorElement);
var fieldRef = reference.getChild('@field').getChild(name);
FieldElementImpl field = fieldRef.element;
if (field == null) {
field = new FieldElementImpl(name, -1);
fieldRef.element = field;
field.enclosingElement = this;
field.isSynthetic = true;
field.isFinal = isGetter;
field.isStatic = accessorElement.isStatic;
fieldList.add(field);
} else {
field.isFinal = false;
}
accessorElement.variable = field;
if (isGetter) {
field.getter = accessorElement;
} else {
field.setter = accessorElement;
}
}
_accessors = accessorList;
_fields = fieldList;
}
/// Return `true` if the given [type] is an [InterfaceType] that can be used
/// as a class.
bool _isInterfaceTypeClass(DartType type) {
if (type is InterfaceType) {
var element = type.element;
return !element.isEnum && !element.isMixin;
}
return false;
}
/// Return `true` if the given [type] is an [InterfaceType] that can be used
/// as an interface or a mixin.
bool _isInterfaceTypeInterface(DartType type) {
return type is InterfaceType && !type.element.isEnum;
}
/// Resynthesize explicit fields and property accessors and fill [_fields] and
/// [_accessors] with explicit and implicit elements.
void _resynthesizeFieldsAndPropertyAccessors() {
assert(_fields == null);
assert(_accessors == null);
var unlinkedFields = _unlinkedClass.fields;
var unlinkedExecutables = _unlinkedClass.executables;
// Build explicit fields and implicit property accessors.
List<FieldElement> explicitFields;
List<PropertyAccessorElement> implicitAccessors;
var unlinkedFieldsLength = unlinkedFields.length;
if (unlinkedFieldsLength != 0) {
explicitFields = new List<FieldElement>(unlinkedFieldsLength);
implicitAccessors = <PropertyAccessorElement>[];
for (var i = 0; i < unlinkedFieldsLength; i++) {
var v = unlinkedFields[i];
FieldElementImpl field =
new FieldElementImpl.forSerializedFactory(v, this);
explicitFields[i] = field;
implicitAccessors.add(
new PropertyAccessorElementImpl_ImplicitGetter(field)
..enclosingElement = this);
if (!field.isConst && !field.isFinal) {
implicitAccessors.add(
new PropertyAccessorElementImpl_ImplicitSetter(field)
..enclosingElement = this);
}
}
} else {
explicitFields = const <FieldElement>[];
implicitAccessors = const <PropertyAccessorElement>[];
}
var unlinkedExecutablesLength = unlinkedExecutables.length;
var getterSetterCount = 0;
for (var i = 0; i < unlinkedExecutablesLength; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.getter ||
e.kind == UnlinkedExecutableKind.setter) {
getterSetterCount++;
}
}
// Build explicit property accessors and implicit fields.
List<PropertyAccessorElement> explicitAccessors;
Map<String, FieldElementImpl> implicitFields;
if (getterSetterCount != 0) {
explicitAccessors = new List<PropertyAccessorElement>(getterSetterCount);
implicitFields = <String, FieldElementImpl>{};
var index = 0;
for (var i = 0; i < unlinkedExecutablesLength; i++) {
var e = unlinkedExecutables[i];
if (e.kind == UnlinkedExecutableKind.getter ||
e.kind == UnlinkedExecutableKind.setter) {
PropertyAccessorElementImpl accessor =
new PropertyAccessorElementImpl.forSerialized(e, this);
explicitAccessors[index++] = accessor;
// Create or update the implicit field.
String fieldName = accessor.displayName;
FieldElementImpl field = implicitFields[fieldName];
if (field == null) {
field = new FieldElementImpl(fieldName, -1);
implicitFields[fieldName] = field;
field.enclosingElement = this;
field.isSynthetic = true;
field.isFinal = e.kind == UnlinkedExecutableKind.getter;
field.isStatic = e.isStatic;
} else {
field.isFinal = false;
}
accessor.variable = field;
if (e.kind == UnlinkedExecutableKind.getter) {
field.getter = accessor;
} else {
field.setter = accessor;
}
}
}
} else {
explicitAccessors = const <PropertyAccessorElement>[];
implicitFields = const <String, FieldElementImpl>{};
}
// Combine explicit and implicit fields and property accessors.
if (implicitFields.isEmpty) {
_fields = explicitFields;
} else if (explicitFields.isEmpty) {
_fields = implicitFields.values.toList(growable: false);
} else {
_fields = <FieldElement>[]
..addAll(explicitFields)
..addAll(implicitFields.values);
}
if (explicitAccessors.isEmpty) {
_accessors = implicitAccessors;
} else if (implicitAccessors.isEmpty) {
_accessors = explicitAccessors;
} else {
_accessors = <PropertyAccessorElement>[]
..addAll(explicitAccessors)
..addAll(implicitAccessors);
}
}
bool _safeIsOrInheritsProxy(
ClassElement element, HashSet<ClassElement> visited) {
if (visited.contains(element)) {
return false;
}
visited.add(element);
if (element.isProxy) {
return true;
} else if (element.supertype != null &&
_safeIsOrInheritsProxy(element.supertype.element, visited)) {
return true;
}
List<InterfaceType> supertypes = element.interfaces;
for (int i = 0; i < supertypes.length; i++) {
if (_safeIsOrInheritsProxy(supertypes[i].element, visited)) {
return true;
}
}
supertypes = element.mixins;
for (int i = 0; i < supertypes.length; i++) {
if (_safeIsOrInheritsProxy(supertypes[i].element, visited)) {
return true;
}
}
return false;
}
static void collectAllSupertypes(List<InterfaceType> supertypes,
InterfaceType startingType, InterfaceType excludeType) {
List<InterfaceType> typesToVisit = new List<InterfaceType>();
List<ClassElement> visitedClasses = new List<ClassElement>();
typesToVisit.add(startingType);
while (!typesToVisit.isEmpty) {
InterfaceType currentType = typesToVisit.removeAt(0);
ClassElement currentElement = currentType.element;
if (!visitedClasses.contains(currentElement)) {
visitedClasses.add(currentElement);
if (!identical(currentType, excludeType)) {
supertypes.add(currentType);
}
InterfaceType supertype = currentType.superclass;
if (supertype != null) {
typesToVisit.add(supertype);
}
for (InterfaceType type in currentType.superclassConstraints) {
typesToVisit.add(type);
}
for (InterfaceType type in currentType.interfaces) {
typesToVisit.add(type);
}
for (InterfaceType type in currentType.mixins) {
typesToVisit.add(type);
}
}
}
}
static ConstructorElement getNamedConstructorFromList(
String name, List<ConstructorElement> constructors) {
for (ConstructorElement element in constructors) {
String elementName = element.name;
if (elementName != null && elementName == name) {
return element;
}
}
return null;
}
}
/// A concrete implementation of a [CompilationUnitElement].
class CompilationUnitElementImpl extends UriReferencedElementImpl
implements CompilationUnitElement {
/// The context in which this unit is resynthesized, or `null` if the
/// element is not resynthesized a summary.
final ResynthesizerContext resynthesizerContext;
/// The unlinked representation of the unit in the summary.
final UnlinkedUnit _unlinkedUnit;
/// The unlinked representation of the part in the summary.
final UnlinkedPart _unlinkedPart;
final LinkedUnitContext linkedContext;
/// The source that corresponds to this compilation unit.
@override
Source source;
@override
LineInfo lineInfo;
/// The source of the library containing this compilation unit.
///
/// This is the same as the source of the containing [LibraryElement],
/// except that it does not require the containing [LibraryElement] to be
/// computed.
Source librarySource;
/// A table mapping the offset of a directive to the annotations associated
/// with that directive, or `null` if none of the annotations in the
/// compilation unit have annotations.
Map<int, List<ElementAnnotation>> annotationMap = null;
/// A list containing all of the top-level accessors (getters and setters)
/// contained in this compilation unit.
List<PropertyAccessorElement> _accessors;
/// A list containing all of the enums contained in this compilation unit.
List<ClassElement> _enums;
/// A list containing all of the top-level functions contained in this
/// compilation unit.
List<FunctionElement> _functions;
/// A list containing all of the mixins contained in this compilation unit.
List<ClassElement> _mixins;
/// A list containing all of the function type aliases contained in this
/// compilation unit.
List<FunctionTypeAliasElement> _typeAliases;
/// A list containing all of the classes contained in this compilation unit.
List<ClassElement> _types;
/// A list containing all of the variables contained in this compilation unit.
List<TopLevelVariableElement> _variables;
/// Resynthesized explicit top-level property accessors.
UnitExplicitTopLevelAccessors _explicitTopLevelAccessors;
/// Resynthesized explicit top-level variables.
UnitExplicitTopLevelVariables _explicitTopLevelVariables;
/// Description of top-level variable replacements that should be applied
/// to implicit top-level variables because of re-linking top-level property
/// accessors between different unit of the same library.
Map<TopLevelVariableElement, TopLevelVariableElement>
_topLevelVariableReplaceMap;
/// Initialize a newly created compilation unit element to have the given
/// [name].
CompilationUnitElementImpl()
: resynthesizerContext = null,
_unlinkedUnit = null,
_unlinkedPart = null,
linkedContext = null,
super(null, -1);
CompilationUnitElementImpl.forLinkedNode(LibraryElementImpl enclosingLibrary,
this.linkedContext, Reference reference, CompilationUnit linkedNode)
: resynthesizerContext = null,
_unlinkedUnit = null,
_unlinkedPart = null,
super.forLinkedNode(enclosingLibrary, reference, linkedNode);
/// Initialize using the given serialized information.
CompilationUnitElementImpl.forSerialized(LibraryElementImpl enclosingLibrary,
this.resynthesizerContext, this._unlinkedUnit, this._unlinkedPart)
: linkedContext = null,
super.forSerialized(null) {
_enclosingElement = enclosingLibrary;
_nameOffset = -1;
}
@override
List<PropertyAccessorElement> get accessors {
if (_accessors != null) return _accessors;
if (linkedNode != null) {
_createPropertiesAndAccessors(this);
assert(_accessors != null);
return _accessors;
}
if (_unlinkedUnit != null) {
_explicitTopLevelAccessors ??=
resynthesizerContext.buildTopLevelAccessors();
_explicitTopLevelVariables ??=
resynthesizerContext.buildTopLevelVariables();
}
if (_explicitTopLevelAccessors != null) {
_accessors = <PropertyAccessorElementImpl>[]
..addAll(_explicitTopLevelAccessors.accessors)
..addAll(_explicitTopLevelVariables.implicitAccessors);
}
return _accessors ?? const <PropertyAccessorElement>[];
}
/// Set the top-level accessors (getters and setters) contained in this
/// compilation unit to the given [accessors].
void set accessors(List<PropertyAccessorElement> accessors) {
for (PropertyAccessorElement accessor in accessors) {
(accessor as PropertyAccessorElementImpl).enclosingElement = this;
}
this._accessors = accessors;
}
@override
int get codeLength {
if (_unlinkedUnit != null) {
return _unlinkedUnit.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (_unlinkedUnit != null) {
return _unlinkedUnit.codeRange?.offset;
}
return super.codeOffset;
}
@override
LibraryElement get enclosingElement =>
super.enclosingElement as LibraryElement;
@override
CompilationUnitElementImpl get enclosingUnit {
return this;
}
@override
List<ClassElement> get enums {
if (_enums != null) return _enums;
if (linkedNode != null) {
var containerRef = reference.getChild('@enum');
CompilationUnit linkedNode = this.linkedNode;
_enums = linkedNode.declarations.whereType<EnumDeclaration>().map((node) {
var name = node.name.name;
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as EnumElementImpl;
}
return EnumElementImpl.forLinkedNode(this, reference, node);
}).toList();
}
if (_unlinkedUnit != null) {
return _enums = _unlinkedUnit.enums
.map((e) => new EnumElementImpl.forSerialized(e, this))
.toList(growable: false);
}
return _enums ??= const <ClassElement>[];
}
/// Set the enums contained in this compilation unit to the given [enums].
void set enums(List<ClassElement> enums) {
_assertNotResynthesized(_unlinkedUnit);
for (ClassElement enumDeclaration in enums) {
(enumDeclaration as EnumElementImpl).enclosingElement = this;
}
this._enums = enums;
}
@override
List<FunctionElement> get functions {
if (_functions != null) return _functions;
if (linkedNode != null) {
CompilationUnit linkedNode = this.linkedNode;
var containerRef = reference.getChild('@function');
return _functions = linkedNode.declarations
.whereType<FunctionDeclaration>()
.where((node) => !node.isGetter && !node.isSetter)
.map((node) {
var name = node.name.name;
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as FunctionElementImpl;
}
return FunctionElementImpl.forLinkedNode(this, reference, node);
}).toList();
} else if (_unlinkedUnit != null) {
_functions = _unlinkedUnit.executables
.where((e) => e.kind == UnlinkedExecutableKind.functionOrMethod)
.map((e) => new FunctionElementImpl.forSerialized(e, this))
.toList(growable: false);
}
return _functions ?? const <FunctionElement>[];
}
/// Set the top-level functions contained in this compilation unit to the
/// given[functions].
void set functions(List<FunctionElement> functions) {
for (FunctionElement function in functions) {
(function as FunctionElementImpl).enclosingElement = this;
}
this._functions = functions;
}
@override
List<FunctionTypeAliasElement> get functionTypeAliases {
if (_typeAliases != null) return _typeAliases;
if (linkedNode != null) {
CompilationUnit linkedNode = this.linkedNode;
var containerRef = reference.getChild('@typeAlias');
return _typeAliases = linkedNode.declarations.where((node) {
return node is FunctionTypeAlias || node is GenericTypeAlias;
}).map((node) {
String name;
if (node is FunctionTypeAlias) {
name = node.name.name;
} else {
name = (node as GenericTypeAlias).name.name;
}
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as GenericTypeAliasElementImpl;
}
return GenericTypeAliasElementImpl.forLinkedNode(this, reference, node);
}).toList();
}
if (_unlinkedUnit != null) {
_typeAliases = _unlinkedUnit.typedefs.map((t) {
return new GenericTypeAliasElementImpl.forSerialized(t, this);
}).toList(growable: false);
}
return _typeAliases ?? const <FunctionTypeAliasElement>[];
}
@override
int get hashCode => source.hashCode;
@override
bool get hasLoadLibraryFunction {
List<FunctionElement> functions = this.functions;
for (int i = 0; i < functions.length; i++) {
if (functions[i].name == FunctionElement.LOAD_LIBRARY_NAME) {
return true;
}
}
return false;
}
@override
String get identifier => source.encoding;
@override
ElementKind get kind => ElementKind.COMPILATION_UNIT;
@override
List<ElementAnnotation> get metadata {
if (_metadata == null) {
if (_unlinkedPart != null) {
return _metadata = _buildAnnotations(
library.definingCompilationUnit as CompilationUnitElementImpl,
_unlinkedPart.annotations);
}
}
return super.metadata;
}
@override
List<ClassElement> get mixins {
if (_mixins != null) return _mixins;
if (linkedNode != null) {
CompilationUnit linkedNode = this.linkedNode;
var containerRef = reference.getChild('@class');
var declarations = linkedNode.declarations;
return _mixins = declarations.whereType<MixinDeclaration>().map((node) {
var name = node.name.name;
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as MixinElementImpl;
}
return MixinElementImpl.forLinkedNode(this, reference, node);
}).toList();
}
if (_unlinkedUnit != null) {
return _mixins = _unlinkedUnit.mixins
.map((c) => new MixinElementImpl.forSerialized(c, this))
.toList(growable: false);
}
return _mixins ?? const <ClassElement>[];
}
/// Set the mixins contained in this compilation unit to the given [mixins].
void set mixins(List<ClassElement> mixins) {
_assertNotResynthesized(_unlinkedUnit);
for (MixinElementImpl type in mixins) {
type.enclosingElement = this;
}
this._mixins = mixins;
}
@override
List<TopLevelVariableElement> get topLevelVariables {
if (linkedNode != null) {
if (_variables != null) return _variables;
_createPropertiesAndAccessors(this);
assert(_variables != null);
return _variables;
}
if (_variables == null) {
if (_unlinkedUnit != null) {
_explicitTopLevelAccessors ??=
resynthesizerContext.buildTopLevelAccessors();
_explicitTopLevelVariables ??=
resynthesizerContext.buildTopLevelVariables();
}
if (_explicitTopLevelVariables != null) {
var variables = <TopLevelVariableElement>[]
..addAll(_explicitTopLevelVariables.variables)
..addAll(_explicitTopLevelAccessors.implicitVariables);
// Ensure that getters and setters in different units use
// the same top-level variables.
BuildLibraryElementUtils.patchTopLevelAccessors(library);
// Apply recorded patches to variables.
_topLevelVariableReplaceMap?.forEach((from, to) {
int index = variables.indexOf(from);
variables[index] = to;
});
_topLevelVariableReplaceMap = null;
_variables = variables;
}
}
return _variables ?? const <TopLevelVariableElement>[];
}
/// Set the top-level variables contained in this compilation unit to the
/// given[variables].
void set topLevelVariables(List<TopLevelVariableElement> variables) {
assert(!isResynthesized);
for (TopLevelVariableElement field in variables) {
(field as TopLevelVariableElementImpl).enclosingElement = this;
}
this._variables = variables;
}
/// Set the function type aliases contained in this compilation unit to the
/// given [typeAliases].
void set typeAliases(List<FunctionTypeAliasElement> typeAliases) {
_assertNotResynthesized(_unlinkedUnit);
for (FunctionTypeAliasElement typeAlias in typeAliases) {
(typeAlias as ElementImpl).enclosingElement = this;
}
this._typeAliases = typeAliases;
}
@override
TypeParameterizedElementMixin get typeParameterContext => null;
@override
List<ClassElement> get types {
if (_types != null) return _types;
if (linkedNode != null) {
CompilationUnit linkedNode = this.linkedNode;
var containerRef = reference.getChild('@class');
_types = <ClassElement>[];
for (var node in linkedNode.declarations) {
String name;
if (node is ClassDeclaration) {
name = node.name.name;
} else if (node is ClassTypeAlias) {
name = node.name.name;
} else {
continue;
}
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
_types.add(reference.element);
} else {
_types.add(
ClassElementImpl.forLinkedNode(this, reference, node),
);
}
}
return _types;
}
if (_unlinkedUnit != null) {
return _types = _unlinkedUnit.classes
.map((c) => new ClassElementImpl.forSerialized(c, this))
.toList(growable: false);
}
return _types ?? const <ClassElement>[];
}
/// Set the types contained in this compilation unit to the given [types].
void set types(List<ClassElement> types) {
_assertNotResynthesized(_unlinkedUnit);
for (ClassElement type in types) {
// Another implementation of ClassElement is _DeferredClassElement,
// which is used to resynthesize classes lazily. We cannot cast it
// to ClassElementImpl, and it already can provide correct values of the
// 'enclosingElement' property.
if (type is ClassElementImpl) {
type.enclosingElement = this;
}
}
this._types = types;
}
@override
bool operator ==(Object object) =>
object is CompilationUnitElementImpl && source == object.source;
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitCompilationUnitElement(this);
@override
void appendTo(StringBuffer buffer) {
if (source == null) {
buffer.write("{compilation unit}");
} else {
buffer.write(source.fullName);
}
}
@deprecated
@override
CompilationUnit computeNode() => unit;
/// Return the annotations associated with the directive at the given
/// [offset], or an empty list if the directive has no annotations or if
/// there is no directive at the given offset.
List<ElementAnnotation> getAnnotations(int offset) {
if (annotationMap == null) {
return const <ElementAnnotation>[];
}
return annotationMap[offset] ?? const <ElementAnnotation>[];
}
@override
ElementImpl getChild(String identifier) {
//
// The casts in this method are safe because the set methods would have
// thrown a CCE if any of the elements in the arrays were not of the
// expected types.
//
for (PropertyAccessorElement accessor in accessors) {
PropertyAccessorElementImpl accessorImpl = accessor;
if (accessorImpl.identifier == identifier) {
return accessorImpl;
}
}
for (TopLevelVariableElement variable in topLevelVariables) {
TopLevelVariableElementImpl variableImpl = variable;
if (variableImpl.identifier == identifier) {
return variableImpl;
}
}
for (FunctionElement function in functions) {
FunctionElementImpl functionImpl = function;
if (functionImpl.identifier == identifier) {
return functionImpl;
}
}
for (GenericTypeAliasElementImpl typeAlias in functionTypeAliases) {
if (typeAlias.identifier == identifier) {
return typeAlias;
}
}
for (ClassElement type in types) {
ClassElementImpl typeImpl = type;
if (typeImpl.name == identifier) {
return typeImpl;
}
}
for (ClassElement type in enums) {
EnumElementImpl typeImpl = type;
if (typeImpl.identifier == identifier) {
return typeImpl;
}
}
return null;
}
@override
ClassElement getEnum(String enumName) {
for (ClassElement enumDeclaration in enums) {
if (enumDeclaration.name == enumName) {
return enumDeclaration;
}
}
return null;
}
@override
ClassElement getType(String className) {
return getTypeFromTypes(className, types);
}
/// Replace the given [from] top-level variable with [to] in this compilation
/// unit.
void replaceTopLevelVariable(
TopLevelVariableElement from, TopLevelVariableElement to) {
if (_unlinkedUnit != null) {
// Getters and setter in different units should be patched to use the
// same variables before these variables were asked and returned.
assert(_variables == null);
_topLevelVariableReplaceMap ??=
<TopLevelVariableElement, TopLevelVariableElement>{};
_topLevelVariableReplaceMap[from] = to;
} else {
int index = _variables.indexOf(from);
_variables[index] = to;
}
}
/// Set the annotations associated with the directive at the given [offset] to
/// the given list of [annotations].
void setAnnotations(int offset, List<ElementAnnotation> annotations) {
annotationMap ??= new HashMap<int, List<ElementAnnotation>>();
annotationMap[offset] = annotations;
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(accessors, visitor);
safelyVisitChildren(enums, visitor);
safelyVisitChildren(functions, visitor);
safelyVisitChildren(functionTypeAliases, visitor);
safelyVisitChildren(mixins, visitor);
safelyVisitChildren(types, visitor);
safelyVisitChildren(topLevelVariables, visitor);
}
static ClassElement getTypeFromTypes(
String className, List<ClassElement> types) {
for (ClassElement type in types) {
if (type.name == className) {
return type;
}
}
return null;
}
static void _createPropertiesAndAccessors(CompilationUnitElementImpl unit) {
if (unit._variables != null) return;
assert(unit._accessors == null);
var accessorMap =
<CompilationUnitElementImpl, List<PropertyAccessorElementImpl>>{};
var variableMap =
<CompilationUnitElementImpl, List<TopLevelVariableElementImpl>>{};
var units = unit.library.units;
for (CompilationUnitElementImpl unit in units) {
var context = unit.linkedContext;
var accessorList = <PropertyAccessorElementImpl>[];
accessorMap[unit] = accessorList;
var variableList = <TopLevelVariableElementImpl>[];
variableMap[unit] = variableList;
var unitNode = unit.linkedContext.unit_withDeclarations;
var unitDeclarations = unitNode.declarations;
var variables = context.topLevelVariables(unitNode);
for (var variable in variables) {
var name = variable.name.name;
var reference = unit.reference.getChild('@variable').getChild(name);
var variableElement = TopLevelVariableElementImpl.forLinkedNodeFactory(
unit,
reference,
variable,
);
variableList.add(variableElement);
accessorList.add(variableElement.getter);
if (variableElement.setter != null) {
accessorList.add(variableElement.setter);
}
}
for (var node in unitDeclarations) {
if (node is FunctionDeclaration) {
var isGetter = node.isGetter;
var isSetter = node.isSetter;
if (!isGetter && !isSetter) continue;
var name = node.name.name;
var containerRef = isGetter
? unit.reference.getChild('@getter')
: unit.reference.getChild('@setter');
var accessorElement = PropertyAccessorElementImpl.forLinkedNode(
unit,
containerRef.getChild(name),
node,
);
accessorList.add(accessorElement);
var fieldRef = unit.reference.getChild('@field').getChild(name);
TopLevelVariableElementImpl field = fieldRef.element;
if (field == null) {
field = new TopLevelVariableElementImpl(name, -1);
fieldRef.element = field;
field.enclosingElement = unit;
field.isSynthetic = true;
field.isFinal = isGetter;
variableList.add(field);
} else {
field.isFinal = false;
}
accessorElement.variable = field;
if (isGetter) {
field.getter = accessorElement;
} else {
field.setter = accessorElement;
}
}
}
}
for (CompilationUnitElementImpl unit in units) {
unit._accessors = accessorMap[unit];
unit._variables = variableMap[unit];
}
}
}
/// A [FieldElement] for a 'const' or 'final' field that has an initializer.
///
/// TODO(paulberry): we should rename this class to reflect the fact that it's
/// used for both const and final fields. However, we shouldn't do so until
/// we've created an API for reading the values of constants; until that API is
/// available, clients are likely to read constant values by casting to
/// ConstFieldElementImpl, so it would be a breaking change to rename this
/// class.
class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement {
/// Initialize a newly created synthetic field element to have the given
/// [name] and [offset].
ConstFieldElementImpl(String name, int offset) : super(name, offset);
ConstFieldElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created field element to have the given [name].
ConstFieldElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
ConstFieldElementImpl.forSerialized(
UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(unlinkedVariable, enclosingElement);
}
/// A field element representing an enum constant.
class ConstFieldElementImpl_EnumValue extends ConstFieldElementImpl_ofEnum {
final UnlinkedEnumValue _unlinkedEnumValue;
final int _index;
ConstFieldElementImpl_EnumValue(
EnumElementImpl enumElement, this._unlinkedEnumValue, this._index)
: super(enumElement);
ConstFieldElementImpl_EnumValue.forLinkedNode(EnumElementImpl enumElement,
Reference reference, AstNode linkedNode, this._index)
: _unlinkedEnumValue = null,
super.forLinkedNode(enumElement, reference, linkedNode);
@override
Expression get constantInitializer => null;
@override
String get documentationComment {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var comment = context.getDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (_unlinkedEnumValue != null) {
return _unlinkedEnumValue.documentationComment?.text;
}
return super.documentationComment;
}
@override
EvaluationResultImpl get evaluationResult {
if (_evaluationResult == null) {
Map<String, DartObjectImpl> fieldMap = <String, DartObjectImpl>{
name: new DartObjectImpl(
context.typeProvider.intType, new IntState(_index))
};
DartObjectImpl value =
new DartObjectImpl(type, new GenericState(fieldMap));
_evaluationResult = new EvaluationResultImpl(value);
}
return _evaluationResult;
}
@override
List<ElementAnnotation> get metadata {
if (_unlinkedEnumValue != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, _unlinkedEnumValue.annotations);
}
return super.metadata;
}
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (_unlinkedEnumValue != null) {
return _unlinkedEnumValue.name;
}
return super.name;
}
@override
int get nameOffset {
if (linkedNode != null) {
return enclosingUnit.linkedContext.getNameOffset(linkedNode);
}
int offset = super.nameOffset;
if (offset == -1) {
if (_unlinkedEnumValue != null) {
return _unlinkedEnumValue.nameOffset;
}
}
return offset;
}
@override
InterfaceType get type => _enum.type;
}
/// The synthetic `values` field of an enum.
class ConstFieldElementImpl_EnumValues extends ConstFieldElementImpl_ofEnum {
ConstFieldElementImpl_EnumValues(EnumElementImpl enumElement)
: super(enumElement) {
isSynthetic = true;
}
@override
EvaluationResultImpl get evaluationResult {
if (_evaluationResult == null) {
List<DartObjectImpl> constantValues = <DartObjectImpl>[];
for (FieldElement field in _enum.fields) {
if (field is ConstFieldElementImpl_EnumValue) {
constantValues.add(field.evaluationResult.value);
}
}
_evaluationResult = new EvaluationResultImpl(
new DartObjectImpl(type, new ListState(constantValues)));
}
return _evaluationResult;
}
@override
String get name => 'values';
@override
InterfaceType get type {
if (_type == null) {
InterfaceType listType = context.typeProvider.listType;
return _type = listType.instantiate(<DartType>[_enum.type]);
}
return _type;
}
}
/// An abstract constant field of an enum.
abstract class ConstFieldElementImpl_ofEnum extends ConstFieldElementImpl {
final EnumElementImpl _enum;
ConstFieldElementImpl_ofEnum(this._enum) : super(null, -1) {
enclosingElement = _enum;
}
ConstFieldElementImpl_ofEnum.forLinkedNode(
this._enum, Reference reference, AstNode linkedNode)
: super.forLinkedNode(_enum, reference, linkedNode);
@override
void set evaluationResult(_) {
assert(false);
}
@override
bool get isConst => true;
@override
void set isConst(bool isConst) {
assert(false);
}
@override
bool get isConstantEvaluated => true;
@override
void set isFinal(bool isFinal) {
assert(false);
}
@override
bool get isStatic => true;
@override
void set isStatic(bool isStatic) {
assert(false);
}
void set type(DartType type) {
assert(false);
}
}
/// A [LocalVariableElement] for a local 'const' variable that has an
/// initializer.
class ConstLocalVariableElementImpl extends LocalVariableElementImpl
with ConstVariableElement {
/// Initialize a newly created local variable element to have the given [name]
/// and [offset].
ConstLocalVariableElementImpl(String name, int offset) : super(name, offset);
/// Initialize a newly created local variable element to have the given
/// [name].
ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
}
/// A concrete implementation of a [ConstructorElement].
class ConstructorElementImpl extends ExecutableElementImpl
implements ConstructorElement {
/// The constructor to which this constructor is redirecting.
ConstructorElement _redirectedConstructor;
/// The initializers for this constructor (used for evaluating constant
/// instance creation expressions).
List<ConstructorInitializer> _constantInitializers;
/// The offset of the `.` before this constructor name or `null` if not named.
int _periodOffset;
/// Return the offset of the character immediately following the last
/// character of this constructor's name, or `null` if not named.
int _nameEnd;
/// For every constructor we initially set this flag to `true`, and then
/// set it to `false` during computing constant values if we detect that it
/// is a part of a cycle.
bool _isCycleFree = true;
@override
bool isConstantEvaluated = false;
/// Initialize a newly created constructor element to have the given [name]
/// and [offset].
ConstructorElementImpl(String name, int offset) : super(name, offset);
ConstructorElementImpl.forLinkedNode(ClassElementImpl enclosingClass,
Reference reference, ConstructorDeclaration linkedNode)
: super.forLinkedNode(enclosingClass, reference, linkedNode);
/// Initialize a newly created constructor element to have the given [name].
ConstructorElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
ConstructorElementImpl.forSerialized(
UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
: super.forSerialized(serializedExecutable, enclosingClass);
/// Return the constant initializers for this element, which will be empty if
/// there are no initializers, or `null` if there was an error in the source.
List<ConstructorInitializer> get constantInitializers {
if (_constantInitializers != null) return _constantInitializers;
if (linkedNode != null) {
return _constantInitializers = linkedContext.getConstructorInitializers(
linkedNode,
);
}
if (serializedExecutable != null) {
return _constantInitializers = serializedExecutable.constantInitializers
.map((i) => _buildConstructorInitializer(i))
.toList(growable: false);
}
return _constantInitializers;
}
void set constantInitializers(
List<ConstructorInitializer> constantInitializers) {
_assertNotResynthesized(serializedExecutable);
_constantInitializers = constantInitializers;
}
@override
String get displayName {
if (linkedNode != null) {
return reference.name;
}
return super.displayName;
}
@override
ClassElementImpl get enclosingElement =>
super.enclosingElement as ClassElementImpl;
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext =>
super.enclosingElement as ClassElementImpl;
/// Set whether this constructor represents a factory method.
void set factory(bool isFactory) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.FACTORY, isFactory);
}
@override
bool get isConst {
if (linkedNode != null) {
ConstructorDeclaration linkedNode = this.linkedNode;
return linkedNode.constKeyword != null;
}
if (serializedExecutable != null) {
return serializedExecutable.isConst;
}
return hasModifier(Modifier.CONST);
}
/// Set whether this constructor represents a 'const' constructor.
void set isConst(bool isConst) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.CONST, isConst);
}
bool get isCycleFree {
if (serializedExecutable != null) {
return serializedExecutable.isConst &&
!enclosingUnit.resynthesizerContext
.isInConstCycle(serializedExecutable.constCycleSlot);
}
return _isCycleFree;
}
void set isCycleFree(bool isCycleFree) {
// This property is updated in ConstantEvaluationEngine even for
// resynthesized constructors, so we don't have the usual assert here.
_isCycleFree = isCycleFree;
}
@override
bool get isDefaultConstructor {
// unnamed
String name = this.name;
if (name != null && name.length != 0) {
return false;
}
// no required parameters
for (ParameterElement parameter in parameters) {
if (parameter.isNotOptional) {
return false;
}
}
// OK, can be used as default constructor
return true;
}
@override
bool get isFactory {
if (linkedNode != null) {
ConstructorDeclaration linkedNode = this.linkedNode;
return linkedNode.factoryKeyword != null;
}
if (serializedExecutable != null) {
return serializedExecutable.isFactory;
}
return hasModifier(Modifier.FACTORY);
}
@override
bool get isStatic => false;
@override
ElementKind get kind => ElementKind.CONSTRUCTOR;
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
return super.name;
}
@override
int get nameEnd {
if (serializedExecutable != null) {
if (serializedExecutable.name.isNotEmpty) {
return serializedExecutable.nameEnd;
} else {
return serializedExecutable.nameOffset + enclosingElement.name.length;
}
}
return _nameEnd;
}
void set nameEnd(int nameEnd) {
_assertNotResynthesized(serializedExecutable);
_nameEnd = nameEnd;
}
@override
int get periodOffset {
if (serializedExecutable != null) {
if (serializedExecutable.name.isNotEmpty) {
return serializedExecutable.periodOffset;
}
}
return _periodOffset;
}
void set periodOffset(int periodOffset) {
_assertNotResynthesized(serializedExecutable);
_periodOffset = periodOffset;
}
@override
ConstructorElement get redirectedConstructor {
if (_redirectedConstructor != null) return _redirectedConstructor;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
if (isFactory) {
var node = context.getConstructorRedirected(linkedNode);
return _redirectedConstructor = node?.staticElement;
} else {
var initializers = context.getConstructorInitializers(linkedNode);
for (var initializer in initializers) {
if (initializer is RedirectingConstructorInvocation) {
return _redirectedConstructor = initializer.staticElement;
}
}
}
return null;
}
if (serializedExecutable != null) {
if (serializedExecutable.isRedirectedConstructor) {
if (serializedExecutable.isFactory) {
_redirectedConstructor = enclosingUnit.resynthesizerContext
.resolveConstructorRef(
enclosingElement, serializedExecutable.redirectedConstructor);
} else {
_redirectedConstructor = enclosingElement.getNamedConstructor(
serializedExecutable.redirectedConstructorName);
}
} else {
return null;
}
}
return _redirectedConstructor;
}
void set redirectedConstructor(ConstructorElement redirectedConstructor) {
_assertNotResynthesized(serializedExecutable);
_redirectedConstructor = redirectedConstructor;
}
@override
DartType get returnType => enclosingElement.type;
void set returnType(DartType returnType) {
assert(false);
}
@override
FunctionType get type {
return _type ??= new FunctionTypeImpl(this);
}
void set type(FunctionType type) {
assert(false);
}
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitConstructorElement(this);
@override