blob: 2750b660a0c606c66ef654300a879c451a56367d [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
void appendTo(StringBuffer buffer) {
if (enclosingElement == null) {
String message;
String name = displayName;
if (name != null && !name.isEmpty) {
message =
'Found constructor element named $name with no enclosing element';
} else {
message = 'Found unnamed constructor element with no enclosing element';
}
AnalysisEngine.instance.logger.logError(message);
buffer.write('<unknown class>');
} else {
buffer.write(enclosingElement.displayName);
}
String name = displayName;
if (name != null && !name.isEmpty) {
buffer.write(".");
buffer.write(name);
}
super.appendTo(buffer);
}
@deprecated
@override
ConstructorDeclaration computeNode() =>
getNodeMatching((node) => node is ConstructorDeclaration);
/// Resynthesize the AST for the given serialized constructor initializer.
ConstructorInitializer _buildConstructorInitializer(
UnlinkedConstructorInitializer serialized) {
UnlinkedConstructorInitializerKind kind = serialized.kind;
String name = serialized.name;
List<Expression> arguments = <Expression>[];
{
int numArguments = serialized.arguments.length;
int numNames = serialized.argumentNames.length;
for (int i = 0; i < numArguments; i++) {
Expression expression = enclosingUnit.resynthesizerContext
.buildExpression(this, serialized.arguments[i]);
int nameIndex = numNames + i - numArguments;
if (nameIndex >= 0) {
expression = AstTestFactory.namedExpression2(
serialized.argumentNames[nameIndex], expression);
}
arguments.add(expression);
}
}
switch (kind) {
case UnlinkedConstructorInitializerKind.field:
ConstructorFieldInitializer initializer =
AstTestFactory.constructorFieldInitializer(
false,
name,
enclosingUnit.resynthesizerContext
.buildExpression(this, serialized.expression));
initializer.fieldName.staticElement = enclosingElement.getField(name);
return initializer;
case UnlinkedConstructorInitializerKind.assertInvocation:
return AstTestFactory.assertInitializer(
arguments[0], arguments.length > 1 ? arguments[1] : null);
case UnlinkedConstructorInitializerKind.superInvocation:
SuperConstructorInvocation initializer =
AstTestFactory.superConstructorInvocation2(
name.isNotEmpty ? name : null, arguments);
ClassElement superElement = enclosingElement.supertype.element;
ConstructorElement element = name.isEmpty
? superElement.unnamedConstructor
: superElement.getNamedConstructor(name);
initializer.staticElement = element;
initializer.constructorName?.staticElement = element;
return initializer;
case UnlinkedConstructorInitializerKind.thisInvocation:
RedirectingConstructorInvocation initializer =
AstTestFactory.redirectingConstructorInvocation2(
name.isNotEmpty ? name : null, arguments);
ConstructorElement element = name.isEmpty
? enclosingElement.unnamedConstructor
: enclosingElement.getNamedConstructor(name);
initializer.staticElement = element;
initializer.constructorName?.staticElement = element;
return initializer;
}
return null;
}
}
/// A [TopLevelVariableElement] for a top-level 'const' variable that has an
/// initializer.
class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl
with ConstVariableElement {
/// Initialize a newly created synthetic top-level variable element to have
/// the given [name] and [offset].
ConstTopLevelVariableElementImpl(String name, int offset)
: super(name, offset);
ConstTopLevelVariableElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created top-level variable element to have the given
/// [name].
ConstTopLevelVariableElementImpl.forNode(Identifier name)
: super.forNode(name);
/// Initialize using the given serialized information.
ConstTopLevelVariableElementImpl.forSerialized(
UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(unlinkedVariable, enclosingElement);
}
/// Mixin used by elements that represent constant variables and have
/// initializers.
///
/// Note that in correct Dart code, all constant variables must have
/// initializers. However, analyzer also needs to handle incorrect Dart code,
/// in which case there might be some constant variables that lack initializers.
/// This interface is only used for constant variables that have initializers.
///
/// This class is not intended to be part of the public API for analyzer.
mixin ConstVariableElement implements ElementImpl, ConstantEvaluationTarget {
/// If this element represents a constant variable, and it has an initializer,
/// a copy of the initializer for the constant. Otherwise `null`.
///
/// Note that in correct Dart code, all constant variables must have
/// initializers. However, analyzer also needs to handle incorrect Dart code,
/// in which case there might be some constant variables that lack
/// initializers.
Expression _constantInitializer;
EvaluationResultImpl _evaluationResult;
Expression get constantInitializer {
if (_constantInitializer != null) return _constantInitializer;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
return _constantInitializer = context.readInitializer(linkedNode);
}
if (_unlinkedConst != null) {
_constantInitializer = enclosingUnit.resynthesizerContext
.buildExpression(this, _unlinkedConst);
}
return _constantInitializer;
}
void set constantInitializer(Expression constantInitializer) {
_assertNotResynthesized(_unlinkedConst);
_constantInitializer = constantInitializer;
}
EvaluationResultImpl get evaluationResult => _evaluationResult;
void set evaluationResult(EvaluationResultImpl evaluationResult) {
_evaluationResult = evaluationResult;
}
@override
bool get isConstantEvaluated => _evaluationResult != null;
/// If this element is resynthesized from the summary, return the unlinked
/// initializer, otherwise return `null`.
UnlinkedExpr get _unlinkedConst;
/// Return a representation of the value of this variable, forcing the value
/// to be computed if it had not previously been computed, or `null` if either
/// this variable was not declared with the 'const' modifier or if the value
/// of this variable could not be computed because of errors.
DartObject computeConstantValue() {
if (evaluationResult == null) {
AnalysisOptionsImpl analysisOptions = context.analysisOptions;
computeConstants(context.typeProvider, context.typeSystem,
context.declaredVariables, [this], analysisOptions.experimentStatus);
}
return evaluationResult?.value;
}
}
/// A [FieldFormalParameterElementImpl] for parameters that have an initializer.
class DefaultFieldFormalParameterElementImpl
extends FieldFormalParameterElementImpl with ConstVariableElement {
/// Initialize a newly created parameter element to have the given [name] and
/// [nameOffset].
DefaultFieldFormalParameterElementImpl(String name, int nameOffset)
: super(name, nameOffset);
DefaultFieldFormalParameterElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created parameter element to have the given [name].
DefaultFieldFormalParameterElementImpl.forNode(Identifier name)
: super.forNode(name);
/// Initialize using the given serialized information.
DefaultFieldFormalParameterElementImpl.forSerialized(
UnlinkedParam unlinkedParam, ElementImpl enclosingElement)
: super.forSerialized(unlinkedParam, enclosingElement);
}
/// A [ParameterElement] for parameters that have an initializer.
class DefaultParameterElementImpl extends ParameterElementImpl
with ConstVariableElement {
/// Initialize a newly created parameter element to have the given [name] and
/// [nameOffset].
DefaultParameterElementImpl(String name, int nameOffset)
: super(name, nameOffset);
DefaultParameterElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created parameter element to have the given [name].
DefaultParameterElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
DefaultParameterElementImpl.forSerialized(
UnlinkedParam unlinkedParam, ElementImpl enclosingElement)
: super.forSerialized(unlinkedParam, enclosingElement);
@deprecated
@override
DefaultFormalParameter computeNode() =>
getNodeMatching((node) => node is DefaultFormalParameter);
}
/// The synthetic element representing the declaration of the type `dynamic`.
class DynamicElementImpl extends ElementImpl implements TypeDefiningElement {
/// Return the unique instance of this class.
static DynamicElementImpl get instance =>
DynamicTypeImpl.instance.element as DynamicElementImpl;
@override
DynamicTypeImpl type;
/// Initialize a newly created instance of this class. Instances of this class
/// should <b>not</b> be created except as part of creating the type
/// associated with this element. The single instance of this class should be
/// accessed through the method [instance].
DynamicElementImpl() : super(Keyword.DYNAMIC.lexeme, -1) {
setModifier(Modifier.SYNTHETIC, true);
}
@override
ElementKind get kind => ElementKind.DYNAMIC;
@override
T accept<T>(ElementVisitor<T> visitor) => null;
}
/// A concrete implementation of an [ElementAnnotation].
class ElementAnnotationImpl implements ElementAnnotation {
/// The name of the top-level variable used to mark that a function always
/// throws, for dead code purposes.
static String _ALWAYS_THROWS_VARIABLE_NAME = "alwaysThrows";
/// The name of the class used to mark an element as being deprecated.
static String _DEPRECATED_CLASS_NAME = "Deprecated";
/// The name of the top-level variable used to mark an element as being
/// deprecated.
static String _DEPRECATED_VARIABLE_NAME = "deprecated";
/// The name of the top-level variable used to mark a method as being a
/// factory.
static String _FACTORY_VARIABLE_NAME = "factory";
/// The name of the top-level variable used to mark a class and its subclasses
/// as being immutable.
static String _IMMUTABLE_VARIABLE_NAME = "immutable";
/// The name of the top-level variable used to mark a constructor as being
/// literal.
static String _LITERAL_VARIABLE_NAME = "literal";
/// The name of the top-level variable used to mark a type as having
/// "optional" type arguments.
static String _OPTIONAL_TYPE_ARGS_VARIABLE_NAME = "optionalTypeArgs";
/// The name of the top-level variable used to mark a function as running
/// a single test.
static String _IS_TEST_VARIABLE_NAME = "isTest";
/// The name of the top-level variable used to mark a function as running
/// a test group.
static String _IS_TEST_GROUP_VARIABLE_NAME = "isTestGroup";
/// The name of the class used to JS annotate an element.
static String _JS_CLASS_NAME = "JS";
/// The name of `js` library, used to define JS annotations.
static String _JS_LIB_NAME = "js";
/// The name of `meta` library, used to define analysis annotations.
static String _META_LIB_NAME = "meta";
/// The name of the top-level variable used to mark a method as requiring
/// overriders to call super.
static String _MUST_CALL_SUPER_VARIABLE_NAME = "mustCallSuper";
/// The name of `angular.meta` library, used to define angular analysis
/// annotations.
static String _NG_META_LIB_NAME = "angular.meta";
/// The name of the top-level variable used to mark a method as being expected
/// to override an inherited method.
static String _OVERRIDE_VARIABLE_NAME = "override";
/// The name of the top-level variable used to mark a method as being
/// protected.
static String _PROTECTED_VARIABLE_NAME = "protected";
/// The name of the top-level variable used to mark a class as implementing a
/// proxy object.
static String PROXY_VARIABLE_NAME = "proxy";
/// The name of the class used to mark a parameter as being required.
static String _REQUIRED_CLASS_NAME = "Required";
/// The name of the top-level variable used to mark a parameter as being
/// required.
static String _REQUIRED_VARIABLE_NAME = "required";
/// The name of the top-level variable used to mark a class as being sealed.
static String _SEALED_VARIABLE_NAME = "sealed";
/// The name of the top-level variable used to mark a method as being
/// visible for templates.
static String _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME = "visibleForTemplate";
/// The name of the top-level variable used to mark a method as being
/// visible for testing.
static String _VISIBLE_FOR_TESTING_VARIABLE_NAME = "visibleForTesting";
/// The element representing the field, variable, or constructor being used as
/// an annotation.
Element element;
/// The compilation unit in which this annotation appears.
CompilationUnitElementImpl compilationUnit;
/// The AST of the annotation itself, cloned from the resolved AST for the
/// source code.
Annotation annotationAst;
/// The result of evaluating this annotation as a compile-time constant
/// expression, or `null` if the compilation unit containing the variable has
/// not been resolved.
EvaluationResultImpl evaluationResult;
/// Initialize a newly created annotation. The given [compilationUnit] is the
/// compilation unit in which the annotation appears.
ElementAnnotationImpl(this.compilationUnit);
@override
List<AnalysisError> get constantEvaluationErrors =>
evaluationResult?.errors ?? const <AnalysisError>[];
@override
DartObject get constantValue => evaluationResult?.value;
@override
AnalysisContext get context => compilationUnit.library.context;
@override
bool get isAlwaysThrows =>
element is PropertyAccessorElement &&
element.name == _ALWAYS_THROWS_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isConstantEvaluated => evaluationResult != null;
@override
bool get isDeprecated {
if (element?.library?.isDartCore == true) {
if (element is ConstructorElement) {
return element.enclosingElement.name == _DEPRECATED_CLASS_NAME;
} else if (element is PropertyAccessorElement) {
return element.name == _DEPRECATED_VARIABLE_NAME;
}
}
return false;
}
@override
bool get isFactory =>
element is PropertyAccessorElement &&
element.name == _FACTORY_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isImmutable =>
element is PropertyAccessorElement &&
element.name == _IMMUTABLE_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isIsTest =>
element is PropertyAccessorElement &&
element.name == _IS_TEST_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isIsTestGroup =>
element is PropertyAccessorElement &&
element.name == _IS_TEST_GROUP_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isJS =>
element is ConstructorElement &&
element.enclosingElement.name == _JS_CLASS_NAME &&
element.library?.name == _JS_LIB_NAME;
@override
bool get isLiteral =>
element is PropertyAccessorElement &&
element.name == _LITERAL_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isMustCallSuper =>
element is PropertyAccessorElement &&
element.name == _MUST_CALL_SUPER_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isOptionalTypeArgs =>
element is PropertyAccessorElement &&
element.name == _OPTIONAL_TYPE_ARGS_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isOverride =>
element is PropertyAccessorElement &&
element.name == _OVERRIDE_VARIABLE_NAME &&
element.library?.isDartCore == true;
@override
bool get isProtected =>
element is PropertyAccessorElement &&
element.name == _PROTECTED_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isProxy =>
element is PropertyAccessorElement &&
element.name == PROXY_VARIABLE_NAME &&
element.library?.isDartCore == true;
@override
bool get isRequired =>
element is ConstructorElement &&
element.enclosingElement.name == _REQUIRED_CLASS_NAME &&
element.library?.name == _META_LIB_NAME ||
element is PropertyAccessorElement &&
element.name == _REQUIRED_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isSealed =>
element is PropertyAccessorElement &&
element.name == _SEALED_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@override
bool get isVisibleForTemplate =>
element is PropertyAccessorElement &&
element.name == _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME &&
element.library?.name == _NG_META_LIB_NAME;
@override
bool get isVisibleForTesting =>
element is PropertyAccessorElement &&
element.name == _VISIBLE_FOR_TESTING_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
/// Get the library containing this annotation.
Source get librarySource => compilationUnit.librarySource;
@override
Source get source => compilationUnit.source;
@override
DartObject computeConstantValue() {
if (evaluationResult == null) {
AnalysisOptionsImpl analysisOptions = context.analysisOptions;
computeConstants(context.typeProvider, context.typeSystem,
context.declaredVariables, [this], analysisOptions.experimentStatus);
}
return constantValue;
}
@override
String toSource() => annotationAst.toSource();
@override
String toString() => '@$element';
}
/// A base class for concrete implementations of an [Element].
abstract class ElementImpl implements Element {
/// An Unicode right arrow.
static final String RIGHT_ARROW = " \u2192 ";
static int _NEXT_ID = 0;
final int id = _NEXT_ID++;
/// The enclosing element of this element, or `null` if this element is at the
/// root of the element structure.
ElementImpl _enclosingElement;
Reference reference;
final AstNode linkedNode;
/// The name of this element.
String _name;
/// The offset of the name of this element in the file that contains the
/// declaration of this element.
int _nameOffset = 0;
/// A bit-encoded form of the modifiers associated with this element.
int _modifiers = 0;
/// A list containing all of the metadata associated with this element.
List<ElementAnnotation> _metadata;
/// A cached copy of the calculated hashCode for this element.
int _cachedHashCode;
/// A cached copy of the calculated location for this element.
ElementLocation _cachedLocation;
/// The documentation comment for this element.
String _docComment;
/// The offset of the beginning of the element's code in the file that
/// contains the element, or `null` if the element is synthetic.
int _codeOffset;
/// The length of the element's code, or `null` if the element is synthetic.
int _codeLength;
/// Initialize a newly created element to have the given [name] at the given
/// [_nameOffset].
ElementImpl(String name, this._nameOffset, {this.reference})
: linkedNode = null {
this._name = StringUtilities.intern(name);
this.reference?.element = this;
}
/// Initialize from linked node.
ElementImpl.forLinkedNode(
this._enclosingElement, this.reference, this.linkedNode) {
reference?.element ??= this;
}
/// Initialize a newly created element to have the given [name].
ElementImpl.forNode(Identifier name)
: this(name == null ? "" : name.name, name == null ? -1 : name.offset);
/// Initialize from serialized information.
ElementImpl.forSerialized(this._enclosingElement)
: reference = null,
linkedNode = null;
/// The length of the element's code, or `null` if the element is synthetic.
int get codeLength => _codeLength;
/// The offset of the beginning of the element's code in the file that
/// contains the element, or `null` if the element is synthetic.
int get codeOffset => _codeOffset;
@override
AnalysisContext get context {
if (_enclosingElement == null) {
return null;
}
return _enclosingElement.context;
}
@override
String get displayName => _name;
@override
String get documentationComment => _docComment;
/// The documentation comment source for this element.
void set documentationComment(String doc) {
assert(!isResynthesized);
_docComment = doc?.replaceAll('\r\n', '\n');
}
@override
Element get enclosingElement => _enclosingElement;
/// Set the enclosing element of this element to the given [element].
void set enclosingElement(Element element) {
_enclosingElement = element as ElementImpl;
}
/// Return the enclosing unit element (which might be the same as `this`), or
/// `null` if this element is not contained in any compilation unit.
CompilationUnitElementImpl get enclosingUnit {
return _enclosingElement?.enclosingUnit;
}
@override
bool get hasAlwaysThrows {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isAlwaysThrows) {
return true;
}
}
return false;
}
@override
bool get hasDeprecated {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isDeprecated) {
return true;
}
}
return false;
}
@override
bool get hasFactory {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isFactory) {
return true;
}
}
return false;
}
@override
int get hashCode {
// TODO: We might want to re-visit this optimization in the future.
// We cache the hash code value as this is a very frequently called method.
if (_cachedHashCode == null) {
_cachedHashCode = location.hashCode;
}
return _cachedHashCode;
}
@override
bool get hasIsTest {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isIsTest) {
return true;
}
}
return false;
}
@override
bool get hasIsTestGroup {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isIsTestGroup) {
return true;
}
}
return false;
}
@override
bool get hasJS {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isJS) {
return true;
}
}
return false;
}
@override
bool get hasLiteral {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isLiteral) {
return true;
}
}
return false;
}
@override
bool get hasMustCallSuper {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isMustCallSuper) {
return true;
}
}
return false;
}
@override
bool get hasOptionalTypeArgs {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isOptionalTypeArgs) {
return true;
}
}
return false;
}
@override
bool get hasOverride {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isOverride) {
return true;
}
}
return false;
}
@override
bool get hasProtected {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isProtected) {
return true;
}
}
return false;
}
@override
bool get hasRequired {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isRequired) {
return true;
}
}
return false;
}
@override
bool get hasSealed {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isSealed) {
return true;
}
}
return false;
}
@override
bool get hasVisibleForTemplate {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isVisibleForTemplate) {
return true;
}
}
return false;
}
@override
bool get hasVisibleForTesting {
var metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isVisibleForTesting) {
return true;
}
}
return false;
}
/// Return an identifier that uniquely identifies this element among the
/// children of this element's parent.
String get identifier => name;
@override
bool get isAlwaysThrows => hasAlwaysThrows;
@override
bool get isDeprecated => hasDeprecated;
@override
bool get isFactory => hasFactory;
@override
bool get isJS => hasJS;
@override
bool get isOverride => hasOverride;
@override
bool get isPrivate {
String name = displayName;
if (name == null) {
return true;
}
return Identifier.isPrivateName(name);
}
@override
bool get isProtected => hasProtected;
@override
bool get isPublic => !isPrivate;
@override
bool get isRequired => hasRequired;
/// Return `true` if this element is resynthesized from a summary.
bool get isResynthesized => enclosingUnit?.resynthesizerContext != null;
@override
bool get isSynthetic {
if (linkedNode != null) {
return linkedNode.isSynthetic;
}
return hasModifier(Modifier.SYNTHETIC);
}
/// Set whether this element is synthetic.
void set isSynthetic(bool isSynthetic) {
setModifier(Modifier.SYNTHETIC, isSynthetic);
}
@override
bool get isVisibleForTesting => hasVisibleForTesting;
@override
LibraryElement get library =>
getAncestor((element) => element is LibraryElement);
@override
Source get librarySource => library?.source;
LinkedUnitContext get linkedContext {
return _enclosingElement.linkedContext;
}
@override
ElementLocation get location {
if (_cachedLocation == null) {
if (library == null) {
return new ElementLocationImpl.con1(this);
}
_cachedLocation = new ElementLocationImpl.con1(this);
}
return _cachedLocation;
}
List<ElementAnnotation> get metadata {
if (linkedNode != null) {
if (_metadata != null) return _metadata;
var metadata = linkedContext.getMetadata(linkedNode);
return _metadata = _buildAnnotations2(enclosingUnit, metadata);
}
return _metadata ?? const <ElementAnnotation>[];
}
void set metadata(List<ElementAnnotation> metadata) {
assert(!isResynthesized);
_metadata = metadata;
}
@override
String get name => _name;
/// Changes the name of this element.
void set name(String name) {
this._name = name;
}
@override
int get nameLength => displayName != null ? displayName.length : 0;
@override
int get nameOffset => _nameOffset;
/// Sets the offset of the name of this element in the file that contains the
/// declaration of this element.
void set nameOffset(int offset) {
_nameOffset = offset;
}
@override
AnalysisSession get session {
return _enclosingElement?.session;
}
@override
Source get source {
if (_enclosingElement == null) {
return null;
}
return _enclosingElement.source;
}
/// Return the context to resolve type parameters in, or `null` if neither
/// this element nor any of its ancestors is of a kind that can declare type
/// parameters.
TypeParameterizedElementMixin get typeParameterContext {
return _enclosingElement?.typeParameterContext;
}
@deprecated
@override
CompilationUnit get unit => context.resolveCompilationUnit(source, library);
@override
bool operator ==(Object object) {
if (identical(this, object)) {
return true;
}
return object is Element &&
object.kind == kind &&
object.location == location;
}
/// Append to the given [buffer] a comma-separated list of the names of the
/// types of this element and every enclosing element.
void appendPathTo(StringBuffer buffer) {
Element element = this;
while (element != null) {
if (element != this) {
buffer.write(', ');
}
buffer.write(element.runtimeType);
String name = element.name;
if (name != null) {
buffer.write(' (');
buffer.write(name);
buffer.write(')');
}
element = element.enclosingElement;
}
}
/// Append a textual representation of this element to the given [buffer].
void appendTo(StringBuffer buffer) {
if (_name == null) {
buffer.write("<unnamed ");
buffer.write(runtimeType.toString());
buffer.write(">");
} else {
buffer.write(_name);
}
}
@override
String computeDocumentationComment() => documentationComment;
@deprecated
@override
AstNode computeNode() => getNodeMatching((node) => node is AstNode);
/// Set this element as the enclosing element for given [element].
void encloseElement(ElementImpl element) {
element.enclosingElement = this;
}
/// Set this element as the enclosing element for given [elements].
void encloseElements(List<Element> elements) {
for (Element element in elements) {
(element as ElementImpl)._enclosingElement = this;
}
}
@override
E getAncestor<E extends Element>(Predicate<Element> predicate) {
return getAncestorStatic<E>(_enclosingElement, predicate);
}
/// Return the child of this element that is uniquely identified by the given
/// [identifier], or `null` if there is no such child.
ElementImpl getChild(String identifier) => null;
@override
String getExtendedDisplayName(String shortName) {
if (shortName == null) {
shortName = displayName;
}
Source source = this.source;
if (source != null) {
return "$shortName (${source.fullName})";
}
return shortName;
}
/// Return the resolved [AstNode] of the given type enclosing [getNameOffset].
@deprecated
AstNode getNodeMatching(Predicate<AstNode> predicate) {
CompilationUnit unit = this.unit;
if (unit == null) {
return null;
}
int offset = nameOffset;
AstNode node = new NodeLocator(offset).searchWithin(unit);
if (node == null) {
return null;
}
return node.thisOrAncestorMatching(predicate);
}
/// Return `true` if this element has the given [modifier] associated with it.
bool hasModifier(Modifier modifier) =>
BooleanArray.get(_modifiers, modifier.ordinal);
@override
bool isAccessibleIn(LibraryElement library) {
if (Identifier.isPrivateName(name)) {
return library == this.library;
}
return true;
}
/// Use the given [visitor] to visit all of the [children] in the given array.
void safelyVisitChildren(List<Element> children, ElementVisitor visitor) {
if (children != null) {
for (Element child in children) {
child.accept(visitor);
}
}
}
/// Set the code range for this element.
void setCodeRange(int offset, int length) {
assert(!isResynthesized);
_codeOffset = offset;
_codeLength = length;
}
/// Set whether the given [modifier] is associated with this element to
/// correspond to the given [value].
void setModifier(Modifier modifier, bool value) {
_modifiers = BooleanArray.set(_modifiers, modifier.ordinal, value);
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
appendTo(buffer);
return buffer.toString();
}
@override
void visitChildren(ElementVisitor visitor) {
// There are no children to visit
}
/// Return annotations for the given [unlinkedConsts] in the [unit].
List<ElementAnnotation> _buildAnnotations(
CompilationUnitElementImpl unit, List<UnlinkedExpr> unlinkedConsts) {
int length = unlinkedConsts.length;
if (length != 0) {
List<ElementAnnotation> annotations = new List<ElementAnnotation>(length);
ResynthesizerContext context = unit.resynthesizerContext;
for (int i = 0; i < length; i++) {
annotations[i] = context.buildAnnotation(this, unlinkedConsts[i]);
}
return annotations;
} else {
return const <ElementAnnotation>[];
}
}
/// Return annotations for the given [nodeList] in the [unit].
List<ElementAnnotation> _buildAnnotations2(
CompilationUnitElementImpl unit, List<Annotation> nodeList) {
var length = nodeList.length;
if (length == 0) {
return const <ElementAnnotation>[];
}
var annotations = new List<ElementAnnotation>(length);
for (int i = 0; i < length; i++) {
var ast = nodeList[i];
annotations[i] = ElementAnnotationImpl(unit)
..annotationAst = ast
..element = ast.element;
}
return annotations;
}
/// If the element associated with the given [type] is a generic function type
/// element, then make it a child of this element. Return the [type] as a
/// convenience.
DartType _checkElementOfType(DartType type) {
Element element = type?.element;
if (element is GenericFunctionTypeElementImpl &&
element.enclosingElement == null) {
element.enclosingElement = this;
}
return type;
}
/// If the given [type] is a generic function type, then the element
/// associated with the type is implicitly a child of this element and should
/// be visited by the given [visitor].
void _safelyVisitPossibleChild(DartType type, ElementVisitor visitor) {
Element element = type?.element;
if (element is GenericFunctionTypeElementImpl &&
element.enclosingElement is! GenericTypeAliasElement) {
element.accept(visitor);
}
}
static int findElementIndexUsingIdentical(List items, Object item) {
int length = items.length;
for (int i = 0; i < length; i++) {
if (identical(items[i], item)) {
return i;
}
}
throw new StateError('Unable to find $item in $items');
}
static E getAncestorStatic<E extends Element>(
Element startingPoint, Predicate<Element> predicate) {
Element ancestor = startingPoint;
while (ancestor != null && !predicate(ancestor)) {
ancestor = ancestor.enclosingElement;
}
return ancestor as E;
}
}
/// A concrete implementation of an [ElementLocation].
class ElementLocationImpl implements ElementLocation {
/// The character used to separate components in the encoded form.
static int _SEPARATOR_CHAR = 0x3B;
/// The path to the element whose location is represented by this object.
List<String> _components;
/// The object managing [indexKeyId] and [indexLocationId].
Object indexOwner;
/// A cached id of this location in index.
int indexKeyId;
/// A cached id of this location in index.
int indexLocationId;
/// Initialize a newly created location to represent the given [element].
ElementLocationImpl.con1(Element element) {
List<String> components = new List<String>();
Element ancestor = element;
while (ancestor != null) {
components.insert(0, (ancestor as ElementImpl).identifier);
ancestor = ancestor.enclosingElement;
}
this._components = components;
}
/// Initialize a newly created location from the given [encoding].
ElementLocationImpl.con2(String encoding) {
this._components = _decode(encoding);
}
/// Initialize a newly created location from the given [components].
ElementLocationImpl.con3(List<String> components) {
this._components = components;
}
@override
List<String> get components => _components;
@override
String get encoding {
StringBuffer buffer = new StringBuffer();
int length = _components.length;
for (int i = 0; i < length; i++) {
if (i > 0) {
buffer.writeCharCode(_SEPARATOR_CHAR);
}
_encode(buffer, _components[i]);
}
return buffer.toString();
}
@override
int get hashCode {
int result = 0;
for (int i = 0; i < _components.length; i++) {
String component = _components[i];
result = JenkinsSmiHash.combine(result, component.hashCode);
}
return result;
}
@override
bool operator ==(Object object) {
if (identical(this, object)) {
return true;
}
if (object is ElementLocationImpl) {
List<String> otherComponents = object._components;
int length = _components.length;
if (otherComponents.length != length) {
return false;
}
for (int i = 0; i < length; i++) {
if (_components[i] != otherComponents[i]) {
return false;
}
}
return true;
}
return false;
}
@override
String toString() => encoding;
/// Decode the [encoding] of a location into a list of components and return
/// the components.
List<String> _decode(String encoding) {
List<String> components = new List<String>();
StringBuffer buffer = new StringBuffer();
int index = 0;
int length = encoding.length;
while (index < length) {
int currentChar = encoding.codeUnitAt(index);
if (currentChar == _SEPARATOR_CHAR) {
if (index + 1 < length &&
encoding.codeUnitAt(index + 1) == _SEPARATOR_CHAR) {
buffer.writeCharCode(_SEPARATOR_CHAR);
index += 2;
} else {
components.add(buffer.toString());
buffer = new StringBuffer();
index++;
}
} else {
buffer.writeCharCode(currentChar);
index++;
}
}
components.add(buffer.toString());
return components;
}
/// Append an encoded form of the given [component] to the given [buffer].
void _encode(StringBuffer buffer, String component) {
int length = component.length;
for (int i = 0; i < length; i++) {
int currentChar = component.codeUnitAt(i);
if (currentChar == _SEPARATOR_CHAR) {
buffer.writeCharCode(_SEPARATOR_CHAR);
}
buffer.writeCharCode(currentChar);
}
}
}
/// An [AbstractClassElementImpl] which is an enum.
class EnumElementImpl extends AbstractClassElementImpl {
/// The unlinked representation of the enum in the summary.
final UnlinkedEnum _unlinkedEnum;
/// The type defined by the enum.
InterfaceType _type;
/// 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.
EnumElementImpl(String name, int offset)
: _unlinkedEnum = null,
super(name, offset);
EnumElementImpl.forLinkedNode(CompilationUnitElementImpl enclosing,
Reference reference, EnumDeclaration linkedNode)
: _unlinkedEnum = null,
super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created class element to have the given [name].
EnumElementImpl.forNode(Identifier name)
: _unlinkedEnum = null,
super.forNode(name);
/// Initialize using the given serialized information.
EnumElementImpl.forSerialized(
this._unlinkedEnum, CompilationUnitElementImpl enclosingUnit)
: super.forSerialized(enclosingUnit);
/// Set whether this class is abstract.
void set abstract(bool isAbstract) {
_assertNotResynthesized(_unlinkedEnum);
}
@override
List<PropertyAccessorElement> get accessors {
if (_accessors == null) {
if (linkedNode != null) {
_resynthesizeMembers2();
}
if (_unlinkedEnum != null) {
_resynthesizeMembers();
}
}
return _accessors ?? const <PropertyAccessorElement>[];
}
@override
void set accessors(List<PropertyAccessorElement> accessors) {
_assertNotResynthesized(_unlinkedEnum);
super.accessors = accessors;
}
@override
List<InterfaceType> get allSupertypes => <InterfaceType>[supertype];
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (_unlinkedEnum != null) {
return _unlinkedEnum.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (_unlinkedEnum != null) {
return _unlinkedEnum.codeRange?.offset;
}
return super.codeOffset;
}
@override
List<ConstructorElement> get constructors {
// The equivalent code for enums in the spec shows a single constructor,
// but that constructor is not callable (since it is a compile-time error
// to subclass, mix-in, implement, or explicitly instantiate an enum).
// So we represent this as having no constructors.
return const <ConstructorElement>[];
}
@override
String get documentationComment {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var comment = context.getDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (_unlinkedEnum != null) {
return _unlinkedEnum.documentationComment?.text;
}
return super.documentationComment;
}
@override
List<FieldElement> get fields {
if (_fields == null) {
if (linkedNode != null) {
_resynthesizeMembers2();
}
if (_unlinkedEnum != null) {
_resynthesizeMembers();
}
}
return _fields ?? const <FieldElement>[];
}
@override
void set fields(List<FieldElement> fields) {
_assertNotResynthesized(_unlinkedEnum);
super.fields = fields;
}
@override
bool get hasNonFinalField => false;
@override
bool get hasReferenceToSuper => false;
@override
bool get hasStaticMember => true;
@override
List<InterfaceType> get interfaces => const <InterfaceType>[];
@override
bool get isAbstract => false;
@override
bool get isEnum => true;
@override
bool get isMixinApplication => false;
@override
bool get isOrInheritsProxy => false;
@override
bool get isProxy => false;
@override
bool get isSimplyBounded => true;
@override
bool get isValidMixin => false;
@override
List<ElementAnnotation> get metadata {
if (_unlinkedEnum != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, _unlinkedEnum.annotations);
}
return super.metadata;
}
@override
List<MethodElement> get methods {
if (_methods == null) {
if (linkedNode != null) {
_resynthesizeMembers2();
}
if (_unlinkedEnum != null) {
_resynthesizeMembers();
}
}
return _methods ?? const <MethodElement>[];
}
@override
List<InterfaceType> get mixins => const <InterfaceType>[];
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (_unlinkedEnum != null) {
return _unlinkedEnum.name;
}
return super.name;
}
@override
int get nameOffset {
int offset = super.nameOffset;
if (offset == 0 && _unlinkedEnum != null && _unlinkedEnum.nameOffset != 0) {
return _unlinkedEnum.nameOffset;
}
return offset;
}
@override
InterfaceType get supertype => context.typeProvider.objectType;
@override
InterfaceType get type {
if (_type == null) {
InterfaceTypeImpl type = new InterfaceTypeImpl(this);
type.typeArguments = const <DartType>[];
_type = type;
}
return _type;
}
@override
List<TypeParameterElement> get typeParameters =>
const <TypeParameterElement>[];
@override
ConstructorElement get unnamedConstructor => null;
@override
void appendTo(StringBuffer buffer) {
buffer.write('enum ');
String name = displayName;
if (name == null) {
buffer.write("{unnamed enum}");
} else {
buffer.write(name);
}
}
/// Create the only method enums have - `toString()`.
void createToStringMethodElement() {
var method = new MethodElementImpl('toString', -1);
method.isSynthetic = true;
if (linkedNode != null || _unlinkedEnum != null) {
method.returnType = context.typeProvider.stringType;
method.type = new FunctionTypeImpl(method);
}
method.enclosingElement = this;
if (linkedNode != null) {
method.reference = reference.getChild('@method').getChild('toString');
}
_methods = <MethodElement>[method];
}
@override
ConstructorElement getNamedConstructor(String name) => null;
void _resynthesizeMembers() {
List<FieldElementImpl> fields = <FieldElementImpl>[];
// Build the 'index' field.
fields.add(new FieldElementImpl('index', -1)
..enclosingElement = this
..isSynthetic = true
..isFinal = true
..type = context.typeProvider.intType);
// Build the 'values' field.
fields.add(new ConstFieldElementImpl_EnumValues(this));
// Build fields for all enum constants.
if (_unlinkedEnum != null) {
for (int i = 0; i < _unlinkedEnum.values.length; i++) {
UnlinkedEnumValue unlinkedValue = _unlinkedEnum.values[i];
ConstFieldElementImpl_EnumValue field =
new ConstFieldElementImpl_EnumValue(this, unlinkedValue, i);
fields.add(field);
}
}
// done
_fields = fields;
_accessors = fields
.map((FieldElementImpl field) =>
new PropertyAccessorElementImpl_ImplicitGetter(field)
..enclosingElement = this)
.toList(growable: false);
createToStringMethodElement();
}
void _resynthesizeMembers2() {
var fields = <FieldElementImpl>[];
var getters = <PropertyAccessorElementImpl>[];
// Build the 'index' field.
{
var field = FieldElementImpl('index', -1)
..enclosingElement = this
..isSynthetic = true
..isFinal = true
..type = context.typeProvider.intType;
fields.add(field);
getters.add(PropertyAccessorElementImpl_ImplicitGetter(field,
reference: reference.getChild('@getter').getChild('index'))
..enclosingElement = this);
}
// Build the 'values' field.
{
var field = ConstFieldElementImpl_EnumValues(this);
fields.add(field);
getters.add(PropertyAccessorElementImpl_ImplicitGetter(field,
reference: reference.getChild('@getter').getChild('values'))
..enclosingElement = this);
}
// Build fields for all enum constants.
var containerRef = this.reference.getChild('@constant');
var constants = linkedContext.getEnumConstants(linkedNode);
for (var i = 0; i < constants.length; ++i) {
var constant = constants[i];
var name = constant.name.name;
var reference = containerRef.getChild(name);
var field = new ConstFieldElementImpl_EnumValue.forLinkedNode(
this, reference, constant, i);
fields.add(field);
getters.add(field.getter);
}
_fields = fields;
_accessors = getters;
createToStringMethodElement();
}
}
/// A base class for concrete implementations of an [ExecutableElement].
abstract class ExecutableElementImpl extends ElementImpl
with TypeParameterizedElementMixin
implements ExecutableElement {
/// The unlinked representation of the executable in the summary.
final UnlinkedExecutable serializedExecutable;
/// A list containing all of the parameters defined by this executable
/// element.
List<ParameterElement> _parameters;
/// The declared return type of this executable element.
DartType _declaredReturnType;
/// The inferred return type of this executable element.
DartType _returnType;
/// The type of function defined by this executable element.
FunctionType _type;
/// Initialize a newly created executable element to have the given [name] and
/// [offset].
ExecutableElementImpl(String name, int offset, {Reference reference})
: serializedExecutable = null,
super(name, offset, reference: reference);
/// Initialize using the given linked node.
ExecutableElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: serializedExecutable = null,
super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created executable element to have the given [name].
ExecutableElementImpl.forNode(Identifier name)
: serializedExecutable = null,
super.forNode(name);
/// Initialize using the given serialized information.
ExecutableElementImpl.forSerialized(
this.serializedExecutable, ElementImpl enclosingElement)
: super.forSerialized(enclosingElement);
/// Set whether this executable element's body is asynchronous.
void set asynchronous(bool isAsynchronous) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.ASYNCHRONOUS, isAsynchronous);
}
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.codeRange?.offset;
}
return super.codeOffset;
}
void set declaredReturnType(DartType returnType) {
_assertNotResynthesized(serializedExecutable);
_declaredReturnType = _checkElementOfType(returnType);
}
@override
String get displayName {
if (linkedNode != null) {
return reference.name;
}
if (serializedExecutable != null) {
return serializedExecutable.name;
}
return super.displayName;
}
@override
String get documentationComment {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var comment = context.getDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (serializedExecutable != null) {
return serializedExecutable.documentationComment?.text;
}
return super.documentationComment;
}
/// Set whether this executable element is external.
void set external(bool isExternal) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.EXTERNAL, isExternal);
}
/// Set whether this method's body is a generator.
void set generator(bool isGenerator) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.GENERATOR, isGenerator);
}
@override
bool get hasImplicitReturnType {
if (linkedNode != null) {
return linkedContext.hasImplicitReturnType(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.returnType == null &&
serializedExecutable.kind != UnlinkedExecutableKind.constructor;
}
return hasModifier(Modifier.IMPLICIT_TYPE);
}
/// Set whether this executable element has an implicit return type.
void set hasImplicitReturnType(bool hasImplicitReturnType) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.IMPLICIT_TYPE, hasImplicitReturnType);
}
@override
bool get isAbstract {
if (linkedNode != null) {
return !isExternal && enclosingUnit.linkedContext.isAbstract(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.isAbstract;
}
return hasModifier(Modifier.ABSTRACT);
}
@override
bool get isAsynchronous {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isAsynchronous(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.isAsynchronous;
}
return hasModifier(Modifier.ASYNCHRONOUS);
}
@override
bool get isExternal {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isExternal(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.isExternal;
}
return hasModifier(Modifier.EXTERNAL);
}
@override
bool get isGenerator {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isGenerator(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.isGenerator;
}
return hasModifier(Modifier.GENERATOR);
}
@override
bool get isOperator => false;
@override
bool get isSynchronous => !isAsynchronous;
@override
List<ElementAnnotation> get metadata {
if (serializedExecutable != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, serializedExecutable.annotations);
}
return super.metadata;
}
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (serializedExecutable != null) {
return serializedExecutable.name;
}
return super.name;
}
@override
int get nameOffset {
if (linkedNode != null) {
return enclosingUnit.linkedContext.getNameOffset(linkedNode);
}
int offset = super.nameOffset;
if (offset == 0 && serializedExecutable != null) {
return serializedExecutable.nameOffset;
}
return offset;
}
@override
List<ParameterElement> get parameters {
if (_parameters != null) return _parameters;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var containerRef = reference.getChild('@parameter');
var formalParameters = context.getFormalParameters(linkedNode);
_parameters = ParameterElementImpl.forLinkedNodeList(
this,
context,
containerRef,
formalParameters,
);
}
if (serializedExecutable != null) {
_parameters = ParameterElementImpl.resynthesizeList(
serializedExecutable.parameters, this);
}
return _parameters ??= const <ParameterElement>[];
}
/// Set the parameters defined by this executable element to the given
/// [parameters].
void set parameters(List<ParameterElement> parameters) {
_assertNotResynthesized(serializedExecutable);
for (ParameterElement parameter in parameters) {
(parameter as ParameterElementImpl).enclosingElement = this;
}
this._parameters = parameters;
}
@override
DartType get returnType {
if (linkedNode != null) {
if (_returnType != null) return _returnType;
var context = enclosingUnit.linkedContext;
return _returnType = context.getReturnType(linkedNode);
}
if (serializedExecutable != null &&
_declaredReturnType == null &&
_returnType == null) {
bool isSetter =
serializedExecutable.kind == UnlinkedExecutableKind.setter;
_returnType = enclosingUnit.resynthesizerContext
.resolveLinkedType(this, serializedExecutable.inferredReturnTypeSlot);
_declaredReturnType = enclosingUnit.resynthesizerContext.resolveTypeRef(
this, serializedExecutable.returnType,
defaultVoid: isSetter, declaredType: true);
}
return _returnType ?? _declaredReturnType;
}
void set returnType(DartType returnType) {
if (linkedNode != null) {
linkedContext.setReturnType(linkedNode, returnType);
}
_assertNotResynthesized(serializedExecutable);
_returnType = _checkElementOfType(returnType);
}
@override
FunctionType get type {
if (linkedNode != null) {
return _type ??= new FunctionTypeImpl(this);
}
if (serializedExecutable != null) {
return _type ??= new FunctionTypeImpl(this);
}
return _type;
}
void set type(FunctionType type) {
_assertNotResynthesized(serializedExecutable);
_type = type;
}
/// Set the type parameters defined by this executable element to the given
/// [typeParameters].
void set typeParameters(List<TypeParameterElement> typeParameters) {
_assertNotResynthesized(serializedExecutable);
for (TypeParameterElement parameter in typeParameters) {
(parameter as TypeParameterElementImpl).enclosingElement = this;
}
this._typeParameterElements = typeParameters;
}
@override
List<UnlinkedTypeParam> get unlinkedTypeParams =>
serializedExecutable?.typeParameters;
@override
void appendTo(StringBuffer buffer) {
if (this.kind != ElementKind.GETTER) {
int typeParameterCount = typeParameters.length;
if (typeParameterCount > 0) {
buffer.write('<');
for (int i = 0; i < typeParameterCount; i++) {
if (i > 0) {
buffer.write(", ");
}
(typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
}
buffer.write('>');
}
buffer.write("(");
String closing = null;
ParameterKind kind = ParameterKind.REQUIRED;
int parameterCount = parameters.length;
for (int i = 0; i < parameterCount; i++) {
if (i > 0) {
buffer.write(", ");
}
ParameterElement parameter = parameters[i];
// ignore: deprecated_member_use_from_same_package
ParameterKind parameterKind = parameter.parameterKind;
if (parameterKind != kind) {
if (closing != null) {
buffer.write(closing);
}
if (parameterKind == ParameterKind.POSITIONAL) {
buffer.write("[");
closing = "]";
} else if (parameterKind == ParameterKind.NAMED) {
buffer.write("{");
closing = "}";
} else {
closing = null;
}
}
kind = parameterKind;
parameter.appendToWithoutDelimiters(buffer);
}
if (closing != null) {
buffer.write(closing);
}
buffer.write(")");
}
if (type != null) {
buffer.write(ElementImpl.RIGHT_ARROW);
buffer.write(type.returnType);
}
}
@override
ElementImpl getChild(String identifier) {
for (ParameterElement parameter in parameters) {
ParameterElementImpl parameterImpl = parameter;
if (parameterImpl.identifier == identifier) {
return parameterImpl;
}
}
return null;
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
_safelyVisitPossibleChild(returnType, visitor);
safelyVisitChildren(typeParameters, visitor);
safelyVisitChildren(parameters, visitor);
}
}
/// A concrete implementation of an [ExportElement].
class ExportElementImpl extends UriReferencedElementImpl
implements ExportElement {
/// The unlinked representation of the export in the summary.
final UnlinkedExportPublic _unlinkedExportPublic;
/// The unlinked representation of the export in the summary.
final UnlinkedExportNonPublic _unlinkedExportNonPublic;
/// The library that is exported from this library by this export directive.
LibraryElement _exportedLibrary;
/// The combinators that were specified as part of the export directive in the
/// order in which they were specified.
List<NamespaceCombinator> _combinators;
/// The URI that was selected based on the declared variables.
String _selectedUri;
/// Initialize a newly created export element at the given [offset].
ExportElementImpl(int offset)
: _unlinkedExportPublic = null,
_unlinkedExportNonPublic = null,
super(null, offset);
ExportElementImpl.forLinkedNode(
LibraryElementImpl enclosing, ExportDirective linkedNode)
: _unlinkedExportPublic = null,
_unlinkedExportNonPublic = null,
super.forLinkedNode(enclosing, null, linkedNode);
/// Initialize using the given serialized information.
ExportElementImpl.forSerialized(this._unlinkedExportPublic,
this._unlinkedExportNonPublic, LibraryElementImpl enclosingLibrary)
: super.forSerialized(enclosingLibrary);
@override
List<NamespaceCombinator> get combinators {
if (_combinators != null) return _combinators;
if (linkedNode != null) {
ExportDirective node = linkedNode;
return _combinators = ImportElementImpl._buildCombinators2(
enclosingUnit.linkedContext,
node.combinators,
);
}
if (_unlinkedExportPublic != null) {
return _combinators = ImportElementImpl._buildCombinators(
_unlinkedExportPublic.combinators);
}
return _combinators ?? const <NamespaceCombinator>[];
}
void set combinators(List<NamespaceCombinator> combinators) {
_assertNotResynthesized(_unlinkedExportPublic);
_combinators = combinators;
}
@override
CompilationUnitElementImpl get enclosingUnit {
LibraryElementImpl enclosingLibrary = enclosingElement;
return enclosingLibrary._definingCompilationUnit;
}
@override
LibraryElement get exportedLibrary {
if (_exportedLibrary != null) return _exportedLibrary;
if (linkedNode != null) {
return _exportedLibrary = linkedContext.directiveLibrary(linkedNode);
}
if (_unlinkedExportNonPublic != null) {
LibraryElementImpl library = enclosingElement as LibraryElementImpl;
_exportedLibrary = library.resynthesizerContext.buildExportedLibrary(uri);
}
return _exportedLibrary;
}
void set exportedLibrary(LibraryElement exportedLibrary) {
_assertNotResynthesized(_unlinkedExportNonPublic);
_exportedLibrary = exportedLibrary;
}
@override
String get identifier => exportedLibrary.name;
@override
ElementKind get kind => ElementKind.EXPORT;
@override
List<ElementAnnotation> get metadata {
if (_metadata == null) {
if (_unlinkedExportNonPublic != null) {
return _metadata = _buildAnnotations(library.definingCompilationUnit,
_unlinkedExportNonPublic.annotations);
}
}
return super.metadata;
}
void set metadata(List<ElementAnnotation> metadata) {
_assertNotResynthesized(_unlinkedExportNonPublic);
super.metadata = metadata;
}
@override
int get nameOffset {
if (linkedNode != null) {
return linkedContext.getDirectiveOffset(linkedNode);
}
int offset = super.nameOffset;
if (offset == 0 && _unlinkedExportNonPublic != null) {
return _unlinkedExportNonPublic.offset;
}
return offset;
}
@override
String get uri {
if (_unlinkedExportPublic != null) {
return _selectedUri ??= _selectUri(
_unlinkedExportPublic.uri, _unlinkedExportPublic.configurations);
}
return super.uri;
}
@override
void set uri(String uri) {
_assertNotResynthesized(_unlinkedExportPublic);
super.uri = uri;
}
@override
int get uriEnd {
if (_unlinkedExportNonPublic != null) {
return _unlinkedExportNonPublic.uriEnd;
}
return super.uriEnd;
}
@override
void set uriEnd(int uriEnd) {
_assertNotResynthesized(_unlinkedExportNonPublic);
super.uriEnd = uriEnd;
}
@override
int get uriOffset {
if (_unlinkedExportNonPublic != null) {
return _unlinkedExportNonPublic.uriOffset;
}
return super.uriOffset;
}
@override
void set uriOffset(int uriOffset) {
_assertNotResynthesized(_unlinkedExportNonPublic);
super.uriOffset = uriOffset;
}
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitExportElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write("export ");
LibraryElementImpl.getImpl(exportedLibrary).appendTo(buffer);
}
}
/// A concrete implementation of a [FieldElement].
class FieldElementImpl extends PropertyInducingElementImpl
implements FieldElement {
/// Initialize a newly created synthetic field element to have the given
/// [name] at the given [offset].
FieldElementImpl(String name, int offset) : super(name, offset);
FieldElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode) {
if (!linkedNode.isSynthetic) {
var enclosingRef = enclosing.reference;
this.getter = PropertyAccessorElementImpl_ImplicitGetter(
this,
reference: enclosingRef.getChild('@getter').getChild(name),
);
if (!isConst && !isFinal) {
this.setter = PropertyAccessorElementImpl_ImplicitSetter(
this,
reference: enclosingRef.getChild('@setter').getChild(name),
);
}
}
}
factory FieldElementImpl.forLinkedNodeFactory(
ClassElementImpl enclosing, Reference reference, AstNode linkedNode) {
var context = enclosing.enclosingUnit.linkedContext;
if (context.shouldBeConstFieldElement(linkedNode)) {
return ConstFieldElementImpl.forLinkedNode(
enclosing,
reference,
linkedNode,
);
}
return FieldElementImpl.forLinkedNode(enclosing, reference, linkedNode);
}
/// Initialize a newly created field element to have the given [name].
FieldElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
FieldElementImpl.forSerialized(
UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(unlinkedVariable, enclosingElement);
/// Initialize using the given serialized information.
factory FieldElementImpl.forSerializedFactory(
UnlinkedVariable unlinkedVariable, ClassElementImpl enclosingClass) {
if (unlinkedVariable.initializer?.bodyExpr != null &&
(unlinkedVariable.isConst ||
unlinkedVariable.isFinal &&
!unlinkedVariable.isStatic &&
enclosingClass._hasConstConstructor)) {
return new ConstFieldElementImpl.forSerialized(
unlinkedVariable, enclosingClass);
} else {
return new FieldElementImpl.forSerialized(
unlinkedVariable, enclosingClass);
}
}
@override
ClassElement get enclosingElement => super.enclosingElement as ClassElement;
@override
bool get isCovariant {
if (linkedNode != null) {
return linkedContext.isCovariant(linkedNode);
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.isCovariant;
}
return hasModifier(Modifier.COVARIANT);
}
/// Set whether this field is explicitly marked as being covariant.
void set isCovariant(bool isCovariant) {
_assertNotResynthesized(_unlinkedVariable);
setModifier(Modifier.COVARIANT, isCovariant);
}
@override
bool get isEnumConstant =>
enclosingElement != null && enclosingElement.isEnum && !isSynthetic;
@override
bool get isLazy {
// if (linkedNode != null) {
// return enclosingUnit.linkedContext.isLazy(linkedNode);
// }
// if (_unlinkedVariable != null) {
// return _unlinkedVariable.isLazy;
// }
return hasModifier(Modifier.LAZY);
}
@override
bool get isStatic {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isStatic(linkedNode);
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.isStatic;
}
return hasModifier(Modifier.STATIC);
}
/// Set whether this field is static.
void set isStatic(bool isStatic) {
_assertNotResynthesized(_unlinkedVariable);
setModifier(Modifier.STATIC, isStatic);
}
@deprecated
@override
bool get isVirtual => true;
@override
ElementKind get kind => ElementKind.FIELD;
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitFieldElement(this);
@deprecated
@override
AstNode computeNode() {
if (isEnumConstant) {
return getNodeMatching((node) => node is EnumConstantDeclaration);
} else {
return getNodeMatching((node) => node is VariableDeclaration);
}
}
}
/// A [ParameterElementImpl] that has the additional information of the
/// [FieldElement] associated with the parameter.
class FieldFormalParameterElementImpl extends ParameterElementImpl
implements FieldFormalParameterElement {
/// The field associated with this field formal parameter.
FieldElement _field;
/// Initialize a newly created parameter element to have the given [name] and
/// [nameOffset].
FieldFormalParameterElementImpl(String name, int nameOffset)
: super(name, nameOffset);
FieldFormalParameterElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created parameter element to have the given [name].
FieldFormalParameterElementImpl.forNode(Identifier name)
: super.forNode(name);
/// Initialize using the given serialized information.
FieldFormalParameterElementImpl.forSerialized(
UnlinkedParam unlinkedParam, ElementImpl enclosingElement)
: super.forSerialized(unlinkedParam, enclosingElement);
@override
FieldElement get field {
if (_field == null) {
String fieldName;
if (linkedNode != null) {
fieldName = linkedContext.getFieldFormalParameterName(linkedNode);
}
if (unlinkedParam != null) {
fieldName = unlinkedParam.name;
}
if (fieldName != null) {
Element enclosingConstructor = enclosingElement;
if (enclosingConstructor is ConstructorElement) {
Element enclosingClass = enclosingConstructor.enclosingElement;
if (enclosingClass is ClassElement) {
FieldElement field = enclosingClass.getField(fieldName);
if (field != null && !field.isSynthetic) {
_field = field;
}
}
}
}
}
return _field;
}
void set field(FieldElement field) {
_assertNotResynthesized(unlinkedParam);
_field = field;
}
@override
bool get isInitializingFormal => true;
@override
DartType get type {
if (unlinkedParam != null &&
unlinkedParam.type == null &&
!unlinkedParam.isFunctionTyped &&
field != null) {
_type ??= field?.type ?? DynamicTypeImpl.instance;
}
return super.type;
}
@override
void set type(DartType type) {
_assertNotResynthesized(unlinkedParam);
_type = type;
}
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitFieldFormalParameterElement(this);
}
/// A concrete implementation of a [FunctionElement].
class FunctionElementImpl extends ExecutableElementImpl
implements FunctionElement, FunctionTypedElementImpl {
/// The offset to the beginning of the visible range for this element.
int _visibleRangeOffset = 0;
/// The length of the visible range for this element, or `-1` if this element
/// does not have a visible range.
int _visibleRangeLength = -1;
/// Initialize a newly created function element to have the given [name] and
/// [offset].
FunctionElementImpl(String name, int offset) : super(name, offset);
FunctionElementImpl.forLinkedNode(ElementImpl enclosing, Reference reference,
FunctionDeclaration linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created function element to have the given [name].
FunctionElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize a newly created function element to have no name and the given
/// [nameOffset]. This is used for function expressions, that have no name.
FunctionElementImpl.forOffset(int nameOffset) : super("", nameOffset);
/// Initialize using the given serialized information.
FunctionElementImpl.forSerialized(
UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
: super.forSerialized(serializedExecutable, enclosingElement);
/// Synthesize an unnamed function element that takes [parameters] and returns
/// [returnType].
FunctionElementImpl.synthetic(
List<ParameterElement> parameters, DartType returnType)
: super("", -1) {
isSynthetic = true;
this.returnType = returnType;
this.parameters = parameters;
type = new FunctionTypeImpl(this);
}
@override
String get displayName {
if (linkedNode != null) {
return reference.name;
}
return super.displayName;
}
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext {
return (enclosingElement as ElementImpl).typeParameterContext;
}
@override
String get identifier {
String identifier = super.identifier;
Element enclosing = this.enclosingElement;
if (enclosing is ExecutableElement) {
identifier += "@$nameOffset";
}
return identifier;
}
@override
bool get isEntryPoint {
return isStatic && displayName == FunctionElement.MAIN_FUNCTION_NAME;
}
@override
bool get isStatic => enclosingElement is CompilationUnitElement;
@override
ElementKind get kind => ElementKind.FUNCTION;
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
return super.name;
}
@override
SourceRange get visibleRange {
if (serializedExecutable != null) {
if (serializedExecutable.visibleLength == 0) {
return null;
}
return new SourceRange(serializedExecutable.visibleOffset,
serializedExecutable.visibleLength);
}
if (_visibleRangeLength < 0) {
return null;
}
return new SourceRange(_visibleRangeOffset, _visibleRangeLength);
}
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitFunctionElement(this);
@override
void appendTo(StringBuffer buffer) {
String name = displayName;
if (name != null) {
buffer.write(name);
}
super.appendTo(buffer);
}
@deprecated
@override
FunctionDeclaration computeNode() =>
getNodeMatching((node) => node is FunctionDeclaration);
/// Set the visible range for this element to the range starting at the given
/// [offset] with the given [length].
void setVisibleRange(int offset, int length) {
_assertNotResynthesized(serializedExecutable);
_visibleRangeOffset = offset;
_visibleRangeLength = length;
}
/// Set the parameters defined by this type alias to the given [parameters]
/// without becoming the parent of the parameters. This should only be used by
/// the [TypeResolverVisitor] when creating a synthetic type alias.
void shareParameters(List<ParameterElement> parameters) {
this._parameters = parameters;
}
/// Set the type parameters defined by this type alias to the given
/// [parameters] without becoming the parent of the parameters. This should
/// only be used by the [TypeResolverVisitor] when creating a synthetic type
/// alias.
void shareTypeParameters(List<TypeParameterElement> typeParameters) {
this._typeParameterElements = typeParameters;
}
/// Create and return [FunctionElement]s for the given [unlinkedFunctions].
static List<FunctionElement> resynthesizeList(
ExecutableElementImpl executableElement,
List<UnlinkedExecutable> unlinkedFunctions) {
int length = unlinkedFunctions.length;
if (length != 0) {
List<FunctionElement> elements = new List<FunctionElement>(length);
for (int i = 0; i < length; i++) {
elements[i] = new FunctionElementImpl.forSerialized(
unlinkedFunctions[i], executableElement);
}
return elements;
} else {
return const <FunctionElement>[];
}
}
}
/// Implementation of [FunctionElementImpl] for a function typed parameter.
class FunctionElementImpl_forFunctionTypedParameter
extends FunctionElementImpl {
@override
final CompilationUnitElementImpl enclosingUnit;
/// The enclosing function typed [ParameterElementImpl].
final ParameterElementImpl _parameter;
FunctionElementImpl_forFunctionTypedParameter(
this.enclosingUnit, this._parameter)
: super('', -1);
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext =>
_parameter.typeParameterContext;
@override
bool get isSynthetic => true;
}
/// Implementation of [FunctionElementImpl] for a synthetic function element
/// that was synthesized by a LUB computation.
class FunctionElementImpl_forLUB extends FunctionElementImpl {
final EntityRef _entityRef;
FunctionElementImpl_forLUB(ElementImpl enclosingElement, this._entityRef)
: super.forSerialized(null, enclosingElement);
@override
bool get isSynthetic => true;
@override
List<ParameterElement> get parameters {
return _parameters ??= ParameterElementImpl.resynthesizeList(
_entityRef.syntheticParams, this,
synthetic: true);
}
@override
void set parameters(List<ParameterElement> parameters) {
assert(false);
}
@override
DartType get returnType {
return _returnType ??= enclosingUnit.resynthesizerContext
.resolveTypeRef(this, _entityRef.syntheticReturnType);
}
@override
void set returnType(DartType returnType) {
assert(false);
}
@override
FunctionType get type {
return _type ??= new FunctionTypeImpl(this);
}
@override
void set type(FunctionType type) {
assert(false);
}
@override
List<UnlinkedTypeParam> get unlinkedTypeParams => _entityRef.typeParameters;
}
/// Common internal interface shared by elements whose type is a function type.
///
/// Clients may not extend, implement or mix-in this class.
abstract class FunctionTypedElementImpl
implements ElementImpl, FunctionTypedElement {
void set returnType(DartType returnType);
}
/// The element used for a generic function type.
///
/// Clients may not extend, implement or mix-in this class.
class GenericFunctionTypeElementImpl extends ElementImpl
with TypeParameterizedElementMixin
implements GenericFunctionTypeElement, FunctionTypedElementImpl {
/// The unlinked representation of the generic function type in the summary.
EntityRef _entityRef;
/// The declared return type of the function.
DartType _returnType;
/// The elements representing the parameters of the function.
List<ParameterElement> _parameters;
/// The type defined by this element.
FunctionType _type;
GenericFunctionTypeElementImpl.forLinkedNode(
ElementImpl enclosingElement, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosingElement, reference, linkedNode);
/// Initialize a newly created function element to have no name and the given
/// [nameOffset]. This is used for function expressions, that have no name.
GenericFunctionTypeElementImpl.forOffset(int nameOffset)
: super("", nameOffset);
/// Initialize from serialized information.
GenericFunctionTypeElementImpl.forSerialized(
ElementImpl enclosingElement, this._entityRef)
: super.forSerialized(enclosingElement);
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext {
return _enclosingElement.typeParameterContext;
}
@override
String get identifier => '-';
@override
ElementKind get kind => ElementKind.GENERIC_FUNCTION_TYPE;
@override
List<ParameterElement> get parameters {
if (_parameters == null) {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
return _parameters = ParameterElementImpl.forLinkedNodeList(
this,
context,
reference.getChild('@parameter'),
context.getFormalParameters(linkedNode),
);
}
if (_entityRef != null) {
_parameters = ParameterElementImpl.resynthesizeList(
_entityRef.syntheticParams, this);
}
}
return _parameters ?? const <ParameterElement>[];
}
/// Set the parameters defined by this function type element to the given
/// [parameters].
void set parameters(List<ParameterElement> parameters) {
_assertNotResynthesized(_entityRef);
for (ParameterElement parameter in parameters) {
(parameter as ParameterElementImpl).enclosingElement = this;
}
this._parameters = parameters;
}
@override
DartType get returnType {
if (_returnType == null) {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
return _returnType = context.getReturnType(linkedNode);
}
if (_entityRef != null) {
_returnType = enclosingUnit.resynthesizerContext.resolveTypeRef(
this, _entityRef.syntheticReturnType,
defaultVoid: false, declaredType: true);
}
}
return _returnType;
}
/// Set the return type defined by this function type element to the given
/// [returnType].
void set returnType(DartType returnType) {
_assertNotResynthesized(_entityRef);
_returnType = _checkElementOfType(returnType);
}
@override
FunctionType get type {
_type ??= new FunctionTypeImpl(this);
return _type;
}
/// Set the function type defined by this function type element to the given
/// [type].
void set type(FunctionType type) {
_assertNotResynthesized(_entityRef);
_type = type;
}
@override
List<TypeParameterElement> get typeParameters {
if (linkedNode != null) {
if (linkedNode is FunctionTypeAlias) {
return const <TypeParameterElement>[];
}
}
return super.typeParameters;
}
/// Set the type parameters defined by this function type element to the given
/// [typeParameters].
void set typeParameters(List<TypeParameterElement> typeParameters) {
_assertNotResynthesized(_entityRef);
for (TypeParameterElement parameter in typeParameters) {
(parameter as TypeParameterElementImpl).enclosingElement = this;
}
this._typeParameterElements = typeParameters;
}
@override
List<UnlinkedTypeParam> get unlinkedTypeParams => _entityRef?.typeParameters;
@override
T accept<T>(ElementVisitor<T> visitor) {
return visitor.visitGenericFunctionTypeElement(this);
}
@override
void appendTo(StringBuffer buffer) {
DartType type = returnType;
if (type is TypeImpl) {
type.appendTo(buffer, new HashSet<TypeImpl>());
buffer.write(' Function');
} else {
buffer.write('Function');
}
List<TypeParameterElement> typeParams = typeParameters;
int typeParameterCount = typeParams.length;
if (typeParameterCount > 0) {
buffer.write('<');
for (int i = 0; i < typeParameterCount; i++) {
if (i > 0) {
buffer.write(', ');
}
(typeParams[i] as TypeParameterElementImpl).appendTo(buffer);
}
buffer.write('>');
}
List<ParameterElement> params = parameters;
buffer.write('(');
for (int i = 0; i < params.length; i++) {
if (i > 0) {
buffer.write(', ');
}
(params[i] as ParameterElementImpl).appendTo(buffer);
}
buffer.write(')');
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
_safelyVisitPossibleChild(returnType, visitor);
safelyVisitChildren(typeParameters, visitor);
safelyVisitChildren(parameters, visitor);
}
}
/// A function type alias of the form
/// `typedef` identifier typeParameters = genericFunctionType;
///
/// Clients may not extend, implement or mix-in this class.
class GenericTypeAliasElementImpl extends ElementImpl
with TypeParameterizedElementMixin, SimplyBoundableMixin
implements GenericTypeAliasElement {
/// The unlinked representation of the type in the summary.
final UnlinkedTypedef _unlinkedTypedef;
/// The element representing the generic function type.
GenericFunctionTypeElementImpl _function;
/// The type of function defined by this type alias.
FunctionType _type;
/// Initialize a newly created type alias element to have the given [name].
GenericTypeAliasElementImpl(String name, int offset)
: _unlinkedTypedef = null,
super(name, offset);
GenericTypeAliasElementImpl.forLinkedNode(
CompilationUnitElementImpl enclosingUnit,
Reference reference,
AstNode linkedNode)
: _unlinkedTypedef = null,
super.forLinkedNode(enclosingUnit, reference, linkedNode);
/// Initialize a newly created type alias element to have the given [name].
GenericTypeAliasElementImpl.forNode(Identifier name)
: _unlinkedTypedef = null,
super.forNode(name);
/// Initialize using the given serialized information.
GenericTypeAliasElementImpl.forSerialized(
this._unlinkedTypedef, CompilationUnitElementImpl enclosingUnit)
: super.forSerialized(enclosingUnit);
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (_unlinkedTypedef != null) {
return _unlinkedTypedef.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (_unlinkedTypedef != null) {
return _unlinkedTypedef.codeRange?.offset;
}
return super.codeOffset;
}
@override
String get displayName => name;
@override
String get documentationComment {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var comment = context.getDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (_unlinkedTypedef != null) {
return _unlinkedTypedef.documentationComment?.text;
}
return super.documentationComment;
}
@override
CompilationUnitElement get enclosingElement =>
super.enclosingElement as CompilationUnitElement;
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@override
CompilationUnitElementImpl get enclosingUnit =>
_enclosingElement as CompilationUnitElementImpl;
@override
GenericFunctionTypeElementImpl get function {
if (_function != null) return _function;
if (linkedNode != null) {
if (linkedNode is GenericTypeAlias) {
var context = enclosingUnit.linkedContext;
return _function = GenericFunctionTypeElementImpl.forLinkedNode(
this,
reference.getChild('@function'),
context.getGeneticTypeAliasFunction(linkedNode),
);
} else {
return _function = GenericFunctionTypeElementImpl.forLinkedNode(
this,
reference.getChild('@function'),
linkedNode,
);
}
}
if (_unlinkedTypedef != null) {
if (_unlinkedTypedef.style == TypedefStyle.genericFunctionType) {
DartType type = enclosingUnit.resynthesizerContext.resolveTypeRef(
this, _unlinkedTypedef.returnType,
declaredType: true);
if (type is FunctionType) {
Element element = type.element;
if (element is GenericFunctionTypeElement) {
(element as GenericFunctionTypeElementImpl).enclosingElement = this;
_function = element;
}
}
} else {
_function = new GenericFunctionTypeElementImpl.forOffset(-1);
_function.enclosingElement = this;
_function.returnType = enclosingUnit.resynthesizerContext
.resolveTypeRef(_function, _unlinkedTypedef.returnType,
declaredType: true);
_function.parameters = ParameterElementImpl.resynthesizeList(
_unlinkedTypedef.parameters, _function);
}
}
return _function;
}
/// Set the function element representing the generic function type on the
/// right side of the equals to the given [function].
void set function(GenericFunctionTypeElementImpl function) {
_assertNotResynthesized(_unlinkedTypedef);
if (function != null) {
function.enclosingElement = this;
}
_function = function;
}
@override
bool get isSimplyBounded {
if (linkedNode != null) {
return linkedContext.isSimplyBounded(linkedNode);
}
return super.isSimplyBounded;
}
@override
ElementKind get kind => ElementKind.FUNCTION_TYPE_ALIAS;
@override
List<ElementAnnotation> get metadata {
if (_unlinkedTypedef != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, _unlinkedTypedef.annotations);
}
return super.metadata;
}
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (_unlinkedTypedef != null) {
return _unlinkedTypedef.name;
}
return super.name;
}
@override
int get nameOffset {
int offset = super.nameOffset;
if (offset == 0 && _unlinkedTypedef != null) {
return _unlinkedTypedef.nameOffset;
}
return offset;
}
@override
List<ParameterElement> get parameters =>
function?.parameters ?? const <ParameterElement>[];
@override
DartType get returnType => function?.returnType;
@override
FunctionType get type {
_type ??= new FunctionTypeImpl.forTypedef(this);
return _type;
}
void set type(FunctionType type) {
_assertNotResynthesized(_unlinkedTypedef);
_type = type;
}
/// Set the type parameters defined for this type to the given
/// [typeParameters].
void set typeParameters(List<TypeParameterElement> typeParameters) {
_assertNotResynthesized(_unlinkedTypedef);
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
this._typeParameterElements = typeParameters;
}
@override
List<UnlinkedTypeParam> get unlinkedTypeParams =>
_unlinkedTypedef?.typeParameters;
@override
int get _notSimplyBoundedSlot => _unlinkedTypedef?.notSimplyBoundedSlot;
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitFunctionTypeAliasElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write("typedef ");
buffer.write(displayName);
var typeParameters = this.typeParameters;
int typeParameterCount = typeParameters.length;
if (typeParameterCount > 0) {
buffer.write("<");
for (int i = 0; i < typeParameterCount; i++) {
if (i > 0) {
buffer.write(", ");
}
(typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
}
buffer.write(">");
}
buffer.write(" = ");
if (function != null) {
function.appendTo(buffer);
}
}
@deprecated
@override
GenericTypeAlias computeNode() =>
getNodeMatching((node) => node is GenericTypeAlias);
@override
ElementImpl getChild(String identifier) {
for (TypeParameterElement typeParameter in typeParameters) {
TypeParameterElementImpl typeParameterImpl = typeParameter;
if (typeParameterImpl.identifier == identifier) {
return typeParameterImpl;
}
}
return null;
}
@override
FunctionType instantiate(List<DartType> argumentTypes) {
return doInstantiate(this, argumentTypes);
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(typeParameters, visitor);
function?.accept(visitor);
}
static FunctionType doInstantiate(
FunctionTypeAliasElement element, List<DartType> argumentTypes) {
if (argumentTypes.length != element.typeParameters.length) {
throw new ArgumentError('Wrong number of type arguments supplied');
}
if (element.typeParameters.isEmpty) return element.function.type;
return typeAfterSubstitution(element, argumentTypes);
}
/// Return the type of the function defined by this typedef after substituting
/// the given [typeArguments] for the type parameters defined for this typedef
/// (but not the type parameters defined by the function). If the number of
/// [typeArguments] does not match the number of type parameters, then
/// `dynamic` will be used in place of each of the type arguments.
static FunctionType typeAfterSubstitution(
FunctionTypeAliasElement element, List<DartType> typeArguments) {
GenericFunctionTypeElement function = element.function;
if (function == null) {
return null;
}
FunctionType functionType = function.type;
List<TypeParameterElement> parameterElements = element.typeParameters;
List<DartType> parameterTypes =
TypeParameterTypeImpl.getTypes(parameterElements);
int parameterCount = parameterTypes.length;
if (typeArguments == null ||
parameterElements.length != typeArguments.length) {
DartType dynamicType = DynamicElementImpl.instance.type;
typeArguments = new List<DartType>.filled(parameterCount, dynamicType);
}
return functionType.substitute2(typeArguments, parameterTypes);
}
}
/// A concrete implementation of a [HideElementCombinator].
class HideElementCombinatorImpl implements HideElementCombinator {
/// The unlinked representation of the combinator in the summary.
final UnlinkedCombinator _unlinkedCombinator;
final LinkedUnitContext linkedContext;
final HideCombinator linkedNode;
/// The names that are not to be made visible in the importing library even if
/// they are defined in the imported library.
List<String> _hiddenNames;
HideElementCombinatorImpl()
: _unlinkedCombinator = null,
linkedContext = null,
linkedNode = null;
HideElementCombinatorImpl.forLinkedNode(this.linkedContext, this.linkedNode)
: _unlinkedCombinator = null;
/// Initialize using the given serialized information.
HideElementCombinatorImpl.forSerialized(this._unlinkedCombinator)
: linkedContext = null,
linkedNode = null;
@override
List<String> get hiddenNames {
if (_hiddenNames != null) return _hiddenNames;
if (linkedNode != null) {
return _hiddenNames = linkedNode.hiddenNames.map((i) => i.name).toList();
}
if (_unlinkedCombinator != null) {
return _hiddenNames = _unlinkedCombinator.hides.toList(growable: false);
}
return _hiddenNames ?? const <String>[];
}
void set hiddenNames(List<String> hiddenNames) {
_assertNotResynthesized(_unlinkedCombinator);
_hiddenNames = hiddenNames;
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
buffer.write("show ");
int count = hiddenNames.length;
for (int i = 0; i < count; i++) {
if (i > 0) {
buffer.write(", ");
}
buffer.write(hiddenNames[i]);
}
return buffer.toString();
}
}
/// A concrete implementation of an [ImportElement].
class ImportElementImpl extends UriReferencedElementImpl
implements ImportElement {
/// The unlinked representation of the import in the summary.
final UnlinkedImport _unlinkedImport;
/// The index of the dependency in the `imports` list.
final int _linkedDependency;
/// The offset of the prefix of this import in the file that contains the this
/// import directive, or `-1` if this import is synthetic.
int _prefixOffset = 0;
/// The library that is imported into this library by this import directive.
LibraryElement _importedLibrary;
/// The combinators that were specified as part of the import directive in the
/// order in which they were specified.
List<NamespaceCombinator> _combinators;
/// The prefix that was specified as part of the import directive, or `null
///` if there was no prefix specified.
PrefixElement _prefix;
/// The URI that was selected based on the declared variables.
String _selectedUri;
/// The cached value of [namespace].
Namespace _namespace;
/// Initialize a newly created import element at the given [offset].
/// The offset may be `-1` if the import is synthetic.
ImportElementImpl(int offset)
: _unlinkedImport = null,
_linkedDependency = null,
super(null, offset);
ImportElementImpl.forLinkedNode(
LibraryElementImpl enclosing, ImportDirective linkedNode)
: _unlinkedImport = null,
_linkedDependency = null,
super.forLinkedNode(enclosing, null, linkedNode);
/// Initialize using the given serialized information.
ImportElementImpl.forSerialized(this._unlinkedImport, this._linkedDependency,
LibraryElementImpl enclosingLibrary)
: super.forSerialized(enclosingLibrary);
@override
List<NamespaceCombinator> get combinators {
if (_combinators != null) return _combinators;
if (linkedNode != null) {
ImportDirective node = linkedNode;
return _combinators = ImportElementImpl._buildCombinators2(
enclosingUnit.linkedContext,
node.combinators,
);
}
if (_unlinkedImport != null) {
return _combinators = _buildCombinators(_unlinkedImport.combinators);
}
return _combinators ?? const <NamespaceCombinator>[];
}
void set combinators(List<NamespaceCombinator> combinators) {
_assertNotResynthesized(_unlinkedImport);
_combinators = combinators;
}
/// Set whether this import is for a deferred library.
void set deferred(bool isDeferred) {
_assertNotResynthesized(_unlinkedImport);
setModifier(Modifier.DEFERRED, isDeferred);
}
@override
CompilationUnitElementImpl get enclosingUnit {
LibraryElementImpl enclosingLibrary = enclosingElement;
return enclosingLibrary._definingCompilationUnit;
}
@override
String get identifier => "${importedLibrary.identifier}@$nameOffset";
@override
LibraryElement get importedLibrary {
if (_importedLibrary != null) return _importedLibrary;
if (linkedNode != null) {
return _importedLibrary = linkedContext.directiveLibrary(linkedNode);
}
if (_linkedDependency != null) {
if (_importedLibrary == null) {
LibraryElementImpl library = enclosingElement as LibraryElementImpl;
if (_linkedDependency == 0) {
_importedLibrary = library;
} else {
_importedLibrary = library.resynthesizerContext
.buildImportedLibrary(_linkedDependency);
}
}
}
return _importedLibrary;
}
void set importedLibrary(LibraryElement importedLibrary) {
_assertNotResynthesized(_unlinkedImport);
_importedLibrary = importedLibrary;
}
@override
bool get isDeferred {
if (linkedNode != null) {
ImportDirective linkedNode = this.linkedNode;
return linkedNode.deferredKeyword != null;
}
if (_unlinkedImport != null) {
return _unlinkedImport.isDeferred;
}
return hasModifier(Modifier.DEFERRED);
}
@override
bool get isSynthetic {
if (_unlinkedImport != null) {
return _unlinkedImport.isImplicit;
}
return super.isSynthetic;
}
@override
ElementKind get kind => ElementKind.IMPORT;
@override
List<ElementAnnotation> get metadata {
if (_metadata == null) {
if (_unlinkedImport != null) {
return _metadata = _buildAnnotations(
library.definingCompilationUnit, _unlinkedImport.annotations);
}
}
return super.metadata;
}
void set metadata(List<ElementAnnotation> metadata) {
_assertNotResynthesized(_unlinkedImport);
super.metadata = metadata;
}
@override
int get nameOffset {
if (linkedNode != null) {
return linkedContext.getDirectiveOffset(linkedNode);
}
int offset = super.nameOffset;
if (offset == 0 && _unlinkedImport != null) {
if (_unlinkedImport.isImplicit) {
return -1;
}
return _unlinkedImport.offset;
}
return offset;
}
@override
Namespace get namespace {
return _namespace ??=
new NamespaceBuilder().createImportNamespaceForDirective(this);
}
PrefixElement get prefix {
if (_prefix != null) return _prefix;
if (linkedNode != null) {
ImportDirective linkedNode = this.linkedNode;
var prefix = linkedNode.prefix;
if (prefix != null) {
var name = prefix.name;
var library = enclosingElement as LibraryElementImpl;
_prefix = new PrefixElementImpl.forLinkedNode(
library,
library.reference.getChild('@prefix').getChild(name),
prefix,
);
}
}
if (_unlinkedImport != null && _unlinkedImport.prefixReference != 0) {
LibraryElementImpl library = enclosingElement as LibraryElementImpl;
_prefix = new PrefixElementImpl.forSerialized(_unlinkedImport, library);
}
return _prefix;
}
void set prefix(PrefixElement prefix) {
_assertNotResynthesized(_unlinkedImport);
_prefix = prefix;
}
@override
int get prefixOffset {
if (_unlinkedImport != null) {
return _unlinkedImport.prefixOffset;
}
return _prefixOffset;
}
void set prefixOffset(int prefixOffset) {
_assertNotResynthesized(_unlinkedImport);
_prefixOffset = prefixOffset;
}
@override
String get uri {
if (_unlinkedImport != null) {
if (_unlinkedImport.isImplicit) {
return null;
}
return _selectedUri ??=
_selectUri(_unlinkedImport.uri, _unlinkedImport.configurations);
}
return super.uri;
}
@override
void set uri(String uri) {
_assertNotResynthesized(_unlinkedImport);
super.uri = uri;
}
@override
int get uriEnd {
if (_unlinkedImport != null) {
if (_unlinkedImport.isImplicit) {
return -1;
}
return _unlinkedImport.uriEnd;
}
return super.uriEnd;
}
@override
void set uriEnd(int uriEnd) {
_assertNotResynthesized(_unlinkedImport);
super.uriEnd = uriEnd;
}
@override
int get uriOffset {
if (_unlinkedImport != null) {
if (_unlinkedImport.isImplicit) {
return -1;
}
return _unlinkedImport.uriOffset;
}
return super.uriOffset;
}
@override
void set uriOffset(int uriOffset) {
_assertNotResynthesized(_unlinkedImport);
super.uriOffset = uriOffset;
}
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitImportElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write("import ");
LibraryElementImpl.getImpl(importedLibrary).appendTo(buffer);
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
prefix?.accept(visitor);
}
static List<NamespaceCombinator> _buildCombinators(
List<UnlinkedCombinator> unlinkedCombinators) {
int length = unlinkedCombinators.length;
if (length != 0) {
List<NamespaceCombinator> combinators =
new List<NamespaceCombinator>(length);
for (int i = 0; i < length; i++) {
UnlinkedCombinator unlinkedCombinator = unlinkedCombinators[i];
combinators[i] = unlinkedCombinator.shows.isNotEmpty
? new ShowElementCombinatorImpl.forSerialized(unlinkedCombinator)
: new HideElementCombinatorImpl.forSerialized(unlinkedCombinator);
}
return combinators;
} else {
return const <NamespaceCombinator>[];
}
}
static List<NamespaceCombinator> _buildCombinators2(
LinkedUnitContext context, List<Combinator> combinators) {
return combinators.map((node) {
if (node is HideCombinator) {
return HideElementCombinatorImpl.forLinkedNode(context, node);
}
if (node is ShowCombinator) {
return ShowElementCombinatorImpl.forLinkedNode(context, node);
}
throw UnimplementedError('${node.runtimeType}');
}).toList();
}
}
/// A concrete implementation of a [LabelElement].
class LabelElementImpl extends ElementImpl implements LabelElement {
/// A flag indicating whether this label is associated with a `switch`
/// statement.
// TODO(brianwilkerson) Make this a modifier.
final bool _onSwitchStatement;
/// A flag indicating whether this label is associated with a `switch` member
/// (`case` or `default`).
// TODO(brianwilkerson) Make this a modifier.
final bool _onSwitchMember;
/// Initialize a newly created label element to have the given [name].
/// [onSwitchStatement] should be `true` if this label is associated with a
/// `switch` statement and [onSwitchMember] should be `true` if this label is
/// associated with a `switch` member.
LabelElementImpl(String name, int nameOffset, this._onSwitchStatement,
this._onSwitchMember)
: super(name, nameOffset);
/// Initialize a newly created label element to have the given [name].
/// [_onSwitchStatement] should be `true` if this label is associated with a
/// `switch` statement and [_onSwitchMember] should be `true` if this label is
/// associated with a `switch` member.
LabelElementImpl.forNode(
Identifier name, this._onSwitchStatement, this._onSwitchMember)
: super.forNode(name);
@override
String get displayName => name;
@override
ExecutableElement get enclosingElement =>
super.enclosingElement as ExecutableElement;
/// Return `true` if this label is associated with a `switch` member (`case
/// ` or`default`).
bool get isOnSwitchMember => _onSwitchMember;
/// Return `true` if this label is associated with a `switch` statement.
bool get isOnSwitchStatement => _onSwitchStatement;
@override
ElementKind get kind => ElementKind.LABEL;
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitLabelElement(this);
}
/// A concrete implementation of a [LibraryElement].
class LibraryElementImpl extends ElementImpl implements LibraryElement {
/// The analysis context in which this library is defined.
final AnalysisContext context;
@override
final AnalysisSession session;
final LibraryResynthesizerContext resynthesizerContext;
final UnlinkedUnit unlinkedDefiningUnit;
/// The context of the defining unit.
final LinkedUnitContext linkedContext;
/// The compilation unit that defines this library.
CompilationUnitElement _definingCompilationUnit;
/// The entry point for this library, or `null` if this library does not have
/// an entry point.
FunctionElement _entryPoint;
/// A list containing specifications of all of the imports defined in this
/// library.
List<ImportElement> _imports;
/// A list containing specifications of all of the exports defined in this
/// library.
List<ExportElement> _exports;
/// A list containing the strongly connected component in the import/export
/// graph in which the current library resides. Computed on demand, null
/// if not present. If _libraryCycle is set, then the _libraryCycle field
/// for all libraries reachable from this library in the import/export graph
/// is also set.
List<LibraryElement> _libraryCycle = null;
/// A list containing all of the compilation units that are included in this
/// library using a `part` directive.
List<CompilationUnitElement> _parts = const <CompilationUnitElement>[];
/// The element representing the synthetic function `loadLibrary` that is
/// defined for this library, or `null` if the element has not yet been
/// created.
FunctionElement _loadLibraryFunction;
@override
final int nameLength;
/// The export [Namespace] of this library, `null` if it has not been
/// computed yet.
Namespace _exportNamespace;
/// The public [Namespace] of this library, `null` if it has not been
/// computed yet.
Namespace _publicNamespace;
/// A bit-encoded form of the capabilities associated with this library.
int _resolutionCapabilities = 0;
/// The cached list of prefixes.
List<PrefixElement> _prefixes;
/// Initialize a newly created library element in the given [context] to have
/// the given [name] and [offset].
LibraryElementImpl(
this.context, this.session, String name, int offset, this.nameLength)
: resynthesizerContext = null,
unlinkedDefiningUnit = null,
linkedContext = null,
super(name, offset);
LibraryElementImpl.forLinkedNode(
this.context,
this.session,
String name,
int offset,
this.nameLength,
this.linkedContext,
Reference reference,
CompilationUnit linkedNode)
: resynthesizerContext = null,
unlinkedDefiningUnit = null,
super.forLinkedNode(null, reference, linkedNode) {
_name = name;
_nameOffset = offset;
setResolutionCapability(
LibraryResolutionCapability.resolvedTypeNames, true);
setResolutionCapability(
LibraryResolutionCapability.constantExpressions, true);
}
/// Initialize a newly created library element in the given [context] to have
/// the given [name].
LibraryElementImpl.forNode(this.context, this.session, LibraryIdentifier name)
: nameLength = name != null ? name.length : 0,
resynthesizerContext = null,
unlinkedDefiningUnit = null,
linkedContext = null,
super.forNode(name);
/// Initialize using the given serialized information.
LibraryElementImpl.forSerialized(
this.context,
this.session,
String name,
int offset,
this.nameLength,
this.resynthesizerContext,
this.unlinkedDefiningUnit)
: linkedContext = null,
super.forSerialized(null) {
_name = name;
_nameOffset = offset;
setResolutionCapability(
LibraryResolutionCapability.resolvedTypeNames, true);
setResolutionCapability(
LibraryResolutionCapability.constantExpressions, true);
}
@override
int get codeLength {
CompilationUnitElement unit = _definingCompilationUnit;
if (unit is CompilationUnitElementImpl) {
return unit.codeLength;
}
return null;
}
@override
int get codeOffset {
CompilationUnitElement unit = _definingCompilationUnit;
if (unit is CompilationUnitElementImpl) {
return unit.codeOffset;
}
return null;
}
@override
CompilationUnitElement get definingCompilationUnit =>
_definingCompilationUnit;
/// Set the compilation unit that defines this library to the given
/// compilation[unit].
void set definingCompilationUnit(CompilationUnitElement unit) {
assert((unit as CompilationUnitElementImpl).librarySource == unit.source);
(unit as CompilationUnitElementImpl).enclosingElement = this;
this._definingCompilationUnit = unit;
}
@override
String get documentationComment {
if (linkedNode != null) {
var comment = linkedContext.getLibraryDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (unlinkedDefiningUnit != null) {
return unlinkedDefiningUnit.libraryDocumentationComment?.text;
}
return super.documentationComment;
}
FunctionElement get entryPoint {
if (resynthesizerContext != null) {
_entryPoint ??= resynthesizerContext.findEntryPoint();
}
return _entryPoint;
}
void set entryPoint(FunctionElement entryPoint) {
_entryPoint = entryPoint;
}
@override
List<LibraryElement> get exportedLibraries {
HashSet<LibraryElement> libraries = new HashSet<LibraryElement>();
for (ExportElement element in exports) {
LibraryElement library = element.exportedLibrary;
if (library != null) {
libraries.add(library);
}
}
return libraries.toList(growable: false);
}
@override
Namespace get exportNamespace {
if (_exportNamespace != null) return _exportNamespace;
if (linkedNode != null) {
var elements = linkedContext.bundleContext.elementFactory;
return _exportNamespace = elements.buildExportNamespace(source.uri);
}
if (resynthesizerContext != null) {
_exportNamespace ??= resynthesizerContext.buildExportNamespace();
}
return _exportNamespace;
}
void set exportNamespace(Namespace exportNamespace) {
_exportNamespace = exportNamespace;
}
@override
List<ExportElement> get exports {
if (_exports != null) return _exports;
if (linkedNode != null) {
var unit = linkedContext.unit_withDirectives;
return _exports = unit.directives
.whereType<ExportDirective>()
.map((node) => ExportElementImpl.forLinkedNode(this, node))
.toList();
}
if (unlinkedDefiningUnit != null) {
List<UnlinkedExportNonPublic> unlinkedNonPublicExports =
unlinkedDefiningUnit.exports;
List<UnlinkedExportPublic> unlinkedPublicExports =
unlinkedDefiningUnit.publicNamespace.exports;
assert(
unlinkedDefiningUnit.exports.length == unlinkedPublicExports.length);
int length = unlinkedNonPublicExports.length;
if (length != 0) {
List<ExportElement> exports = new List<ExportElement>();
for (int i = 0; i < length; i++) {
UnlinkedExportPublic serializedExportPublic =
unlinkedPublicExports[i];
UnlinkedExportNonPublic serializedExportNonPublic =
unlinkedNonPublicExports[i];
ExportElementImpl exportElement = new ExportElementImpl.forSerialized(
serializedExportPublic, serializedExportNonPublic, library);
exports.add(exportElement);
}
_exports = exports;
} else {
_exports = const <ExportElement>[];
}
}
return _exports ??= const <ExportElement>[];
}
/// Set the specifications of all of the exports defined in this library to
/// the given list of [exports].
void set exports(List<ExportElement> exports) {
_assertNotResynthesized(unlinkedDefiningUnit);
for (ExportElement exportElement in exports) {
(exportElement as ExportElementImpl).enclosingElement = this;
}
this._exports = exports;
}
@override
bool get hasExtUri {
if (unlinkedDefiningUnit != null) {
List<UnlinkedImport> unlinkedImports = unlinkedDefiningUnit.imports;
for (UnlinkedImport import in unlinkedImports) {
if (DartUriResolver.isDartExtUri(import.uri)) {
return true;
}
}
return false;
}
return hasModifier(Modifier.HAS_EXT_URI);
}
/// Set whether this library has an import of a "dart-ext" URI.
void set hasExtUri(bool hasExtUri) {
setModifier(Modifier.HAS_EXT_URI, hasExtUri);
}
@override
bool get hasLoadLibraryFunction {
if (_definingCompilationUnit.hasLoadLibraryFunction) {
return true;
}
for (int i = 0; i < _parts.length; i++) {
if (_parts[i].hasLoadLibraryFunction) {
return true;
}
}
return false;
}
@override
String get identifier => _definingCompilationUnit.source.encoding;
@override
List<LibraryElement> get importedLibraries {
HashSet<LibraryElement> libraries = new HashSet<LibraryElement>();
for (ImportElement element in imports) {
LibraryElement library = element.importedLibrary;
if (library != null) {
libraries.add(library);
}
}
return libraries.toList(growable: false);
}
@override
List<ImportElement> get imports {
if (_imports != null) return _imports;
if (linkedNode != null) {
var unit = linkedContext.unit_withDirectives;
_imports = unit.directives
.whereType<ImportDirective>()
.map((node) => ImportElementImpl.forLinkedNode(this, node))
.toList();
var hasCore = _imports.any((import) {
return import.importedLibrary?.isDartCore ?? false;
});
if (!hasCore) {
var elements = linkedContext.bundleContext.elementFactory;
_imports.add(ImportElementImpl(-1)
..importedLibrary = elements.libraryOfUri('dart:core')
..isSynthetic = true);
}
return _imports;
}
if (unlinkedDefiningUnit != null) {
_imports = buildImportsFromSummary(this, unlinkedDefiningUnit.imports,
resynthesizerContext.linkedLibrary.importDependencies);
}
return _imports ??= const <ImportElement>[];
}
/// Set the specifications of all of the imports defined in this library to
/// the given list of [imports].
void set imports(List<ImportElement> imports) {
_assertNotResynthesized(unlinkedDefiningUnit);
for (ImportElement importElement in imports) {
(importElement as ImportElementImpl).enclosingElement = this;
PrefixElementImpl prefix = importElement.prefix as PrefixElementImpl;
if (prefix != null) {
prefix.enclosingElement = this;
}
}
this._imports = imports;
this._prefixes = null;
}
@override
bool get isBrowserApplication =>
entryPoint != null && isOrImportsBrowserLibrary;
@override
bool get isDartAsync => name == "dart.async";
@override
bool get isDartCore => name == "dart.core";
@override
bool get isInSdk {
Uri uri = definingCompilationUnit.source?.uri;
if (uri != null) {
return DartUriResolver.isDartUri(uri);
}
return false;
}
/// Return `true` if the receiver directly or indirectly imports the
/// 'dart:html' libraries.
bool get isOrImportsBrowserLibrary {
List<LibraryElement> visited = new List<LibraryElement>();
Source htmlLibSource = context.sourceFactory.forUri(DartSdk.DART_HTML);
visited.add(this);
for (int index = 0; index < visited.length; index++) {
LibraryElement library = visited[index];
Source source = library.definingCompilationUnit.source;
if (source == htmlLibSource) {
return true;
}
for (LibraryElement importedLibrary in library.importedLibraries) {
if (!visited.contains(importedLibrary)) {
visited.add(importedLibrary);
}
}
for (LibraryElement exportedLibrary in library.exportedLibraries) {
if (!visited.contains(exportedLibrary)) {
visited.add(exportedLibrary);
}
}
}
return false;
}
@override
bool get isResynthesized {
return resynthesizerContext != null;
}
@override
ElementKind get kind => ElementKind.LIBRARY;
@override
LibraryElement get library => this;
@override
List<LibraryElement> get libraryCycle {
if (_libraryCycle != null) {
return _libraryCycle;
}
// Global counter for this run of the algorithm
int counter = 0;
// The discovery times of each library
Map<LibraryElementImpl, int> indices = {};
// The set of scc candidates
Set<LibraryElementImpl> active = new Set();
// The stack of discovered elements
List<LibraryElementImpl> stack = [];
// For a given library that has not yet been processed by this run of the
// algorithm, compute the strongly connected components.
int scc(LibraryElementImpl library) {
int index = counter++;
int root = index;
indices[library] = index;
active.add(library);
stack.add(library);
LibraryElementImpl getActualLibrary(LibraryElement lib) {
// TODO(paulberry): this means that computing a library cycle will be
// expensive for libraries resynthesized from summaries, since it will
// require fully resynthesizing all the libraries in the cycle as well
// as any libraries they import or export. Try to find a better way.
if (lib is LibraryElementHandle) {
return lib.actualElement;
} else {
return lib;
}
}
void recurse(LibraryElementImpl child) {
if (!indices.containsKey(child)) {
// We haven't visited this child yet, so recurse on the child,
// returning the lowest numbered node reachable from the child. If
// the child can reach a root which is lower numbered than anything
// we've reached so far, update the root.
root = min(root, scc(child));
} else if (active.contains(child)) {
// The child has been visited, but has not yet been placed into a
// component. If the child is higher than anything we've seen so far
// update the root appropriately.
root = min(root, indices[child]);
}
}
// Recurse on all of the children in the import/export graph, filtering
// out those for which library cycles have already been computed.
library.exportedLibraries
.map(getActualLibrary)
.where((l) => l._libraryCycle == null)
.forEach(recurse);
library.importedLibraries
.map(getActualLibrary)
.where((l) => l._libraryCycle == null)
.forEach(recurse);
if (root == index) {
// This is the root of a strongly connected component.
// Pop the elements, and share the component across all
// of the elements.
List<LibraryElement> component = <LibraryElement>[];
LibraryElementImpl cur = null;
do {
cur = stack.removeLast();
active.remove(cur);
component.add(cur);
cur._libraryCycle = component;
} while (cur != library);
}
return root;
}
scc(library);
return _libraryCycle;
}
@override
FunctionElement get loadLibraryFunction {
assert(_loadLibraryFunction != null);
return _loadLibraryFunction;
}
@override
List<ElementAnnotation> get metadata {
if (_metadata != null) return _metadata;
if (linkedNode != null) {
var metadata = linkedContext.getLibraryMetadata(linkedNode);
return _metadata = _buildAnnotations2(definingCompilationUnit, metadata);
}
if (unlinkedDefiningUnit != null) {
return _metadata = _buildAnnotations(
_definingCompilationUnit as CompilationUnitElementImpl,
unlinkedDefiningUnit.libraryAnnotations);
}
return super.metadata;
}
@override
List<CompilationUnitElement> get parts => _parts;
/// Set the compilation units that are included in this library using a `part`
/// directive to the given list of [parts].
void set parts(List<CompilationUnitElement> parts) {
for (CompilationUnitElement compilationUnit in parts) {
assert((compilationUnit as CompilationUnitElementImpl).librarySource ==
source);
(compilationUnit as CompilationUnitElementImpl).enclosingElement = this;
}
this._parts = parts;
}
@override
List<PrefixElement> get prefixes =>
_prefixes ??= buildPrefixesFromImports(imports);
@override
Namespace get publicNamespace {
if (_publicNamespace != null) return _publicNamespace;
if (linkedNode != null) {
return _publicNamespace =
NamespaceBuilder().createPublicNamespaceForLibrary(this);
}
if (resynthesizerContext != null) {
return _publicNamespace = resynthesizerContext.buildPublicNamespace();
}
return _publicNamespace;
}
void set publicNamespace(Namespace publicNamespace) {
_publicNamespace = publicNamespace;
}
@override
Source get source {
if (_definingCompilationUnit == null) {
return null;
}
return _definingCompilationUnit.source;
}
@override
Iterable<Element> get topLevelElements sync* {
for (var unit in units) {
yield* unit.accessors;
yield* unit.enums;
yield* unit.functionTypeAliases;
yield* unit.functions;
yield* unit.mixins;
yield* unit.topLevelVariables;
yield* unit.types;
}
}
@override
List<CompilationUnitElement> get units {
List<CompilationUnitElement> units = new List<CompilationUnitElement>();
units.add(_definingCompilationUnit);
units.addAll(_parts);
return units;
}
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitLibraryElement(this);
/// Create the [FunctionElement] to be returned by [loadLibraryFunction],
/// using types provided by [typeProvider].
void createLoadLibraryFunction(TypeProvider typeProvider) {
_loadLibraryFunction =
createLoadLibraryFunctionForLibrary(typeProvider, this);
}
@override
ElementImpl getChild(String identifier) {
CompilationUnitElementImpl unitImpl = _definingCompilationUnit;
if (unitImpl.identifier == identifier) {
return unitImpl;
}
for (CompilationUnitElement part in _parts) {
CompilationUnitElementImpl partImpl = part;
if (partImpl.identifier == identifier) {
return partImpl;
}
}
for (ImportElement importElement in imports) {
ImportElementImpl importElementImpl = importElement;
if (importElementImpl.identifier == identifier) {
return importElementImpl;
}
}
for (ExportElement exportElement in exports) {
ExportElementImpl exportElementImpl = exportElement;
if (exportElementImpl.identifier == identifier) {
return exportElementImpl;
}
}
return null;
}
ClassElement getEnum(String name) {
ClassElement element = _definingCompilationUnit.getEnum(name);
if (element != null) {
return element;
}
for (CompilationUnitElement part in _parts) {
element = part.getEnum(name);
if (element != null) {
return element;
}
}
return null;
}
@override
List<ImportElement> getImportsWithPrefix(PrefixElement prefixElement) {
return getImportsWithPrefixFromImports(prefixElement, imports);
}
@override
ClassElement getType(String className) {
return getTypeFromParts(className, _definingCompilationUnit, _parts);
}
/// Given an update to this library which may have added or deleted edges
/// in the import/export graph originating from this node only, remove any
/// cached library cycles in the element model which may have been
/// invalidated.
void invalidateLibraryCycles() {
// If we have pre-computed library cycle information, then we must
// invalidate the information both on this element, and on certain
// other elements. Edges originating at this node may have been
// added or deleted. A deleted edge that points outside of this cycle
// cannot change the cycle information for anything outside of this cycle,
// and so it is sufficient to delete the cached library information on this
// cycle. An added edge which points to another node within the cycle
// only invalidates the cycle. An added edge which points to a node earlier
// in the topological sort of cycles induces no invalidation (since there
// are by definition no back edges from earlier cycles in the topological
// order, and hence no possible cycle can have been introduced. The only
// remaining case is that we have added an edge to a node which is later
// in the topological sort of cycles. This can induce cycles, since it
// represents a new back edge. It would be sufficient to invalidate the
// cycle information for all nodes that are between the target and the
// node in the topological order. For simplicity, we simply invalidate
// all nodes which are reachable from the source node.
// Note that in the invalidation phase, we do not cut off when we encounter
// a node with no library cycle information, since we do not know whether
// we are in the case where invalidation has already been performed, or we
// are in the case where library cycles have simply never been computed from
// a newly reachable node.
Set<LibraryElementImpl> active = new HashSet();
void invalidate(LibraryElement element) {
LibraryElementImpl library =
element is LibraryElementHandle ? element.actualElement : element;
if (active.add(library)) {
if (library._libraryCycle != null) {
library._libraryCycle.forEach(invalidate);
library._libraryCycle = null;
}
library.exportedLibraries.forEach(invalidate);
library.importedLibraries.forEach(invalidate);
}
}
invalidate(this);
}
/// Set whether the library has the given [capability] to
/// correspond to the given [value].
void setResolutionCapability(
LibraryResolutionCapability capability, bool value) {
_resolutionCapabilities =
BooleanArray.set(_resolutionCapabilities, capability.index, value);
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
_definingCompilationUnit?.accept(visitor);
safelyVisitChildren(exports, visitor);
safelyVisitChildren(imports, visitor);
safelyVisitChildren(_parts, visitor);
}
static List<ImportElement> buildImportsFromSummary(LibraryElement library,
List<UnlinkedImport> unlinkedImports, List<int> importDependencies) {
int length = unlinkedImports.length;
if (length != 0) {
List<ImportElement> imports = new List<ImportElement>();
for (int i = 0; i < length; i++) {
int dependency = importDependencies[i];
ImportElementImpl importElement = new ImportElementImpl.forSerialized(
unlinkedImports[i], dependency, library);
imports.add(importElement);
}
return imports;
} else {
return const <ImportElement>[];
}
}
static List<PrefixElement> buildPrefixesFromImports(
List<ImportElement> imports) {
HashSet<PrefixElement> prefixes = new HashSet<PrefixElement>();
for (ImportElement element in imports) {
PrefixElement prefix = element.prefix;
if (prefix != null) {
prefixes.add(prefix);
}
}
return prefixes.toList(growable: false);
}
static FunctionElementImpl createLoadLibraryFunctionForLibrary(
TypeProvider typeProvider, LibraryElement library) {
FunctionElementImpl function =
new FunctionElementImpl(FunctionElement.LOAD_LIBRARY_NAME, -1);
function.isSynthetic = true;
function.enclosingElement = library;
function.returnType = typeProvider.futureDynamicType;
function.type = new FunctionTypeImpl(function);
return function;
}
/// Return the [LibraryElementImpl] of the given [element].
static LibraryElementImpl getImpl(LibraryElement element) {
if (element is LibraryElementHandle) {
return getImpl(element.actualElement);
}
return element as LibraryElementImpl;
}
static List<ImportElement> getImportsWithPrefixFromImports(
PrefixElement prefixElement, List<ImportElement> imports) {
int count = imports.length;
List<ImportElement> importList = new List<ImportElement>();
for (int i = 0; i < count; i++) {
if (identical(imports[i].prefix, prefixElement)) {
importList.add(imports[i]);
}
}
return importList;
}
static ClassElement getTypeFromParts(
String className,
CompilationUnitElement definingCompilationUnit,
List<CompilationUnitElement> parts) {
ClassElement type = definingCompilationUnit.getType(className);
if (type != null) {
return type;
}
for (CompilationUnitElement part in parts) {
type = part.getType(className);
if (type != null) {
return type;
}
}
return null;
}
/// Return `true` if the [library] has the given [capability].
static bool hasResolutionCapability(
LibraryElement library, LibraryResolutionCapability capability) {
return library is LibraryElementImpl &&
BooleanArray.get(library._resolutionCapabilities, capability.index);
}
}
/// Enum of possible resolution capabilities that a [LibraryElementImpl] has.
enum LibraryResolutionCapability {
/// All elements have their types resolved.
resolvedTypeNames,
/// All (potentially) constants expressions are set into corresponding
/// elements.
constantExpressions,
}
/// The context in which the library is resynthesized.
abstract class LibraryResynthesizerContext {
/// Return the [LinkedLibrary] that corresponds to the library being
/// resynthesized.
LinkedLibrary get linkedLibrary;
/// Return the exported [LibraryElement] for with the given [relativeUri].
LibraryElement buildExportedLibrary(String relativeUri);
/// Return the export namespace of the library.
Namespace buildExportNamespace();
/// Return the imported [LibraryElement] for the given dependency in the
/// linked library.
LibraryElement buildImportedLibrary(int dependency);
/// Return the public namespace of the library.
Namespace buildPublicNamespace();
/// Find the entry point of the library.
FunctionElement findEntryPoint();
/// Ensure that getters and setters in different units use the same
/// top-level variables.
void patchTopLevelAccessors();
}
/// A concrete implementation of a [LocalVariableElement].
class LocalVariableElementImpl extends NonParameterVariableElementImpl
implements LocalVariableElement {
/// The offset to the beginning of the visible range for this element.
int _visibleRangeOffset = 0;
/// The length of the visible range for this element, or `-1` if this element
/// does not have a visible range.
int _visibleRangeLength = -1;
/// Initialize a newly created method element to have the given [name] and
/// [offset].
LocalVariableElementImpl(String name, int offset) : super(name, offset);
/// Initialize a newly created local variable element to have the given
/// [name].
LocalVariableElementImpl.forNode(Identifier name) : super.forNode(name);
@override
String get identifier {
return '$name$nameOffset';
}
@override
bool get isLazy {
// if (linkedNode != null) {
// return enclosingUnit.linkedContext.isLazy(linkedNode);
// }
// if (_unlinkedVariable != null) {
// return _unlinkedVariable.isLazy;
// }
return hasModifier(Modifier.LAZY);
}
@override
bool get isPotentiallyMutatedInClosure => true;
@override
bool get isPotentiallyMutatedInScope => true;
@override
ElementKind get kind => ElementKind.LOCAL_VARIABLE;
@override
SourceRange get visibleRange {
if (_visibleRangeLength < 0) {
return null;
}
return new SourceRange(_visibleRangeOffset, _visibleRangeLength);
}
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitLocalVariableElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write(type);
buffer.write(" ");
buffer.write(displayName);
}
@deprecated
@override
Declaration computeNode() => getNodeMatching(
(node) => node is DeclaredIdentifier || node is VariableDeclaration);
/// Set the visible range for this element to the range starting at the given
/// [offset] with the given [length].
void setVisibleRange(int offset, int length) {
_visibleRangeOffset = offset;
_visibleRangeLength = length;
}
}
/// A concrete implementation of a [MethodElement].
class MethodElementImpl extends ExecutableElementImpl implements MethodElement {
/// Initialize a newly created method element to have the given [name] at the
/// given [offset].
MethodElementImpl(String name, int offset) : super(name, offset);
MethodElementImpl.forLinkedNode(ClassElementImpl enclosingClass,
Reference reference, MethodDeclaration linkedNode)
: super.forLinkedNode(enclosingClass, reference, linkedNode);
/// Initialize a newly created method element to have the given [name].
MethodElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
MethodElementImpl.forSerialized(
UnlinkedExecutable serializedExecutable, ClassElementImpl enclosingClass)
: super.forSerialized(serializedExecutable, enclosingClass);
/// Set whether this method is abstract.
void set abstract(bool isAbstract) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.ABSTRACT, isAbstract);
}
@override
String get displayName {
String displayName = super.displayName;
if ("unary-" == displayName) {
return "-";
}
return displayName;
}
@override
ClassElement get enclosingElement => super.enclosingElement as ClassElement;
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext =>
super.enclosingElement as ClassElementImpl;
@override
bool get isOperator {
String name = displayName;
if (name.isEmpty) {
return false;
}
int first = name.codeUnitAt(0);
return !((0x61 <= first && first <= 0x7A) ||
(0x41 <= first && first <= 0x5A) ||
first == 0x5F ||
first == 0x24);
}
@override
bool get isStatic {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isStatic(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.isStatic;
}
return hasModifier(Modifier.STATIC);
}
/// Set whether this method is static.
void set isStatic(bool isStatic) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.STATIC, isStatic);
}
@override
ElementKind get kind => ElementKind.METHOD;
@override
String get name {
String name = super.name;
if (name == '-' && parameters.isEmpty) {
return 'unary-';
}
return super.name;
}
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitMethodElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write(displayName);
super.appendTo(buffer);
}
@deprecated
@override
MethodDeclaration computeNode() =>
getNodeMatching((node) => node is MethodDeclaration);
@deprecated
@override
FunctionType getReifiedType(DartType objectType) {
// TODO(jmesserly): this implementation is completely wrong:
// It does not handle covariant parameters from a generic class.
// It drops type parameters from generic methods.
// Since this method was for DDC, it should be removed.
//
// Check whether we have any covariant parameters.
// Usually we don't, so we can use the same type.
bool hasCovariant = false;
for (ParameterElement parameter in parameters) {
if (parameter.isCovariant) {
hasCovariant = true;
break;
}
}
if (!hasCovariant) {
return type;
}
List<ParameterElement> covariantParameters = parameters.map((parameter) {
DartType type = parameter.isCovariant ? objectType : parameter.type;
return new ParameterElementImpl.synthetic(
parameter.name, type, parameter.parameterKind);
}).toList();
return new FunctionElementImpl.synthetic(covariantParameters, returnType)
.type;
}
}
/// A [ClassElementImpl] representing a mixin declaration.
class MixinElementImpl extends ClassElementImpl {
// TODO(brianwilkerson) Consider creating an abstract superclass of
// ClassElementImpl that contains the portions of the API that this class
// needs, and make this class extend the new class.
/// A list containing all of the superclass constraints that are defined for
/// the mixin.
List<InterfaceType> _superclassConstraints;
/// 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> _superInvokedNames;
/// 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.
MixinElementImpl(String name, int offset) : super(name, offset);
MixinElementImpl.forLinkedNode(CompilationUnitElementImpl enclosing,
Reference reference, MixinDeclaration linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created class element to have the given [name].
MixinElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
MixinElementImpl.forSerialized(
UnlinkedClass unlinkedClass, CompilationUnitElementImpl enclosingUnit)
: super.forSerialized(unlinkedClass, enclosingUnit);
@override
bool get isAbstract => true;
@override
bool get isMixin => true;
@override
List<InterfaceType> get mixins => const <InterfaceType>[];
@override
List<InterfaceType> get superclassConstraints {
if (_superclassConstraints != null) return _superclassConstraints;
if (linkedNode != null) {
List<InterfaceType> constraints;
var onClause = enclosingUnit.linkedContext.getOnClause(linkedNode);
if (onClause != null) {
constraints = onClause.superclassConstraints
.map((node) => node.type)
.whereType<InterfaceType>()
.toList();
}
if (constraints == null || constraints.isEmpty) {
constraints = [context.typeProvider.objectType];
}
return _superclassConstraints = constraints;
}
if (_unlinkedClass != null) {
List<InterfaceType> constraints;
if (_unlinkedClass.superclassConstraints.isNotEmpty) {
ResynthesizerContext context = enclosingUnit.resynthesizerContext;
constraints = _unlinkedClass.superclassConstraints
.map((EntityRef t) => context.resolveTypeRef(this, t))
.where(_isInterfaceTypeInterface)
.cast<InterfaceType>()
.toList(growable: false);
}
if (constraints == null || constraints.isEmpty) {
constraints = [context.typeProvider.objectType];
}
return _superclassConstraints = constraints;
}
return _superclassConstraints ?? const <InterfaceType>[];
}
void set superclassConstraints(List<InterfaceType> superclassConstraints) {
_assertNotResynthesized(_unlinkedClass);
// Note: if we are using the analysis driver, the set of superclass
// constraints has already been computed, and it's more accurate. So we
// only store superclass constraints if we are using the old task model.
if (_unlinkedClass == null) {
_superclassConstraints = superclassConstraints;
}
}
@override
List<String> get superInvokedNames {
if (_superInvokedNames == null) {
if (_unlinkedClass != null) {
_superInvokedNames = _unlinkedClass.superInvokedNames;
}
}
return _superInvokedNames ?? const <String>[];
}
void set superInvokedNames(List<String> superInvokedNames) {
_assertNotResynthesized(_unlinkedClass);
if (_unlinkedClass == null) {
_superInvokedNames = superInvokedNames;
}
}
@override
InterfaceType get supertype => null;
@override
void set supertype(InterfaceType supertype) {
throw new StateError('Attempt to set a supertype for a mixin declaratio.');
}
@override
void appendTo(StringBuffer buffer) {
buffer.write('mixin ');
String name = displayName;
if (name == null) {
// TODO(brianwilkerson) Can this happen (for either classes or mixins)?
buffer.write("{unnamed mixin}");
} 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 (superclassConstraints.isNotEmpty) {
buffer.write(' on ');
buffer.write(superclassConstraints.map((t) => t.displayName).join(', '));
}
if (interfaces.isNotEmpty) {
buffer.write(' implements ');
buffer.write(interfaces.map((t) => t.displayName).join(', '));
}
}
}
/// The constants for all of the modifiers defined by the Dart language and for
/// a few additional flags that are useful.
///
/// Clients may not extend, implement or mix-in this class.
class Modifier implements Comparable<Modifier> {
/// Indicates that the modifier 'abstract' was applied to the element.
static const Modifier ABSTRACT = const Modifier('ABSTRACT', 0);
/// Indicates that an executable element has a body marked as being
/// asynchronous.
static const Modifier ASYNCHRONOUS = const Modifier('ASYNCHRONOUS', 1);
/// Indicates that the modifier 'const' was applied to the element.
static const Modifier CONST = const Modifier('CONST', 2);
/// Indicates that the modifier 'covariant' was applied to the element.
static const Modifier COVARIANT = const Modifier('COVARIANT', 3);
/// Indicates that the import element represents a deferred library.
static const Modifier DEFERRED = const Modifier('DEFERRED', 4);
/// Indicates that a class element was defined by an enum declaration.
static const Modifier ENUM = const Modifier('ENUM', 5);
/// Indicates that a class element was defined by an enum declaration.
static const Modifier EXTERNAL = const Modifier('EXTERNAL', 6);
/// Indicates that the modifier 'factory' was applied to the element.
static const Modifier FACTORY = const Modifier('FACTORY', 7);
/// Indicates that the modifier 'final' was applied to the element.
static const Modifier FINAL = const Modifier('FINAL', 8);
/// Indicates that an executable element has a body marked as being a
/// generator.
static const Modifier GENERATOR = const Modifier('GENERATOR', 9);
/// Indicates that the pseudo-modifier 'get' was applied to the element.
static const Modifier GETTER = const Modifier('GETTER', 10);
/// A flag used for libraries indicating that the defining compilation unit
/// contains at least one import directive whose URI uses the "dart-ext"
/// scheme.
static const Modifier HAS_EXT_URI = const Modifier('HAS_EXT_URI', 11);
/// Indicates that the associated element did not have an explicit type
/// associated with it. If the element is an [ExecutableElement], then the
/// type being referred to is the return type.
static const Modifier IMPLICIT_TYPE = const Modifier('IMPLICIT_TYPE', 12);
/// Indicates that modifier 'lazy' was applied to the element.
static const Modifier LAZY = const Modifier('LAZY', 13);
/// Indicates that a class is a mixin application.
static const Modifier MIXIN_APPLICATION =
const Modifier('MIXIN_APPLICATION', 14);
/// Indicates that a class contains an explicit reference to 'super'.
static const Modifier REFERENCES_SUPER =
const Modifier('REFERENCES_SUPER', 15);
/// Indicates that the pseudo-modifier 'set' was applied to the element.
static const Modifier SETTER = const Modifier('SETTER', 16);
/// Indicates that the modifier 'static' was applied to the element.
static const Modifier STATIC = const Modifier('STATIC', 17);
/// Indicates that the element does not appear in the source code but was
/// implicitly created. For example, if a class does not define any
/// constructors, an implicit zero-argument constructor will be created and it
/// will be marked as being synthetic.
static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 18);
static const List<Modifier> values = const [
ABSTRACT,
ASYNCHRONOUS,
CONST,
COVARIANT,
DEFERRED,
ENUM,
EXTERNAL,
FACTORY,
FINAL,
GENERATOR,
GETTER,
HAS_EXT_URI,
IMPLICIT_TYPE,
LAZY,
MIXIN_APPLICATION,
REFERENCES_SUPER,
SETTER,
STATIC,
SYNTHETIC
];
/// The name of this modifier.
final String name;
/// The ordinal value of the modifier.
final int ordinal;
const Modifier(this.name, this.ordinal);
@override
int get hashCode => ordinal;
@override
int compareTo(Modifier other) => ordinal - other.ordinal;
@override
String toString() => name;
}
/// A concrete implementation of a [MultiplyDefinedElement].
class MultiplyDefinedElementImpl implements MultiplyDefinedElement {
/// The unique integer identifier of this element.
final int id = ElementImpl._NEXT_ID++;
/// The analysis context in which the multiply defined elements are defined.
@override
final AnalysisContext context;
@override
final AnalysisSession session;
/// The name of the conflicting elements.
@override
final String name;
@override
final List<Element> conflictingElements;
/// Initialize a newly created element in the given [context] to represent
/// the given non-empty [conflictingElements].
MultiplyDefinedElementImpl(
this.context, this.session, this.name, this.conflictingElements);
@override
String get displayName => name;
@override
String get documentationComment => null;
@override
Element get enclosingElement => null;
@override
bool get hasAlwaysThrows => false;
@override
bool get hasDeprecated => false;
@override
bool get hasFactory => false;
@override
bool get hasIsTest => false;
@override
bool get hasIsTestGroup => false;
@override
bool get hasJS => false;
@override
bool get hasLiteral => false;
@override
bool get hasMustCallSuper => false;
@override
bool get hasOptionalTypeArgs => false;
@override
bool get hasOverride => false;
@override
bool get hasProtected => false;
@override
bool get hasRequired => false;
@override
bool get hasSealed => false;
@override
bool get hasVisibleForTemplate => false;
@override
bool get hasVisibleForTesting => false;
@override
bool get isAlwaysThrows => false;
@override
bool get isDeprecated => false;
@override
bool get isFactory => false;
@override
bool get isJS => false;
@override
bool get isOverride => false;
@override
bool get isPrivate {
String name = displayName;
if (name == null) {
return false;
}
return Identifier.isPrivateName(name);
}
@override
bool get isProtected => false;
@override
bool get isPublic => !isPrivate;
@override
bool get isRequired => false;
@override
bool get isSynthetic => true;
bool get isVisibleForTemplate => false;
@override
bool get isVisibleForTesting => false;
@override
ElementKind get kind => ElementKind.ERROR;
@override
LibraryElement get library => null;
@override
Source get librarySource => null;
@override
ElementLocation get location => null;
@override
List<ElementAnnotation> get metadata => const <ElementAnnotation>[];
@override
int get nameLength => displayName != null ? displayName.length : 0;
@override
int get nameOffset => -1;
@override
Source get source => null;
@override
DartType get type => DynamicTypeImpl.instance;
@override
CompilationUnit get unit => null;
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitMultiplyDefinedElement(this);
@override
String computeDocumentationComment() => null;
@deprecated
@override
AstNode computeNode() => null;
@override
E getAncestor<E extends Element>(Predicate<Element> predicate) => null;
@override
String getExtendedDisplayName(String shortName) {
if (shortName != null) {
return shortName;
}
return displayName;
}
@override
bool isAccessibleIn(LibraryElement library) {
for (Element element in conflictingElements) {
if (element.isAccessibleIn(library)) {
return true;
}
}
return false;
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
bool needsSeparator = false;
void writeList(List<Element> elements) {
for (Element element in elements) {
if (needsSeparator) {
buffer.write(", ");
} else {
needsSeparator = true;
}
if (element is ElementImpl) {
element.appendTo(buffer);
} else {
buffer.write(element);
}
}
}
buffer.write("[");
writeList(conflictingElements);
buffer.write("]");
return buffer.toString();
}
@override
void visitChildren(ElementVisitor visitor) {
// There are no children to visit
}
}
/// A [MethodElementImpl], with the additional information of a list of
/// [ExecutableElement]s from which this element was composed.
class MultiplyInheritedMethodElementImpl extends MethodElementImpl
implements MultiplyInheritedExecutableElement {
/// A list the array of executable elements that were used to compose this
/// element.
List<ExecutableElement> _elements = const <MethodElement>[];
MultiplyInheritedMethodElementImpl(Identifier name) : super.forNode(name) {
isSynthetic = true;
}
@override
List<ExecutableElement> get inheritedElements => _elements;
void set inheritedElements(List<ExecutableElement> elements) {
this._elements = elements;
}
}
/// A [PropertyAccessorElementImpl], with the additional information of a list
/// of[ExecutableElement]s from which this element was composed.
class MultiplyInheritedPropertyAccessorElementImpl
extends PropertyAccessorElementImpl
implements MultiplyInheritedExecutableElement {
/// A list the array of executable elements that were used to compose this
/// element.
List<ExecutableElement> _elements = const <PropertyAccessorElement>[];
MultiplyInheritedPropertyAccessorElementImpl(Identifier name)
: super.forNode(name) {
isSynthetic = true;
}
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@override
List<ExecutableElement> get inheritedElements => _elements;
void set inheritedElements(List<ExecutableElement> elements) {
this._elements = elements;
}
}
/// A [VariableElementImpl], which is not a parameter.
abstract class NonParameterVariableElementImpl extends VariableElementImpl {
/// The unlinked representation of the variable in the summary.
final UnlinkedVariable _unlinkedVariable;
/// Initialize a newly created variable element to have the given [name] and
/// [offset].
NonParameterVariableElementImpl(String name, int offset)
: _unlinkedVariable = null,
super(name, offset);
NonParameterVariableElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: _unlinkedVariable = null,
super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created variable element to have the given [name].
NonParameterVariableElementImpl.forNode(Identifier name)
: _unlinkedVariable = null,
super.forNode(name);
/// Initialize using the given serialized information.
NonParameterVariableElementImpl.forSerialized(
this._unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(enclosingElement);
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.codeRange?.offset;
}
return super.codeOffset;
}
@override
String get documentationComment {
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var comment = context.getDocumentationComment(linkedNode);
return getCommentNodeRawText(comment);
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.documentationComment?.text;
}
return super.documentationComment;
}
@override
bool get hasImplicitType {
if (linkedNode != null) {
return linkedContext.hasImplicitType(linkedNode);
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.type == null;
}
return super.hasImplicitType;
}
@override
void set hasImplicitType(bool hasImplicitType) {
_assertNotResynthesized(_unlinkedVariable);
super.hasImplicitType = hasImplicitType;
}
@override
FunctionElement get initializer {
if (_initializer == null) {
if (linkedNode != null) {
if (linkedContext.readInitializer(linkedNode) != null) {
_initializer = new FunctionElementImpl('', -1)..isSynthetic = true;
}
}
if (_unlinkedVariable != null) {
UnlinkedExecutable unlinkedInitializer = _unlinkedVariable.initializer;
if (unlinkedInitializer != null) {
_initializer =
new FunctionElementImpl.forSerialized(unlinkedInitializer, this)
..isSynthetic = true;
} else {
return null;
}
}
}
return super.initializer;
}
/// Set the function representing this variable's initializer to the given
/// [function].
void set initializer(FunctionElement function) {
_assertNotResynthesized(_unlinkedVariable);
super.initializer = function;
}
@override
bool get isConst {
if (_unlinkedVariable != null) {
return _unlinkedVariable.isConst;
}
return super.isConst;
}
@override
void set isConst(bool isConst) {
_assertNotResynthesized(_unlinkedVariable);
super.isConst = isConst;
}
@override
bool get isFinal {
if (_unlinkedVariable != null) {
return _unlinkedVariable.isFinal;
}
return super.isFinal;
}
@override
void set isFinal(bool isFinal) {
_assertNotResynthesized(_unlinkedVariable);
super.isFinal = isFinal;
}
@override
List<ElementAnnotation> get metadata {
if (_unlinkedVariable != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, _unlinkedVariable.annotations);
}
return super.metadata;
}
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (_unlinkedVariable != null) {
return _unlinkedVariable.name;
}
return super.name;
}
@override
int get nameOffset {
if (linkedNode != null) {
return enclosingUnit.linkedContext.getNameOffset(linkedNode);
}
int offset = super.nameOffset;
if (offset == 0) {
if (_unlinkedVariable != null) {
return _unlinkedVariable.nameOffset;
}
}
return offset;
}
@override
DartType get type {
if (_unlinkedVariable != null && _declaredType == null && _type == null) {
_type = enclosingUnit.resynthesizerContext
.resolveLinkedType(this, _unlinkedVariable.inferredTypeSlot);
declaredType = enclosingUnit.resynthesizerContext
.resolveTypeRef(this, _unlinkedVariable.type, declaredType: true);
}
return super.type;
}
@override
void set type(DartType type) {
if (linkedNode != null) {
return linkedContext.setVariableType(linkedNode, type);
}
_assertNotResynthesized(_unlinkedVariable);
_type = _checkElementOfType(type);
}
@override
TopLevelInferenceError get typeInferenceError {
if (_unlinkedVariable != null) {
return enclosingUnit.resynthesizerContext
.getTypeInferenceError(_unlinkedVariable.inferredTypeSlot);
}
// We don't support type inference errors without linking.
return null;
}
/// Subclasses need this getter, see [ConstVariableElement._unlinkedConst].
UnlinkedExpr get _unlinkedConst => _unlinkedVariable?.initializer?.bodyExpr;
}
/// A concrete implementation of a [ParameterElement].
class ParameterElementImpl extends VariableElementImpl
with ParameterElementMixin
implements ParameterElement {
/// The unlinked representation of the parameter in the summary.
final UnlinkedParam unlinkedParam;
/// A list containing all of the parameters defined by this parameter element.
/// There will only be parameters if this parameter is a function typed
/// parameter.
List<ParameterElement> _parameters;
/// A list containing all of the type parameters defined for this parameter
/// element. There will only be parameters if this parameter is a function
/// typed parameter.
List<TypeParameterElement> _typeParameters;
/// The kind of this parameter.
ParameterKind _parameterKind;
/// The Dart code of the default value.
String _defaultValueCode;
/// The offset to the beginning of the visible range for this element.
int _visibleRangeOffset = 0;
/// The length of the visible range for this element, or `-1` if this element
/// does not have a visible range.
int _visibleRangeLength = -1;
bool _inheritsCovariant = false;
/// Initialize a newly created parameter element to have the given [name] and
/// [nameOffset].
ParameterElementImpl(String name, int nameOffset)
: unlinkedParam = null,
super(name, nameOffset);
ParameterElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, FormalParameter linkedNode)
: unlinkedParam = null,
super.forLinkedNode(enclosing, reference, linkedNode);
factory ParameterElementImpl.forLinkedNodeFactory(
ElementImpl enclosing, Reference reference, FormalParameter node) {
if (node is FieldFormalParameter) {
return FieldFormalParameterElementImpl.forLinkedNode(
enclosing,
reference,
node,
);
} else if (node is FunctionTypedFormalParameter ||
node is SimpleFormalParameter) {
return ParameterElementImpl.forLinkedNode(enclosing, reference, node);
} else {
throw UnimplementedError('${node.runtimeType}');
}
}
/// Initialize a newly created parameter element to have the given [name].
ParameterElementImpl.forNode(Identifier name)
: unlinkedParam = null,
super.forNode(name);
/// Initialize using the given serialized information.
ParameterElementImpl.forSerialized(
this.unlinkedParam, ElementImpl enclosingElement)
: super.forSerialized(enclosingElement);
/// Initialize using the given serialized information.
factory ParameterElementImpl.forSerializedFactory(
UnlinkedParam unlinkedParameter, ElementImpl enclosingElement,
{bool synthetic: false}) {
ParameterElementImpl element;
if (unlinkedParameter.isInitializingFormal) {
if (unlinkedParameter.kind == UnlinkedParamKind.required) {
element = new FieldFormalParameterElementImpl.forSerialized(
unlinkedParameter, enclosingElement);
} else {
element = new DefaultFieldFormalParameterElementImpl.forSerialized(
unlinkedParameter, enclosingElement);
}
} else {
if (unlinkedParameter.kind == UnlinkedParamKind.required) {
element = new ParameterElementImpl.forSerialized(
unlinkedParameter, enclosingElement);
} else {
element = new DefaultParameterElementImpl.forSerialized(
unlinkedParameter, enclosingElement);
}
}
element.isSynthetic = synthetic;
return element;
}
/// Creates a synthetic parameter with [name], [type] and [kind].
factory ParameterElementImpl.synthetic(
String name, DartType type, ParameterKind kind) {
ParameterElementImpl element = new ParameterElementImpl(name, -1);
element.type = type;
element.isSynthetic = true;
element.parameterKind = kind;
return element;
}
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (unlinkedParam != null) {
return unlinkedParam.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (unlinkedParam != null) {
return unlinkedParam.codeRange?.offset;
}
return super.codeOffset;
}
@override
String get defaultValueCode {
if (unlinkedParam != null) {
if (unlinkedParam.initializer?.bodyExpr == null) {
return null;
}
return unlinkedParam.defaultValueCode;
}
return _defaultValueCode;
}
/// Set Dart code of the default value.
void set defaultValueCode(String defaultValueCode) {
_assertNotResynthesized(unlinkedParam);
this._defaultValueCode = StringUtilities.intern(defaultValueCode);
}
@override
bool get hasImplicitType {
if (linkedNode != null) {
return linkedContext.hasImplicitType(linkedNode);
}
if (unlinkedParam != null) {
return unlinkedParam.type == null && !unlinkedParam.isFunctionTyped;
}
return super.hasImplicitType;
}
@override
void set hasImplicitType(bool hasImplicitType) {
_assertNotResynthesized(unlinkedParam);
super.hasImplicitType = hasImplicitType;
}
/// True if this parameter inherits from a covariant parameter. This happens
/// when it overrides a method in a supertype that has a corresponding
/// covariant parameter.
bool get inheritsCovariant {
if (unlinkedParam != null) {
return enclosingUnit.resynthesizerContext
.inheritsCovariant(unlinkedParam.inheritsCovariantSlot);
} else {
return _inheritsCovariant;
}
}
/// Record whether or not this parameter inherits from a covariant parameter.
void set inheritsCovariant(bool value) {
_assertNotResynthesized(unlinkedParam);
_inheritsCovariant = value;
}
@override
FunctionElement get initializer {
if (_initializer == null) {
if (linkedNode != null) {
if (linkedContext.readInitializer(linkedNode) != null) {
_initializer = new FunctionElementImpl('', -1)..isSynthetic = true;
}
}
if (unlinkedParam != null) {
UnlinkedExecutable unlinkedInitializer = unlinkedParam.initializer;
if (unlinkedInitializer != null) {
_initializer =
new FunctionElementImpl.forSerialized(unlinkedInitializer, this)
..isSynthetic = true;
} else {
return null;
}
}
}
return super.initializer;
}
/// Set the function representing this variable's initializer to the given
/// [function].
void set initializer(FunctionElement function) {
_assertNotResynthesized(unlinkedParam);
super.initializer = function;
}
@override
bool get isConst {
if (unlinkedParam != null) {
return false;
}
return super.isConst;
}
@override
void set isConst(bool isConst) {
_assertNotResynthesized(unlinkedParam);
super.isConst = isConst;
}
@override
bool get isCovariant {
if (linkedNode != null) {
return linkedContext.isCovariant(linkedNode);
}
if (isExplicitlyCovariant || inheritsCovariant) {
return true;
}
return false;
}
/// Return true if this parameter is explicitly marked as being covariant.
bool get isExplicitlyCovariant {
if (unlinkedParam != null) {
return unlinkedParam.isExplicitlyCovariant;
}
return hasModifier(Modifier.COVARIANT);
}
/// Set whether this variable parameter is explicitly marked as being
/// covariant.
void set isExplicitlyCovariant(bool isCovariant) {
_assertNotResynthesized(unlinkedParam);
setModifier(Modifier.COVARIANT, isCovariant);
}
@override
bool get isFinal {
if (linkedNode != null) {
FormalParameter linkedNode = this.linkedNode;
return linkedNode.isFinal;
}
if (unlinkedParam != null) {
return unlinkedParam.isFinal;
}
return super.isFinal;
}
@override
void set isFinal(bool isFinal) {
_assertNotResynthesized(unlinkedParam);
super.isFinal = isFinal;
}
@override
bool get isInitializingFormal => false;
@override
bool get isPotentiallyMutatedInClosure => true;
@override
bool get isPotentiallyMutatedInScope => true;
@override
ElementKind get kind => ElementKind.PARAMETER;
@override
List<ElementAnnotation> get metadata {
if (unlinkedParam != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, unlinkedParam.annotations);
}
return super.metadata;
}
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (unlinkedParam != null) {
return unlinkedParam.name;
}
return super.name;
}
@override
int get nameOffset {
if (linkedNode != null) {
return enclosingUnit.linkedContext.getNameOffset(linkedNode);
}
int offset = super.nameOffset;
if (offset == 0) {
if (unlinkedParam != null) {
if (isSynthetic ||
(unlinkedParam.name.isEmpty &&
unlinkedParam.kind != UnlinkedParamKind.named &&
enclosingElement is GenericFunctionTypeElement)) {
return -1;
}
return unlinkedParam.nameOffset;
}
}
return offset;
}
@override
ParameterKind get parameterKind {
if (_parameterKind != null) return _parameterKind;
if (linkedNode != null) {
FormalParameter linkedNode = this.linkedNode;
// ignore: deprecated_member_use_from_same_package
return linkedNode.kind;
}
if (unlinkedParam != null) {
switch (unlinkedParam.kind) {
case UnlinkedParamKind.named:
_parameterKind = ParameterKind.NAMED;
break;
case UnlinkedParamKind.positional:
_parameterKind = ParameterKind.POSITIONAL;
break;
case UnlinkedParamKind.required:
_parameterKind = ParameterKind.REQUIRED;
break;
}
}
return _parameterKind;
}
void set parameterKind(ParameterKind parameterKind) {
_assertNotResynthesized(unlinkedParam);
_parameterKind = parameterKind;
}
@override
List<ParameterElement> get parameters {
if (_parameters != null) return _parameters;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
var formalParameters = context.getFormalParameters(linkedNode);
if (formalParameters != null) {
var containerRef = reference.getChild('@parameter');
return _parameters = ParameterElementImpl.forLinkedNodeList(
this,
context,
containerRef,
formalParameters,
);
} else {
return _parameters ??= const <ParameterElement>[];
}
}
if (unlinkedParam != null) {
_resynthesizeTypeAndParameters();
return _parameters ??= const <ParameterElement>[];
}
return _parameters ??= const <ParameterElement>[];
}
/// Set the parameters defined by this executable element to the given
/// [parameters].
void set parameters(List<ParameterElement> parameters) {
for (ParameterElement parameter in parameters) {
(parameter as ParameterElementImpl).enclosingElement = this;
}
this._parameters = parameters;
}
@override
DartType get type {
if (linkedNode != null) {
if (_type != null) return _type;
var context = enclosingUnit.linkedContext;
return _type = context.getType(linkedNode);
}
_resynthesizeTypeAndParameters();
return super.type;
}
@override
TopLevelInferenceError get typeInferenceError {
if (unlinkedParam != null) {
return enclosingUnit.resynthesizerContext
.getTypeInferenceError(unlinkedParam.inferredTypeSlot);
}
// We don't support type inference errors without linking.
return null;
}
@override
List<TypeParameterElement> get typeParameters {
if (_typeParameters != null) return _typeParameters;
return _typeParameters ??= const <TypeParameterElement>[];
}
/// Set the type parameters defined by this parameter element to the given
/// [typeParameters].
void set typeParameters(List<TypeParameterElement> typeParameters) {
for (TypeParameterElement parameter in typeParameters) {
(parameter as TypeParameterElementImpl).enclosingElement = this;
}
this._typeParameters = typeParameters;
}
@override
SourceRange get visibleRange {
if (unlinkedParam != null) {
if (unlinkedParam.visibleLength == 0) {
return null;
}
return new SourceRange(
unlinkedParam.visibleOffset, unlinkedParam.visibleLength);
}
if (_visibleRangeLength < 0) {
return null;
}
return new SourceRange(_visibleRangeOffset, _visibleRangeLength);
}
/// Subclasses need this getter, see [ConstVariableElement._unlinkedConst].
UnlinkedExpr get _unlinkedConst => unlinkedParam?.initializer?.bodyExpr;
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitParameterElement(this);
@override
void appendTo(StringBuffer buffer) {
String left = "";
String right = "";
while (true) {
if (parameterKind == ParameterKind.NAMED) {
left = "{";
right = "}";
} else if (parameterKind == ParameterKind.POSITIONAL) {
left = "[";
right = "]";
} else if (parameterKind == ParameterKind.REQUIRED) {}
break;
}
buffer.write(left);
appendToWithoutDelimiters(buffer);
buffer.write(right);
}
@deprecated
@override
FormalParameter computeNode() =>
getNodeMatching((node) => node is FormalParameter);
/// Set the visible range for this element to the range starting at the given
/// [offset] with the given [length].
void setVisibleRange(int offset, int length) {
_assertNotResynthesized(unlinkedParam);
_visibleRangeOffset = offset;
_visibleRangeLength = length;
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(parameters, visitor);
}
/// If this element is resynthesized, and its type and parameters have not
/// been build yet, build them and remember in the corresponding fields.
void _resynthesizeTypeAndParameters() {
if (unlinkedParam != null && _declaredType == null && _type == null) {
if (unlinkedParam.isFunctionTyped) {
CompilationUnitElementImpl enclosingUnit = this.enclosingUnit;
var typeElement = new GenericFunctionTypeElementImpl.forOffset(-1);
typeElement.enclosingElement = this;
_parameters = ParameterElementImpl.resynthesizeList(
unlinkedParam.parameters, typeElement,
synthetic: isSynthetic);
typeElement.parameters = _parameters;
typeElement.returnType = enclosingUnit.resynthesizerContext
.resolveTypeRef(this, unlinkedParam.type);
_type = new FunctionTypeImpl(typeElement);
typeElement.type = _type;
} else {
if (unlinkedParam.inferredTypeSlot != 0) {
_type = enclosingUnit.resynthesizerContext
.resolveLinkedType(this, unlinkedParam.inferredTypeSlot);
}
declaredType = enclosingUnit.resynthesizerContext
.resolveTypeRef(this, unlinkedParam.type, declaredType: true);
}
}
}
static List<ParameterElement> forLinkedNodeList(
ElementImpl enclosing,
LinkedUnitContext context,
Reference containerRef,
List<FormalParameter> formalParameters) {
if (formalParameters == null) {
return const [];
}
return formalParameters.map((node) {
if (node is DefaultFormalParameter) {
NormalFormalParameter parameterNode = node.parameter;
var name = parameterNode.identifier.name;
var reference = containerRef.getChild(name);
reference.node2 = node;
if (parameterNode is FieldFormalParameter) {
return DefaultFieldFormalParameterElementImpl.forLinkedNode(
enclosing,
reference,
node,
);
} else {
return DefaultParameterElementImpl.forLinkedNode(
enclosing,
reference,
node,
);
}
} else {
if (node.identifier == null) {
return ParameterElementImpl.forLinkedNodeFactory(
enclosing,
containerRef.getChild(''),
node,
);
} else {
var name = node.identifier.name;
var reference = containerRef.getChild(name);
if (reference.hasElementFor(node)) {
return reference.element as ParameterElement;
}
return ParameterElementImpl.forLinkedNodeFactory(
enclosing,
reference,
node,
);
}
}
}).toList();
}
/// Create and return [ParameterElement]s for the given [unlinkedParameters].
static List<ParameterElement> resynthesizeList(
List<UnlinkedParam> unlinkedParameters, ElementImpl enclosingElement,
{bool synthetic: false}) {
int length = unlinkedParameters.length;
if (length != 0) {
List<ParameterElement> parameters = new List<ParameterElement>(length);
for (int i = 0; i < length; i++) {
parameters[i] = new ParameterElementImpl.forSerializedFactory(
unlinkedParameters[i], enclosingElement,
synthetic: synthetic);
}
return parameters;
} else {
return const <ParameterElement>[];
}
}
}
/// The parameter of an implicit setter.
class ParameterElementImpl_ofImplicitSetter extends ParameterElementImpl {
final PropertyAccessorElementImpl_ImplicitSetter setter;
ParameterElementImpl_ofImplicitSetter(
PropertyAccessorElementImpl_ImplicitSetter setter)
: setter = setter,
super('_${setter.variable.name}', setter.variable.nameOffset) {
enclosingElement = setter;
isSynthetic = true;
parameterKind = ParameterKind.REQUIRED;
}
@override
bool get inheritsCovariant {
PropertyInducingElement variable = setter.variable;
if (variable is FieldElementImpl && variable._unlinkedVariable != null) {
return enclosingUnit.resynthesizerContext
.inheritsCovariant(variable._unlinkedVariable.inheritsCovariantSlot);
}
return super.inheritsCovariant;
}
@override
bool get isCovariant {
if (isExplicitlyCovariant || inheritsCovariant) {
return true;
}
return false;
}
@override
bool get isExplicitlyCovariant {
PropertyInducingElement variable = setter.variable;
if (variable is FieldElementImpl) {
return variable.isCovariant;
}
return false;
}
@override
DartType get type => setter.variable.type;
@override
void set type(DartType type) {
assert(false); // Should never be called.
}
}
/// A mixin that provides a common implementation for methods defined in
/// [ParameterElement].
mixin ParameterElementMixin implements ParameterElement {
@override
bool get isNamed => parameterKind == ParameterKind.NAMED;
@override
bool get isNotOptional => parameterKind == ParameterKind.REQUIRED;
@override
bool get isOptional =>
parameterKind == ParameterKind.NAMED ||
parameterKind == ParameterKind.POSITIONAL;
@override
bool get isOptionalPositional => parameterKind == ParameterKind.POSITIONAL;
@override
bool get isPositional =>
parameterKind == ParameterKind.POSITIONAL ||
parameterKind == ParameterKind.REQUIRED;
@override
// Overridden to remove the 'deprecated' annotation.
ParameterKind get parameterKind;
@override
void appendToWithoutDelimiters(StringBuffer buffer) {
buffer.write(type);
buffer.write(" ");
buffer.write(displayName);
if (defaultValueCode != null) {
if (parameterKind == ParameterKind.NAMED) {
buffer.write(": ");
}
if (parameterKind == ParameterKind.POSITIONAL) {
buffer.write(" = ");
}
buffer.write(defaultValueCode);
}
}
}
/// A concrete implementation of a [PrefixElement].
class PrefixElementImpl extends ElementImpl implements PrefixElement {
/// The unlinked representation of the import in the summary.
final UnlinkedImport _unlinkedImport;
/// Initialize a newly created method element to have the given [name] and
/// [nameOffset].
PrefixElementImpl(String name, int nameOffset)
: _unlinkedImport = null,
super(name, nameOffset);
PrefixElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, SimpleIdentifier linkedNode)
: _unlinkedImport = null,
super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created prefix element to have the given [name].
PrefixElementImpl.forNode(Identifier name)
: _unlinkedImport = null,
super.forNode(name);
/// Initialize using the given serialized information.
PrefixElementImpl.forSerialized(
this._unlinkedImport, LibraryElementImpl enclosingLibrary)
: super.forSerialized(enclosingLibrary);
@override
String get displayName => name;
@override
LibraryElement get enclosingElement =>
super.enclosingElement as LibraryElement;
@override
List<LibraryElement> get importedLibraries => const <LibraryElement>[];
@override
ElementKind get kind => ElementKind.PREFIX;
@override
String get name {
if (linkedNode != null) {
return reference.name;
}
if (_name == null) {
if (_unlinkedImport != null) {
LibraryElementImpl library = enclosingElement as LibraryElementImpl;
int prefixId = _unlinkedImport.prefixReference;
return _name = library.unlinkedDefiningUnit.references[prefixId].name;
}
}
return super.name;
}
@override
int get nameOffset {
if (linkedNode != null) {
return (linkedNode as SimpleIdentifier).offset;
}
int offset = super.nameOffset;
if (offset == 0 && _unlinkedImport != null) {
return _unlinkedImport.prefixOffset;
}
return offset;
}
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitPrefixElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write("as ");
super.appendTo(buffer);
}
}
/// A concrete implementation of a [PropertyAccessorElement].
class PropertyAccessorElementImpl extends ExecutableElementImpl
implements PropertyAccessorElement {
/// The variable associated with this accessor.
PropertyInducingElement variable;
/// Initialize a newly created property accessor element to have the given
/// [name] and [offset].
PropertyAccessorElementImpl(String name, int offset) : super(name, offset);
PropertyAccessorElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created property accessor element to have the given
/// [name].
PropertyAccessorElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
PropertyAccessorElementImpl.forSerialized(
UnlinkedExecutable serializedExecutable, ElementImpl enclosingElement)
: super.forSerialized(serializedExecutable, enclosingElement);
/// Initialize a newly created synthetic property accessor element to be
/// associated with the given [variable].
PropertyAccessorElementImpl.forVariable(PropertyInducingElementImpl variable,
{Reference reference})
: super(variable.name, variable.nameOffset, reference: reference) {
this.variable = variable;
isStatic = variable.isStatic;
isSynthetic = true;
}
/// Set whether this accessor is abstract.
void set abstract(bool isAbstract) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.ABSTRACT, isAbstract);
}
@override
PropertyAccessorElement get correspondingGetter {
if (isGetter || variable == null) {
return null;
}
return variable.getter;
}
@override
PropertyAccessorElement get correspondingSetter {
if (isSetter || variable == null) {
return null;
}
return variable.setter;
}
@override
String get displayName {
if (serializedExecutable != null && isSetter) {
String name = serializedExecutable.name;
assert(name.endsWith('='));
return name.substring(0, name.length - 1);
}
return super.displayName;
}
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext {
return (enclosingElement as ElementImpl).typeParameterContext;
}
/// Set whether this accessor is a getter.
void set getter(bool isGetter) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.GETTER, isGetter);
}
@override
String get identifier {
String name = displayName;
String suffix = isGetter ? "?" : "=";
return "$name$suffix";
}
@override
bool get isGetter {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isGetter(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.kind == UnlinkedExecutableKind.getter;
}
return hasModifier(Modifier.GETTER);
}
@override
bool get isSetter {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isSetter(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.kind == UnlinkedExecutableKind.setter;
}
return hasModifier(Modifier.SETTER);
}
@override
bool get isStatic {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isStatic(linkedNode);
}
if (serializedExecutable != null) {
return serializedExecutable.isStatic ||
variable is TopLevelVariableElement;
}
return hasModifier(Modifier.STATIC);
}
/// Set whether this accessor is static.
void set isStatic(bool isStatic) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.STATIC, isStatic);
}
@override
ElementKind get kind {
if (isGetter) {
return ElementKind.GETTER;
}
return ElementKind.SETTER;
}
@override
String get name {
if (linkedNode != null) {
var name = reference.name;
if (isSetter) {
return '$name=';
}
return name;
}
if (serializedExecutable != null) {
return serializedExecutable.name;
}
if (isSetter) {
return "${super.name}=";
}
return super.name;
}
/// Set whether this accessor is a setter.
void set setter(bool isSetter) {
_assertNotResynthesized(serializedExecutable);
setModifier(Modifier.SETTER, isSetter);
}
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitPropertyAccessorElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write(isGetter ? "get " : "set ");
buffer.write(variable.displayName);
super.appendTo(buffer);
}
@deprecated
@override
AstNode computeNode() {
if (isSynthetic) {
return null;
}
if (enclosingElement is ClassElement) {
return getNodeMatching((node) => node is MethodDeclaration);
} else if (enclosingElement is CompilationUnitElement) {
return getNodeMatching((node) => node is FunctionDeclaration);
}
return null;
}
}
/// Implicit getter for a [PropertyInducingElementImpl].
class PropertyAccessorElementImpl_ImplicitGetter
extends PropertyAccessorElementImpl {
/// Create the implicit getter and bind it to the [property].
PropertyAccessorElementImpl_ImplicitGetter(
PropertyInducingElementImpl property,
{Reference reference})
: super.forVariable(property, reference: reference) {
property.getter = this;
enclosingElement = property.enclosingElement;
}
@override
bool get hasImplicitReturnType => variable.hasImplicitType;
@override
bool get isGetter => true;
@override
DartType get returnType => variable.type;
@override
void set returnType(DartType returnType) {
assert(false); // Should never be called.
}
@override
FunctionType get type {
return _type ??= new FunctionTypeImpl(this);
}
@override
void set type(FunctionType type) {
assert(false); // Should never be called.
}
}
/// Implicit setter for a [PropertyInducingElementImpl].
class PropertyAccessorElementImpl_ImplicitSetter
extends PropertyAccessorElementImpl {
/// Create the implicit setter and bind it to the [property].
PropertyAccessorElementImpl_ImplicitSetter(
PropertyInducingElementImpl property,
{Reference reference})
: super.forVariable(property, reference: reference) {
property.setter = this;
enclosingElement = property.enclosingElement;
}
@override
bool get isSetter => true;
@override
List<ParameterElement> get parameters {
return _parameters ??= <ParameterElement>[
new ParameterElementImpl_ofImplicitSetter(this)
];
}
@override
DartType get returnType => VoidTypeImpl.instance;
@override
void set returnType(DartType returnType) {
assert(false); // Should never be called.
}
@override
FunctionType get type {
return _type ??= new FunctionTypeImpl(this);
}
@override
void set type(FunctionType type) {
assert(false); // Should never be called.
}
}
/// A concrete implementation of a [PropertyInducingElement].
abstract class PropertyInducingElementImpl
extends NonParameterVariableElementImpl implements PropertyInducingElement {
/// The getter associated with this element.
PropertyAccessorElement getter;
/// The setter associated with this element, or `null` if the element is
/// effectively `final` and therefore does not have a setter associated with
/// it.
PropertyAccessorElement setter;
/// Initialize a newly created synthetic element to have the given [name] and
/// [offset].
PropertyInducingElementImpl(String name, int offset) : super(name, offset);
PropertyInducingElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created element to have the given [name].
PropertyInducingElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
PropertyInducingElementImpl.forSerialized(
UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(unlinkedVariable, enclosingElement);
@override
bool get isConstantEvaluated => true;
@deprecated
@override
DartType get propagatedType => null;
@deprecated
void set propagatedType(DartType propagatedType) {}
@override
DartType get type {
if (linkedNode != null) {
if (_type != null) return _type;
return _type = linkedContext.getType(linkedNode);
}
if (isSynthetic && _type == null) {
if (getter != null) {
_type = getter.returnType;
} else if (setter != null) {
List<ParameterElement> parameters = setter.parameters;
_type = parameters.isNotEmpty
? parameters[0].type
: DynamicTypeImpl.instance;
} else {
_type = DynamicTypeImpl.instance;
}
}
return super.type;
}
}
/// The context in which elements are resynthesized.
abstract class ResynthesizerContext {
@deprecated
bool get isStrongMode;
/// Build [ElementAnnotationImpl] for the given [UnlinkedExpr].
ElementAnnotationImpl buildAnnotation(ElementImpl context, UnlinkedExpr uc);
/// Build [Expression] for the given [UnlinkedExpr].
Expression buildExpression(ElementImpl context, UnlinkedExpr uc);
/// Build explicit top-level property accessors.
UnitExplicitTopLevelAccessors buildTopLevelAccessors();
/// Build explicit top-level variables.
UnitExplicitTopLevelVariables buildTopLevelVariables();
/// Return the error reported during type inference for the given [slot],
/// or `null` if there was no error.
TopLevelInferenceError getTypeInferenceError(int slot);
/// Return `true` if the given parameter [slot] inherits `@covariant`
/// behavior.
bool inheritsCovariant(int slot);
/// Return `true` if the given const constructor [slot] is a part of a cycle.
bool isInConstCycle(int slot);
bool isSimplyBounded(int notSimplyBoundedSlot);
/// Resolve an [EntityRef] into a constructor. If the reference is
/// unresolved, return `null`.
ConstructorElement resolveConstructorRef(
ElementImpl context, EntityRef entry);
/// Build the appropriate [DartType] object corresponding to a slot id in the
/// [LinkedUnit.types] table.
DartType resolveLinkedType(ElementImpl context, int slot);
/// Resolve an [EntityRef] into a type. If the reference is
/// unresolved, return [DynamicTypeImpl.instance].
///
/// TODO(paulberry): or should we have a class representing an
/// unresolved type, for consistency with the full element model?
DartType resolveTypeRef(ElementImpl context, EntityRef type,
{bool defaultVoid: false,
bool instantiateToBoundsAllowed: true,
bool declaredType: false});
}
/// A concrete implementation of a [ShowElementCombinator].
class ShowElementCombinatorImpl implements ShowElementCombinator {
/// The unlinked representation of the combinator in the summary.
final UnlinkedCombinator _unlinkedCombinator;
final LinkedUnitContext linkedContext;
final ShowCombinator linkedNode;
/// The names that are to be made visible in the importing library if they are
/// defined in the imported library.
List<String> _shownNames;
/// The offset of the character immediately following the last character of
/// this node.
int _end = -1;
/// The offset of the 'show' keyword of this element.
int _offset = 0;
ShowElementCombinatorImpl()
: _unlinkedCombinator = null,
linkedContext = null,
linkedNode = null;
ShowElementCombinatorImpl.forLinkedNode(this.linkedContext, this.linkedNode)
: _unlinkedCombinator = null;
/// Initialize using the given serialized information.
ShowElementCombinatorImpl.forSerialized(this._unlinkedCombinator)
: linkedContext = null,
linkedNode = null;
@override
int get end {
if (_unlinkedCombinator != null) {
return _unlinkedCombinator.end;
}
return _end;
}
void set end(int end) {
_assertNotResynthesized(_unlinkedCombinator);
_end = end;
}
@override
int get offset {
if (linkedNode != null) {
return linkedNode.keyword.offset;
}
if (_unlinkedCombinator != null) {
return _unlinkedCombinator.offset;
}
return _offset;
}
void set offset(int offset) {
_assertNotResynthesized(_unlinkedCombinator);
_offset = offset;
}
@override
List<String> get shownNames {
if (_shownNames != null) return _shownNames;
if (linkedNode != null) {
return _shownNames = linkedNode.shownNames.map((i) => i.name).toList();
}
if (_unlinkedCombinator != null) {
return _shownNames = _unlinkedCombinator.shows.toList(growable: false);
}
return _shownNames ?? const <String>[];
}
void set shownNames(List<String> shownNames) {
_assertNotResynthesized(_unlinkedCombinator);
_shownNames = shownNames;
}
@override
String toString() {
StringBuffer buffer = new StringBuffer();
buffer.write("show ");
int count = shownNames.length;
for (int i = 0; i < count; i++) {
if (i > 0) {
buffer.write(", ");
}
buffer.write(shownNames[i]);
}
return buffer.toString();
}
}
/// Mixin providing the implementation of
/// [TypeParameterizedElement.isSimplyBounded] for elements that define a type.
mixin SimplyBoundableMixin implements TypeParameterizedElement {
CompilationUnitElementImpl get enclosingUnit;
@override
bool get isSimplyBounded {
var notSimplyBoundedSlot = _notSimplyBoundedSlot;
if (notSimplyBoundedSlot == null) {
// No summary is in use; we must be on the old task model. Not supported.
// TODO(paulberry): remove this check when the old task model is gone.
return true;
}
if (notSimplyBoundedSlot == 0) {
return true;
}
return enclosingUnit.resynthesizerContext
.isSimplyBounded(_notSimplyBoundedSlot);
}
int get _notSimplyBoundedSlot;
}
/// A concrete implementation of a [TopLevelVariableElement].
class TopLevelVariableElementImpl extends PropertyInducingElementImpl
implements TopLevelVariableElement {
/// Initialize a newly created synthetic top-level variable element to have
/// the given [name] and [offset].
TopLevelVariableElementImpl(String name, int offset) : super(name, offset);
TopLevelVariableElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode) {
if (!linkedNode.isSynthetic) {
var enclosingRef = enclosing.reference;
this.getter = PropertyAccessorElementImpl_ImplicitGetter(
this,
reference: enclosingRef.getChild('@getter').getChild(name),
);
if (!isConst && !isFinal) {
this.setter = PropertyAccessorElementImpl_ImplicitSetter(
this,
reference: enclosingRef.getChild('@setter').getChild(name),
);
}
}
}
factory TopLevelVariableElementImpl.forLinkedNodeFactory(
ElementImpl enclosing, Reference reference, AstNode linkedNode) {
if (enclosing.enclosingUnit.linkedContext.isConst(linkedNode)) {
return ConstTopLevelVariableElementImpl.forLinkedNode(
enclosing,
reference,
linkedNode,
);
}
return TopLevelVariableElementImpl.forLinkedNode(
enclosing,
reference,
linkedNode,
);
}
/// Initialize a newly created top-level variable element to have the given
/// [name].
TopLevelVariableElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
TopLevelVariableElementImpl.forSerialized(
UnlinkedVariable unlinkedVariable, ElementImpl enclosingElement)
: super.forSerialized(unlinkedVariable, enclosingElement);
@override
bool get isStatic => true;
@override
ElementKind get kind => ElementKind.TOP_LEVEL_VARIABLE;
UnlinkedVariable get unlinkedVariableForTesting => _unlinkedVariable;
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitTopLevelVariableElement(this);
@deprecated
@override
VariableDeclaration computeNode() =>
getNodeMatching((node) => node is VariableDeclaration);
}
/// A concrete implementation of a [TypeParameterElement].
class TypeParameterElementImpl extends ElementImpl
implements TypeParameterElement {
/// The unlinked representation of the type parameter in the summary.
final UnlinkedTypeParam _unlinkedTypeParam;
/// The type defined by this type parameter.
TypeParameterType _type;
/// The type representing the bound associated with this parameter, or `null`
/// if this parameter does not have an explicit bound.
DartType _bound;
/// Initialize a newly created method element to have the given [name] and
/// [offset].
TypeParameterElementImpl(String name, int offset)
: _unlinkedTypeParam = null,
super(name, offset);
TypeParameterElementImpl.forLinkedNode(
TypeParameterizedElementMixin enclosing,
Reference reference,
TypeParameter linkedNode)
: _unlinkedTypeParam = null,
super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created type parameter element to have the given
/// [name].
TypeParameterElementImpl.forNode(Identifier name)
: _unlinkedTypeParam = null,
super.forNode(name);
/// Initialize using the given serialized information.
TypeParameterElementImpl.forSerialized(
this._unlinkedTypeParam, TypeParameterizedElementMixin enclosingElement)
: super.forSerialized(enclosingElement);
/// Initialize a newly created synthetic type parameter element to have the
/// given [name], and with [synthetic] set to true.
TypeParameterElementImpl.synthetic(String name)
: _unlinkedTypeParam = null,
super(name, -1) {
isSynthetic = true;
}
DartType get bound {
if (_bound != null) return _bound;
if (linkedNode != null) {
var context = enclosingUnit.linkedContext;
return _bound = context.getTypeParameterBound(linkedNode)?.type;
}
if (_unlinkedTypeParam != null) {
if (_unlinkedTypeParam.bound == null) {
return null;
}
return _bound = enclosingUnit.resynthesizerContext.resolveTypeRef(
this, _unlinkedTypeParam.bound,
instantiateToBoundsAllowed: false, declaredType: true);
}
return _bound;
}
void set bound(DartType bound) {
_assertNotResynthesized(_unlinkedTypeParam);
_bound = _checkElementOfType(bound);
}
@override
int get codeLength {
if (linkedNode != null) {
return linkedContext.getCodeLength(linkedNode);
}
if (_unlinkedTypeParam != null) {
return _unlinkedTypeParam.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (linkedNode != null) {
return linkedContext.getCodeOffset(linkedNode);
}
if (_unlinkedTypeParam != null) {
return _unlinkedTypeParam.codeRange?.offset;
}
return super.codeOffset;
}
@override
String get displayName => name;
@override
ElementKind get kind => ElementKind.TYPE_PARAMETER;
@override
List<ElementAnnotation> get metadata {
if (_unlinkedTypeParam != null) {
return _metadata ??=
_buildAnnotations(enclosingUnit, _unlinkedTypeParam.annotations);
}
return super.metadata;
}
@override
String get name {
if (linkedNode != null) {
TypeParameter node = this.linkedNode;
return node.name.name;
}
if (_unlinkedTypeParam != null) {
return _unlinkedTypeParam.name;
}
return super.name;
}
@override
int get nameOffset {
int offset = super.nameOffset;
if (offset == 0 && _unlinkedTypeParam != null) {
return _unlinkedTypeParam.nameOffset;
}
return offset;
}
TypeParameterType get type {
if (linkedNode != null) {
_type ??= new TypeParameterTypeImpl(this);
}
if (_unlinkedTypeParam != null) {
_type ??= new TypeParameterTypeImpl(this);
}
return _type;
}
void set type(TypeParameterType type) {
_type = type;
}
@override
T accept<T>(ElementVisitor<T> visitor) =>
visitor.visitTypeParameterElement(this);
@override
void appendTo(StringBuffer buffer) {
buffer.write(displayName);
if (bound != null) {
buffer.write(" extends ");
buffer.write(bound);
}
}
}
/// Mixin representing an element which can have type parameters.
mixin TypeParameterizedElementMixin
implements
TypeParameterizedElement,
ElementImpl,
TypeParameterSerializationContext {
/// A cached list containing the type parameters declared by this element
/// directly, or `null` if the elements have not been created yet. This does
/// not include type parameters that are declared by any enclosing elements.
List<TypeParameterElement> _typeParameterElements;
/// A cached list containing the type parameter types declared by this element
/// directly, or `null` if the list has not been computed yet.
List<TypeParameterType> _typeParameterTypes;
/// Get the type parameter context enclosing this one, if any.
TypeParameterizedElementMixin get enclosingTypeParameterContext;
@override
bool get isSimplyBounded => true;
@override
TypeParameterizedElementMixin get typeParameterContext => this;
@override
List<TypeParameterElement> get typeParameters {
if (_typeParameterElements != null) return _typeParameterElements;
if (linkedNode != null) {
var typeParameters = linkedContext.getTypeParameters2(linkedNode);
if (typeParameters == null) {
return _typeParameterElements = const [];
}
return _typeParameterElements = typeParameters.typeParameters.map((node) {
TypeParameterElementImpl element = node.declaredElement;
element.enclosingElement = this;
return element;
}).toList();
}
List<UnlinkedTypeParam> unlinkedParams = unlinkedTypeParams;
if (unlinkedParams != null) {
int numTypeParameters = unlinkedParams.length;
_typeParameterElements =
new List<TypeParameterElement>(numTypeParameters);
for (int i = 0; i < numTypeParameters; i++) {
_typeParameterElements[i] =
new TypeParameterElementImpl.forSerialized(unlinkedParams[i], this);
}
}
return _typeParameterElements ?? const <TypeParameterElement>[];
}
/// Get a list of [TypeParameterType] objects corresponding to the
/// element's type parameters.
List<TypeParameterType> get typeParameterTypes {
return _typeParameterTypes ??= typeParameters
.map((TypeParameterElement e) => e.type)
.toList(growable: false);
}
/// Get the [UnlinkedTypeParam]s representing the type parameters declared by
/// this element, or `null` if this element isn't from a summary.
///
/// TODO(scheglov) make private after switching linker to Impl
List<UnlinkedTypeParam> get unlinkedTypeParams;
@override
int computeDeBruijnIndex(TypeParameterElement typeParameter,
{int offset = 0}) {
if (typeParameter.enclosingElement == this) {
var index = typeParameters.indexOf(typeParameter);
assert(index >= 0);
return typeParameters.length - index + offset;
} else if (enclosingTypeParameterContext != null) {
return enclosingTypeParameterContext.computeDeBruijnIndex(typeParameter,
offset: offset + typeParameters.length);
} else {
return null;
}
}
/// Convert the given [index] into a type parameter type.
TypeParameterType getTypeParameterType(int index) {
List<TypeParameterType> types = typeParameterTypes;
if (index <= types.length) {
return types[types.length - index];
} else if (enclosingTypeParameterContext != null) {
return enclosingTypeParameterContext
.getTypeParameterType(index - types.length);
} else {
// If we get here, it means that a summary contained a type parameter
// index that was out of range.
throw new RangeError('Invalid type parameter index');
}
}
}
/// Interface used by linker serialization methods to convert type parameter
/// references into De Bruijn indices.
abstract class TypeParameterSerializationContext {
/// Return the given [typeParameter]'s de Bruijn index in this context, or
/// `null` if it's not in scope.
///
/// If an [offset] is provided, then it is added to the computed index.
int computeDeBruijnIndex(TypeParameterElement typeParameter, {int offset: 0});
}
/// Container with information about explicit top-level property accessors and
/// corresponding implicit top-level variables.
class UnitExplicitTopLevelAccessors {
final List<PropertyAccessorElementImpl> accessors =
<PropertyAccessorElementImpl>[];
final List<TopLevelVariableElementImpl> implicitVariables =
<TopLevelVariableElementImpl>[];
}
/// Container with information about explicit top-level variables and
/// corresponding implicit top-level property accessors.
class UnitExplicitTopLevelVariables {
final List<TopLevelVariableElementImpl> variables;
final List<PropertyAccessorElementImpl> implicitAccessors =
<PropertyAccessorElementImpl>[];
UnitExplicitTopLevelVariables(int numberOfVariables)
: variables = numberOfVariables != 0
? new List<TopLevelVariableElementImpl>(numberOfVariables)
: const <TopLevelVariableElementImpl>[];
}
/// A concrete implementation of a [UriReferencedElement].
abstract class UriReferencedElementImpl extends ElementImpl
implements UriReferencedElement {
/// The offset of the URI in the file, or `-1` if this node is synthetic.
int _uriOffset = -1;
/// The offset of the character immediately following the last character of
/// this node's URI, or `-1` if this node is synthetic.
int _uriEnd = -1;
/// The URI that is specified by this directive.
String _uri;
/// Initialize a newly created import element to have the given [name] and
/// [offset]. The offset may be `-1` if the element is synthetic.
UriReferencedElementImpl(String name, int offset) : super(name, offset);
UriReferencedElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize using the given serialized information.
UriReferencedElementImpl.forSerialized(ElementImpl enclosingElement)
: super.forSerialized(enclosingElement);
/// Return the URI that is specified by this directive.
String get uri => _uri;
/// Set the URI that is specified by this directive to be the given [uri].
void set uri(String uri) {
_uri = uri;
}
/// Return the offset of the character immediately following the last
/// character of this node's URI, or `-1` if this node is synthetic.
int get uriEnd => _uriEnd;
/// Set the offset of the character immediately following the last character
/// of this node's URI to the given [offset].
void set uriEnd(int offset) {
_uriEnd = offset;
}
/// Return the offset of the URI in the file, or `-1` if this node is
/// synthetic.
int get uriOffset => _uriOffset;
/// Set the offset of the URI in the file to the given [offset].
void set uriOffset(int offset) {
_uriOffset = offset;
}
String _selectUri(
String defaultUri, List<UnlinkedConfiguration> configurations) {
for (UnlinkedConfiguration configuration in configurations) {
if (context.declaredVariables.get(configuration.name) ==
configuration.value) {
return configuration.uri;
}
}
return defaultUri;
}
}
/// A concrete implementation of a [VariableElement].
abstract class VariableElementImpl extends ElementImpl
implements VariableElement {
/// The declared type of this variable.
DartType _declaredType;
/// The inferred type of this variable.
DartType _type;
/// A synthetic function representing this variable's initializer, or `null
///` if this variable does not have an initializer.
FunctionElement _initializer;
/// Initialize a newly created variable element to have the given [name] and
/// [offset].
VariableElementImpl(String name, int offset) : super(name, offset);
VariableElementImpl.forLinkedNode(
ElementImpl enclosing, Reference reference, AstNode linkedNode)
: super.forLinkedNode(enclosing, reference, linkedNode);
/// Initialize a newly created variable element to have the given [name].
VariableElementImpl.forNode(Identifier name) : super.forNode(name);
/// Initialize using the given serialized information.
VariableElementImpl.forSerialized(ElementImpl enclosingElement)
: super.forSerialized(enclosingElement);
/// If this element represents a constant variable, and it has an initializer,
/// a copy of the initializer for the constant. Otherwise `null`.
///
/// Note that in correct Dart code, all constant variables must have
/// initializers. However, analyzer also needs to handle incorrect Dart code,
/// in which case there might be some constant variables that lack
/// initializers.
Expression get constantInitializer => null;
@override
DartObject get constantValue => evaluationResult?.value;
void set declaredType(DartType type) {
_declaredType = _checkElementOfType(type);
}
@override
String get displayName => name;
/// Return the result of evaluating this variable's initializer as a
/// compile-time constant expression, or `null` if this variable is not a
/// 'const' variable, if it does not have an initializer, or if the
/// compilation unit containing the variable has not been resolved.
EvaluationResultImpl get evaluationResult => null;
/// Set the result of evaluating this variable's initializer as a compile-time
/// constant expression to the given [result].
void set evaluationResult(EvaluationResultImpl result) {
throw new StateError(
"Invalid attempt to set a compile-time constant result");
}
@override
bool get hasImplicitType {
return hasModifier(Modifier.IMPLICIT_TYPE);
}
/// Set whether this variable element has an implicit type.
void set hasImplicitType(bool hasImplicitType) {
setModifier(Modifier.IMPLICIT_TYPE, hasImplicitType);
}
@override
FunctionElement get initializer => _initializer;
/// Set the function representing this variable's initializer to the given
/// [function].
void set initializer(FunctionElement function) {
if (function != null) {
(function as FunctionElementImpl).enclosingElement = this;
}
this._initializer = function;
}
@override
bool get isConst {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isConst(linkedNode);
}
return hasModifier(Modifier.CONST);
}
/// Set whether this variable is const.
void set isConst(bool isConst) {
setModifier(Modifier.CONST, isConst);
}
@override
bool get isConstantEvaluated => true;
@override
bool get isFinal {
if (linkedNode != null) {
return enclosingUnit.linkedContext.isFinal(linkedNode);
}
return hasModifier(Modifier.FINAL);
}
/// Set whether this variable is final.
void set isFinal(bool isFinal) {
setModifier(Modifier.FINAL, isFinal);
}
@override
bool get isPotentiallyMutatedInClosure => false;
@override
bool get isPotentiallyMutatedInScope => false;
@override
bool get isStatic => hasModifier(Modifier.STATIC);
@override
DartType get type => _type ?? _declaredType;
void set type(DartType type) {
if (linkedNode != null) {
return linkedContext.setVariableType(linkedNode, type);
}
_type = _checkElementOfType(type);
}
/// Return the error reported during type inference for this variable, or
/// `null` if this variable is not a subject of type inference, or there was
/// no error.
TopLevelInferenceError get typeInferenceError {
return null;
}
@override
void appendTo(StringBuffer buffer) {
buffer.write(type);
buffer.write(" ");
buffer.write(displayName);
}
@override
DartObject computeConstantValue() => null;
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
_initializer?.accept(visitor);
}
}