blob: 4e466b6e965e0a5dce164dac0f270c7ef8476c5c [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/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/src/dart/ast/utilities.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/error/codes.dart' show CompileTimeErrorCode;
import 'package:analyzer/src/generated/constant.dart' show EvaluationResultImpl;
import 'package:analyzer/src/generated/engine.dart'
show AnalysisContext, AnalysisEngine;
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/task/dart.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);
/**
* 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);
@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 {
/**
* 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);
/**
* 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) {
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 (_unlinkedClass != null) {
return _unlinkedClass.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (_unlinkedClass != null) {
return _unlinkedClass.codeRange?.offset;
}
return super.codeOffset;
}
@override
List<ConstructorElement> get constructors {
if (isMixinApplication) {
return _computeMixinAppConstructors();
}
if (_unlinkedClass != null && _constructors == null) {
_constructors = _unlinkedClass.executables
.where((e) => e.kind == UnlinkedExecutableKind.constructor)
.map((e) => new ConstructorElementImpl.forSerialized(e, this))
.toList(growable: false);
// Ensure at least implicit default constructor.
if (_constructors.isEmpty) {
ConstructorElementImpl constructor = new ConstructorElementImpl('', -1);
constructor.isSynthetic = true;
constructor.enclosingElement = this;
_constructors = <ConstructorElement>[constructor];
}
}
assert(_constructors != null);
return _constructors ?? const <ConstructorElement>[];
}
/**
* 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 (_unlinkedClass != null) {
return _unlinkedClass.documentationComment?.text;
}
return super.documentationComment;
}
/**
* Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
* be reported for this class.
*/
bool get doesMixinLackConstructors {
if (!isMixinApplication && mixins.isEmpty) {
// This class is not a mixin application and it doesn't have a "with"
// clause, so CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS is
// inapplicable.
return false;
}
if (supertype == null) {
// Should never happen, since Object and mixins are the only classes that
// have no supertype, and they should have been caught by the test above.
assert(false);
return false;
}
// Find the nearest class in the supertype chain that is not a mixin
// application.
ClassElement nearestNonMixinClass = supertype.element;
if (nearestNonMixinClass.isMixinApplication) {
// Use a list to keep track of the classes we've seen, so that we won't
// go into an infinite loop in the event of a non-trivial loop in the
// class hierarchy.
List<ClassElement> classesSeen = <ClassElement>[this];
while (nearestNonMixinClass.isMixinApplication) {
if (classesSeen.contains(nearestNonMixinClass)) {
// Loop in the class hierarchy (which is reported elsewhere). Don't
// confuse the user with further errors.
return false;
}
classesSeen.add(nearestNonMixinClass);
if (nearestNonMixinClass.supertype == null) {
// Should never happen, since Object and mixins are the only classes that
// have no supertype, and they are not mixin applications.
assert(false);
return false;
}
nearestNonMixinClass = nearestNonMixinClass.supertype.element;
}
}
return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
}
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@override
List<FieldElement> get fields {
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 {
return _unlinkedClass != null || _hasBeenInferred;
}
void set hasBeenInferred(bool hasBeenInferred) {
_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) {
if (_unlinkedClass != null) {
ResynthesizerContext context = enclosingUnit.resynthesizerContext;
_interfaces = _unlinkedClass.interfaces
.map((EntityRef t) => context.resolveTypeRef(this, t))
.where(_isInterfaceTypeInterface)
.cast<InterfaceType>()
.toList(growable: false);
}
}
return _interfaces ?? const <InterfaceType>[];
}
void set interfaces(List<InterfaceType> interfaces) {
_assertNotResynthesized(_unlinkedClass);
_interfaces = interfaces;
}
@override
bool get isAbstract {
if (_unlinkedClass != null) {
return _unlinkedClass.isAbstract;
}
return hasModifier(Modifier.ABSTRACT);
}
@override
bool get isMixinApplication {
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 isValidMixin {
if (!context.analysisOptions.enableSuperMixins) {
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 (_unlinkedClass != null) {
_methods ??= _unlinkedClass.executables
.where((e) => e.kind == UnlinkedExecutableKind.functionOrMethod)
.map((e) => new MethodElementImpl.forSerialized(e, this))
.toList(growable: false);
}
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) {
if (_unlinkedClass != null) {
ResynthesizerContext context = enclosingUnit.resynthesizerContext;
_mixins = _unlinkedClass.mixins
.map((EntityRef t) => context.resolveTypeRef(this, t))
.where(_isInterfaceTypeInterface)
.cast<InterfaceType>()
.toList(growable: false);
}
}
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 (_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) {
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
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
bool isSuperConstructorAccessible(ConstructorElement constructor) {
if (!constructor.isAccessibleIn(library)) {
return false;
}
// If this class has no mixins, then all superclass constructors are
// accessible.
if (mixins.isEmpty) {
return true;
}
// Otherwise only constructors that lack optional parameters are
// accessible (see dartbug.com/19576).
for (ParameterElement parameter in constructor.parameters) {
if (parameter.isOptional) {
return false;
}
}
return true;
}
@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) {
List<ConstructorElement> superclassConstructors =
supertype.element.constructors;
// Filter out any constructors with optional parameters (see
// dartbug.com/15101).
constructorsToForward =
superclassConstructors.where(isSuperConstructorAccessible);
} 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 =
new ParameterElementImpl(superParameter.name, -1);
implicitParameter.isConst = superParameter.isConst;
implicitParameter.isFinal = superParameter.isFinal;
// ignore: deprecated_member_use
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);
}
/**
* 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 explicitFields = <FieldElement>[];
var implicitAccessors = <PropertyAccessorElement>[];
var explicitAccessors = <PropertyAccessorElement>[];
var implicitFields = <String, FieldElementImpl>{};
// Build explicit fields and implicit property accessors.
for (UnlinkedVariable v in _unlinkedClass.fields) {
FieldElementImpl field =
new FieldElementImpl.forSerializedFactory(v, this);
explicitFields.add(field);
implicitAccessors.add(
new PropertyAccessorElementImpl_ImplicitGetter(field)
..enclosingElement = this);
if (!field.isConst && !field.isFinal) {
implicitAccessors.add(
new PropertyAccessorElementImpl_ImplicitSetter(field)
..enclosingElement = this);
}
}
// Build explicit property accessors and implicit fields.
for (UnlinkedExecutable e in _unlinkedClass.executables) {
if (e.kind == UnlinkedExecutableKind.getter ||
e.kind == UnlinkedExecutableKind.setter) {
PropertyAccessorElementImpl accessor =
new PropertyAccessorElementImpl.forSerialized(e, this);
explicitAccessors.add(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;
}
}
}
// Combine explicit and implicit fields and property accessors.
_fields = <FieldElement>[]
..addAll(explicitFields)
..addAll(implicitFields.values);
_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;
/**
* 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(String name)
: resynthesizerContext = null,
_unlinkedUnit = null,
_unlinkedPart = null,
super(name, -1);
/**
* Initialize using the given serialized information.
*/
CompilationUnitElementImpl.forSerialized(
LibraryElementImpl enclosingLibrary,
this.resynthesizerContext,
this._unlinkedUnit,
this._unlinkedPart,
String name)
: super.forSerialized(null) {
_enclosingElement = enclosingLibrary;
_name = name;
_nameOffset = -1;
}
@override
List<PropertyAccessorElement> get accessors {
if (_accessors == null) {
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 (_unlinkedUnit != null) {
_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 (_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 (_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 (_unlinkedUnit != null) {
_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 (_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 (_unlinkedUnit != null) {
_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);
}
}
@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;
}
}
/**
* 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);
/**
* 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);
@override
String get documentationComment {
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 (_unlinkedEnumValue != null) {
return _unlinkedEnumValue.name;
}
return super.name;
}
@override
int get nameOffset {
int offset = super.nameOffset;
if (offset == -1 && _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;
}
@override
void set evaluationResult(_) {
assert(false);
}
@override
bool get isConst => true;
@override
void set isConst(bool isConst) {
assert(false);
}
@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;
/**
* Initialize a newly created constructor element to have the given [name] and
* [offset].
*/
ConstructorElementImpl(String name, int offset) : super(name, offset);
/**
* 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) {
if (serializedExecutable != null) {
_constantInitializers = serializedExecutable.constantInitializers
.map((i) => _buildConstructorInitializer(i))
.toList(growable: false);
}
}
return _constantInitializers;
}
void set constantInitializers(
List<ConstructorInitializer> constantInitializers) {
_assertNotResynthesized(serializedExecutable);
_constantInitializers = constantInitializers;
}
@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 (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 (serializedExecutable != null) {
return serializedExecutable.isFactory;
}
return hasModifier(Modifier.FACTORY);
}
@override
bool get isStatic => false;
@override
ElementKind get kind => ElementKind.CONSTRUCTOR;
@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) {
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);
}
@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);
/**
* 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.
*/
abstract class 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) {
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;
}
/**
* 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) {
context?.computeResult(this, CONSTANT_VALUE);
}
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);
/**
* 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);
/**
* 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);
@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;
LibraryElement _library;
/**
* 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
LibraryElement get library => _library;
set library(LibraryElement library) {
assert(library.name == 'dart.core');
_library = library;
}
@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 top-level variable used to mark a method parameter as
* covariant.
*/
static String _COVARIANT_VARIABLE_NAME = "checked";
/**
* 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 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
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;
/**
* Return `true` if this annotation marks the associated parameter as being
* covariant, meaning it is allowed to have a narrower type in an override.
*/
bool get isCovariant =>
element is PropertyAccessorElement &&
element.name == _COVARIANT_VARIABLE_NAME &&
element.library?.name == _META_LIB_NAME;
@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 isMustCallSuper =>
element is PropertyAccessorElement &&
element.name == _MUST_CALL_SUPER_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) {
context?.computeResult(this, CONSTANT_VALUE);
}
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;
/**
* 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._name = StringUtilities.intern(name);
}
/**
* 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);
/**
* 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 =>
metadata.any((ElementAnnotation annotation) => annotation.isAlwaysThrows);
@override
bool get hasDeprecated =>
metadata.any((ElementAnnotation annotation) => annotation.isDeprecated);
@override
bool get hasFactory =>
metadata.any((ElementAnnotation annotation) => annotation.isFactory);
@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 =>
metadata.any((ElementAnnotation annotation) => annotation.isIsTest);
@override
bool get hasIsTestGroup =>
metadata.any((ElementAnnotation annotation) => annotation.isIsTestGroup);
@override
bool get hasJS =>
metadata.any((ElementAnnotation annotation) => annotation.isJS);
@override
bool get hasOverride =>
metadata.any((ElementAnnotation annotation) => annotation.isOverride);
@override
bool get hasProtected =>
metadata.any((ElementAnnotation annotation) => annotation.isProtected);
@override
bool get hasRequired =>
metadata.any((ElementAnnotation annotation) => annotation.isRequired);
@override
bool get hasSealed =>
metadata.any((ElementAnnotation annotation) => annotation.isSealed);
@override
bool get hasVisibleForTemplate => metadata
.any((ElementAnnotation annotation) => annotation.isVisibleForTemplate);
@override
bool get hasVisibleForTesting => metadata
.any((ElementAnnotation annotation) => annotation.isVisibleForTesting);
/**
* Return an identifier that uniquely identifies this element among the
* children of this element's parent.
*/
String get identifier => name;
@override
bool get isAlwaysThrows =>
metadata.any((ElementAnnotation annotation) => annotation.isAlwaysThrows);
@override
bool get isDeprecated {
for (ElementAnnotation annotation in metadata) {
if (annotation.isDeprecated) {
return true;
}
}
return false;
}
@override
bool get isFactory {
for (ElementAnnotation annotation in metadata) {
if (annotation.isFactory) {
return true;
}
}
return false;
}
@override
bool get isJS {
for (ElementAnnotation annotation in metadata) {
if (annotation.isJS) {
return true;
}
}
return false;
}
@override
bool get isOverride {
for (ElementAnnotation annotation in metadata) {
if (annotation.isOverride) {
return true;
}
}
return false;
}
@override
bool get isPrivate {
String name = displayName;
if (name == null) {
return true;
}
return Identifier.isPrivateName(name);
}
@override
bool get isProtected {
for (ElementAnnotation annotation in metadata) {
if (annotation.isProtected) {
return true;
}
}
return false;
}
@override
bool get isPublic => !isPrivate;
@override
bool get isRequired {
for (ElementAnnotation annotation in metadata) {
if (annotation.isRequired) {
return true;
}
}
return false;
}
/**
* Return `true` if this element is resynthesized from a summary.
*/
bool get isResynthesized => enclosingUnit?.resynthesizerContext != null;
@override
bool get isSynthetic => hasModifier(Modifier.SYNTHETIC);
/**
* Set whether this element is synthetic.
*/
void set isSynthetic(bool isSynthetic) {
setModifier(Modifier.SYNTHETIC, isSynthetic);
}
bool get isVisibleForTemplate => metadata
.any((ElementAnnotation annotation) => annotation.isVisibleForTemplate);
@override
bool get isVisibleForTesting => metadata
.any((ElementAnnotation annotation) => annotation.isVisibleForTesting);
@override
LibraryElement get library =>
getAncestor((element) => element is LibraryElement);
@override
Source get librarySource => library?.source;
@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 {
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
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;
}
@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;
@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].
*/
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.getAncestor(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>[];
}
}
/**
* 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 visted 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);
/**
* 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 (_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 (_unlinkedEnum != null) {
return _unlinkedEnum.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
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 (_unlinkedEnum != null) {
return _unlinkedEnum.documentationComment?.text;
}
return super.documentationComment;
}
@override
List<FieldElement> get fields {
if (_fields == null) {
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 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 (_unlinkedEnum != null) {
_resynthesizeMembers();
}
}
return _methods ?? const <MethodElement>[];
}
@override
List<InterfaceType> get mixins => const <InterfaceType>[];
@override
String get 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);
if (_unlinkedEnum != null) {
method.returnType = context.typeProvider.stringType;
method.type = new FunctionTypeImpl(method);
}
method.enclosingElement = this;
_methods = <MethodElement>[method];
}
@override
ConstructorElement getNamedConstructor(String name) => null;
@override
bool isSuperConstructorAccessible(ConstructorElement constructor) => false;
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();
}
}
/**
* 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)
: serializedExecutable = null,
super(name, offset);
/**
* 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 (serializedExecutable != null) {
return serializedExecutable.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
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 (serializedExecutable != null) {
return serializedExecutable.name;
}
return super.displayName;
}
@override
String get documentationComment {
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 (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 (serializedExecutable != null) {
return serializedExecutable.isAbstract;
}
return hasModifier(Modifier.ABSTRACT);
}
@override
bool get isAsynchronous {
if (serializedExecutable != null) {
return serializedExecutable.isAsynchronous;
}
return hasModifier(Modifier.ASYNCHRONOUS);
}
@override
bool get isExternal {
if (serializedExecutable != null) {
return serializedExecutable.isExternal;
}
return hasModifier(Modifier.EXTERNAL);
}
@override
bool get isGenerator {
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 (serializedExecutable != null) {
return serializedExecutable.name;
}
return super.name;
}
@override
int get nameOffset {
int offset = super.nameOffset;
if (offset == 0 && serializedExecutable != null) {
return serializedExecutable.nameOffset;
}
return offset;
}
@override
List<ParameterElement> get parameters {
if (_parameters == null) {
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 (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) {
_assertNotResynthesized(serializedExecutable);
_returnType = _checkElementOfType(returnType);
}
@override
FunctionType get type {
if (serializedExecutable != null) {
_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
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 [context] declared variables.
*/
String _selectedUri;
/**
* Initialize a newly created export element at the given [offset].
*/
ExportElementImpl(int offset)
: _unlinkedExportPublic = null,
_unlinkedExportNonPublic = null,
super(null, offset);
/**
* 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) {
if (_unlinkedExportPublic != null) {
_combinators = ImportElementImpl._buildCombinators(
_unlinkedExportPublic.combinators);
}
}
return _combinators ?? const <NamespaceCombinator>[];
}
void set combinators(List<NamespaceCombinator> combinators) {
_assertNotResynthesized(_unlinkedExportPublic);
_combinators = combinators;
}
@override
LibraryElement get exportedLibrary {
if (_exportedLibrary == null) {
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 {
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);
/**
* 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;
/**
* Return `true` if this field was explicitly marked as being covariant.
*/
bool get isCovariant {
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 isStatic {
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);
}
@override
bool get isVirtual => true;
@override
ElementKind get kind => ElementKind.FIELD;
@override
T accept<T>(ElementVisitor<T> visitor) => visitor.visitFieldElement(this);
@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);
/**
* 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 (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 && 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);
/**
* 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
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
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);
}
@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;
/**
* 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 (_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 (_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;
}
/**
* 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
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);
/**
* 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 (_unlinkedTypedef != null) {
return _unlinkedTypedef.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (_unlinkedTypedef != null) {
return _unlinkedTypedef.codeRange?.offset;
}
return super.codeOffset;
}
@override
String get displayName => name;
@override
String get documentationComment {
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) {
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
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 (_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
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);
}
}
@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) {
if (argumentTypes.length != typeParameters.length) {
throw new ArgumentError('Wrong number of type arguments supplied');
}
if (typeParameters.isEmpty) return function.type;
return typeAfterSubstitution(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.
*/
FunctionType typeAfterSubstitution(List<DartType> typeArguments) {
GenericFunctionTypeElement function = this.function;
if (function == null) {
return null;
}
FunctionType functionType = function.type;
List<TypeParameterElement> parameterElements = 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);
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(typeParameters, visitor);
function?.accept(visitor);
}
}
/**
* A concrete implementation of a [HideElementCombinator].
*/
class HideElementCombinatorImpl implements HideElementCombinator {
/**
* The unlinked representation of the combinator in the summary.
*/
final UnlinkedCombinator _unlinkedCombinator;
/**
* 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;
/**
* Initialize using the given serialized information.
*/
HideElementCombinatorImpl.forSerialized(this._unlinkedCombinator);
@override
List<String> get hiddenNames {
if (_unlinkedCombinator != null) {
_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 [context] 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);
/**
* 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) {
if (_unlinkedImport != null) {
_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
String get identifier => "${importedLibrary.identifier}@$nameOffset";
@override
LibraryElement get importedLibrary {
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 (_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 {
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) {
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>[];
}
}
}
/**
* 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;
final LibraryResynthesizerContext resynthesizerContext;
final UnlinkedUnit unlinkedDefiningUnit;
/**
* 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, String name, int offset, this.nameLength)
: resynthesizerContext = null,
unlinkedDefiningUnit = null,
super(name, offset);
/**
* Initialize a newly created library element in the given [context] to have
* the given [name].
*/
LibraryElementImpl.forNode(this.context, LibraryIdentifier name)
: nameLength = name != null ? name.length : 0,
resynthesizerContext = null,
unlinkedDefiningUnit = null,
super.forNode(name);
/**
* Initialize using the given serialized information.
*/
LibraryElementImpl.forSerialized(this.context, String name, int offset,
this.nameLength, this.resynthesizerContext, this.unlinkedDefiningUnit)
: 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 (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 (resynthesizerContext != null) {
_exportNamespace ??= resynthesizerContext.buildExportNamespace();
}
return _exportNamespace;
}
void set exportNamespace(Namespace exportNamespace) {
_exportNamespace = exportNamespace;
}
@override
List<ExportElement> get exports {
if (_exports == null) {
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) {
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) {
if (unlinkedDefiningUnit != null) {
_metadata = _buildAnnotations(
_definingCompilationUnit as CompilationUnitElementImpl,
unlinkedDefiningUnit.libraryAnnotations);
return _metadata;
}
}
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 (resynthesizerContext != null) {
_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
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 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);
}
@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);
/**
* 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 (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);
}
@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);
/**
* 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 isMixin => true;
@override
List<InterfaceType> get superclassConstraints {
if (_superclassConstraints == null) {
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];
}
_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
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 a class is a mixin application.
*/
static const Modifier MIXIN_APPLICATION =
const Modifier('MIXIN_APPLICATION', 13);
/**
* Indicates that a class contains an explicit reference to 'super'.
*/
static const Modifier REFERENCES_SUPER =
const Modifier('REFERENCES_SUPER', 14);
/**
* Indicates that the pseudo-modifier 'set' was applied to the element.
*/
static const Modifier SETTER = const Modifier('SETTER', 15);
/**
* Indicates that the modifier 'static' was applied to the element.
*/
static const Modifier STATIC = const Modifier('STATIC', 16);
/**
* 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', 17);
static const List<Modifier> values = const [
ABSTRACT,
ASYNCHRONOUS,
CONST,
COVARIANT,
DEFERRED,
ENUM,
EXTERNAL,
FACTORY,
FINAL,
GENERATOR,
GETTER,
HAS_EXT_URI,
IMPLICIT_TYPE,
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;
/**
* 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.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 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;
@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);
/**
* 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 (_unlinkedVariable != null) {
return _unlinkedVariable.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
if (_unlinkedVariable != null) {
return _unlinkedVariable.codeRange?.offset;
}
return super.codeOffset;
}
@override
String get documentationComment {
if (_unlinkedVariable != null) {
return _unlinkedVariable.documentationComment?.text;
}
return super.documentationComment;
}
@override
bool get hasImplicitType {
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 (_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 (_unlinkedVariable != null) {
return _unlinkedVariable.name;
}
return super.name;
}
@override
int get nameOffset {
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) {
_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;
/**
* 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);
/**
* 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 (unlinkedParam != null) {
return unlinkedParam.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
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 (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 (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 (isExplicitlyCovariant || inheritsCovariant) {
return true;
}
for (ElementAnnotationImpl annotation in metadata) {
if (annotation.isCovariant) {
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 (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 (unlinkedParam != null) {
return unlinkedParam.name;
}
return super.name;
}
@override
int get nameOffset {
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 (unlinkedParam != null && _parameterKind == 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 {
return const <ParameterElement>[];
}
@override
DartType get type {
_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 {
return const <TypeParameterElement>[];
}
@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);
}
@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;
typeElement.parameters = ParameterElementImpl.resynthesizeList(
unlinkedParam.parameters, typeElement,
synthetic: isSynthetic);
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);
}
}
}
/**
* 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;
}
for (ElementAnnotationImpl annotation in setter.variable.metadata) {
if (annotation.isCovariant) {
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].
*/
abstract class 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);
/**
* 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
String get identifier => "_${super.identifier}";
@override
List<LibraryElement> get importedLibraries => const <LibraryElement>[];
@override
ElementKind get kind => ElementKind.PREFIX;
@override
String get 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 {
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);
/**
* 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)
: super(variable.name, variable.nameOffset) {
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 (serializedExecutable != null) {
return serializedExecutable.kind == UnlinkedExecutableKind.getter;
}
return hasModifier(Modifier.GETTER);
}
@override
bool get isSetter {
if (serializedExecutable != null) {
return serializedExecutable.kind == UnlinkedExecutableKind.setter;
}
return hasModifier(Modifier.SETTER);
}
@override
bool get isStatic {
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 (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);
}
@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)
: super.forVariable(property) {
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)
: super.forVariable(property) {
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);
/**
* 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);
@deprecated
@override
DartType get propagatedType => null;
@deprecated
void set propagatedType(DartType propagatedType) {}
@override
DartType get type {
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);
/**
* 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;
/**
* 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;
/**
* Initialize using the given serialized information.
*/
ShowElementCombinatorImpl.forSerialized(this._unlinkedCombinator);
@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 (_unlinkedCombinator != null) {
return _unlinkedCombinator.offset;
}
return _offset;
}
void set offset(int offset) {
_assertNotResynthesized(_unlinkedCombinator);
_offset = offset;
}
@override
List<String> get shownNames {
if (_unlinkedCombinator != null) {
_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();
}
}
/**
* 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);
/**
* 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);
@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);
/**
* 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) {
if (_unlinkedTypeParam != null) {
if (_unlinkedTypeParam.bound == null) {
return null;
}
_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 (_unlinkedTypeParam != null) {
return _unlinkedTypeParam.codeRange?.length;
}
return super.codeLength;
}
@override
int get codeOffset {
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 (_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 (_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.
*/
abstract class TypeParameterizedElementMixin
implements TypeParameterizedElement, ElementImpl {
/**
* 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;
/**
* The unit in which this element is resynthesized.
*/
CompilationUnitElementImpl get enclosingUnit;
@override
TypeParameterizedElementMixin get typeParameterContext => this;
@override
List<TypeParameterElement> get typeParameters {
if (_typeParameterElements == null) {
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;
/**
* 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');
}
}
/**
* 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}) {
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;
}
}
}
/**
* 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);
/**
* 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);
/**
* 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 {
return hasModifier(Modifier.CONST);
}
/**
* Set whether this variable is const.
*/
void set isConst(bool isConst) {
setModifier(Modifier.CONST, isConst);
}
@override
bool get isFinal {
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) {
_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);
}
}