blob: 0f7bb2d0c8781308c84ed2384f4aba68382a2ce1 [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 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/error/error.dart';
import 'package:analyzer/src/context/source.dart';
import 'package:analyzer/src/dart/analysis/experiments.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/ast_factory.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/constant/compute.dart';
import 'package:analyzer/src/dart/constant/evaluation.dart';
import 'package:analyzer/src/dart/element/display_string_builder.dart';
import 'package:analyzer/src/dart/element/member.dart';
import 'package:analyzer/src/dart/element/nullability_eliminator.dart';
import 'package:analyzer/src/dart/element/scope.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/dart/resolver/scope.dart'
show Namespace, NamespaceBuilder;
import 'package:analyzer/src/dart/resolver/variance.dart';
import 'package:analyzer/src/generated/element_type_provider.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/sdk.dart' show DartSdk;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_collection.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/summary2/ast_binary_tokens.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
import 'package:analyzer/src/summary2/macro.dart';
import 'package:analyzer/src/summary2/macro_application_error.dart';
import 'package:analyzer/src/summary2/reference.dart';
import 'package:analyzer/src/task/inference_error.dart';
import 'package:collection/collection.dart';
/// A concrete implementation of a [ClassElement].
abstract class AbstractClassElementImpl extends _ExistingElementImpl
with TypeParameterizedElementMixin, HasCompletionData, MacroTargetElement
implements ClassElement {
/// The superclass of the class, or `null` for [Object].
InterfaceType? _supertype;
/// 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 = const [];
/// A list containing all of the interfaces that are implemented by this
/// class.
List<InterfaceType> _interfaces = const [];
/// The type defined by the class.
InterfaceType? _thisType;
/// A list containing all of the accessors (getters and setters) contained in
/// this class.
List<PropertyAccessorElement> _accessors = _Sentinel.propertyAccessorElement;
/// A list containing all of the fields contained in this class.
List<FieldElement> _fields = _Sentinel.fieldElement;
/// A list containing all of the methods contained in this class.
List<MethodElement> _methods = _Sentinel.methodElement;
/// This callback is set during mixins inference to handle reentrant calls.
List<InterfaceType>? Function(AbstractClassElementImpl)?
mixinInferenceCallback;
/// 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);
/// Set the accessors contained in this class to the given [accessors].
set accessors(List<PropertyAccessorElement> accessors) {
assert(!isMixinApplication);
for (PropertyAccessorElement accessor in accessors) {
(accessor as PropertyAccessorElementImpl).enclosingElement = this;
}
_accessors = accessors;
}
@override
List<InterfaceType> get allSupertypes {
var sessionImpl = library.session as AnalysisSessionImpl;
return sessionImpl.classHierarchy.implementedInterfaces(this);
}
@override
String get displayName => name;
@override
CompilationUnitElementImpl get enclosingElement {
return _enclosingElement as CompilationUnitElementImpl;
}
/// Set the fields contained in this class to the given [fields].
set fields(List<FieldElement> fields) {
assert(!isMixinApplication);
for (FieldElement field in fields) {
(field as FieldElementImpl).enclosingElement = this;
}
_fields = fields;
}
@override
List<InterfaceType> get interfaces =>
ElementTypeProvider.current.getClassInterfaces(this);
set interfaces(List<InterfaceType> interfaces) {
_interfaces = interfaces;
}
List<InterfaceType> get interfacesInternal {
return _interfaces;
}
@override
bool get isDartCoreEnum {
return name == 'Enum' && library.isDartCore;
}
/// Return `true` if this class represents the class '_Enum' defined in the
/// dart:core library.
bool get isDartCoreEnumImpl {
return name == '_Enum' && library.isDartCore;
}
@override
bool get isDartCoreObject => false;
@override
bool get isEnum => false;
@override
bool get isMixin => false;
@override
List<InterfaceType> get mixins {
if (mixinInferenceCallback != null) {
var mixins = mixinInferenceCallback!(this);
if (mixins != null) {
return _mixins = mixins;
}
}
return _mixins;
}
set mixins(List<InterfaceType> mixins) {
_mixins = mixins;
}
@override
List<InterfaceType> get superclassConstraints => const <InterfaceType>[];
@override
InterfaceType? get supertype {
if (_supertype != null) return _supertype!;
if (hasModifier(Modifier.DART_CORE_OBJECT)) {
return null;
}
return _supertype;
}
set supertype(InterfaceType? supertype) {
_supertype = supertype;
}
@override
InterfaceType get thisType {
if (_thisType == null) {
List<DartType> typeArguments;
if (typeParameters.isNotEmpty) {
typeArguments = typeParameters.map<DartType>((t) {
return t.instantiate(nullabilitySuffix: _noneOrStarSuffix);
}).toList();
} else {
typeArguments = const <DartType>[];
}
return _thisType = instantiate(
typeArguments: typeArguments,
nullabilitySuffix: _noneOrStarSuffix,
);
}
return _thisType!;
}
set typeParameters(List<TypeParameterElement> typeParameters) {
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
_typeParameterElements = typeParameters;
}
@override
ConstructorElement? get unnamedConstructor {
for (ConstructorElement element in constructors) {
if (element.name.isEmpty) {
return element;
}
}
return null;
}
@override
T? accept<T>(ElementVisitor<T> visitor) => visitor.visitClassElement(this);
@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
ConstructorElement? getNamedConstructor(String name) {
if (name == 'new') {
// A constructor declared as `C.new` is unnamed, and is modeled as such.
name = '';
}
for (ConstructorElement element in constructors) {
if (element.name == name) {
return element;
}
}
return null;
}
@override
PropertyAccessorElement? getSetter(String setterName) {
return getSetterFromAccessors(setterName, accessors);
}
@override
InterfaceType instantiate({
required List<DartType> typeArguments,
required NullabilitySuffix nullabilitySuffix,
}) {
return InterfaceTypeImpl(
element: this,
typeArguments: typeArguments,
nullabilitySuffix: nullabilitySuffix,
);
}
@override
MethodElement? lookUpConcreteMethod(
String methodName, LibraryElement library) =>
_first(_implementationsOfMethod(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.isStatic &&
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(_implementationsOfMethod(methodName).where(
(MethodElement method) =>
!method.isAbstract &&
!method.isStatic &&
method.isAccessibleIn(library) &&
method.enclosingElement != this));
@override
PropertyAccessorElement? lookUpInheritedConcreteSetter(
String setterName, LibraryElement library) =>
_first(_implementationsOfSetter(setterName).where(
(PropertyAccessorElement setter) =>
!setter.isAbstract &&
!setter.isStatic &&
setter.isAccessibleIn(library) &&
setter.enclosingElement != this));
@override
MethodElement? lookUpInheritedMethod(
String methodName, LibraryElement library) =>
_first(_implementationsOfMethod(methodName).where(
(MethodElement method) =>
!method.isStatic &&
method.isAccessibleIn(library) &&
method.enclosingElement != this));
@override
MethodElement? lookUpMethod(String methodName, LibraryElement library) =>
_first(_implementationsOfMethod(methodName)
.where((MethodElement method) => method.isAccessibleIn(library)));
@override
PropertyAccessorElement? lookUpSetter(
String setterName, LibraryElement library) =>
_first(_implementationsOfSetter(setterName).where(
(PropertyAccessorElement setter) => setter.isAccessibleIn(library)));
/// Return the static getter with the [name], accessible to the [library].
///
/// This method should be used only for error recovery during analysis,
/// when instance access to a static class member, defined in this class,
/// or a superclass.
PropertyAccessorElement? lookupStaticGetter(
String name, LibraryElement library) {
return _first(_implementationsOfGetter(name).where((element) {
return element.isStatic && element.isAccessibleIn(library);
}));
}
/// Return the static method with the [name], accessible to the [library].
///
/// This method should be used only for error recovery during analysis,
/// when instance access to a static class member, defined in this class,
/// or a superclass.
MethodElement? lookupStaticMethod(String name, LibraryElement library) {
return _first(_implementationsOfMethod(name).where((element) {
return element.isStatic && element.isAccessibleIn(library);
}));
}
/// Return the static setter with the [name], accessible to the [library].
///
/// This method should be used only for error recovery during analysis,
/// when instance access to a static class member, defined in this class,
/// or a superclass.
PropertyAccessorElement? lookupStaticSetter(
String name, LibraryElement library) {
return _first(_implementationsOfSetter(name).where((element) {
return element.isStatic && element.isAccessibleIn(library);
}));
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(accessors, visitor);
safelyVisitChildren(fields, visitor);
safelyVisitChildren(constructors, visitor);
safelyVisitChildren(methods, visitor);
safelyVisitChildren(typeParameters, 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 = HashSet<ClassElement>();
while (classElement != null && visitedClasses.add(classElement)) {
var 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 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.
Iterable<MethodElement> _implementationsOfMethod(String methodName) sync* {
ClassElement? classElement = this;
HashSet<ClassElement> visitedClasses = HashSet<ClassElement>();
while (classElement != null && visitedClasses.add(classElement)) {
var 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;
}
}
/// 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 = HashSet<ClassElement>();
while (classElement != null && visitedClasses.add(classElement)) {
var 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;
}
}
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 (!setterName.endsWith('=')) {
setterName += '=';
}
for (PropertyAccessorElement accessor in accessors) {
if (accessor.isSetter && accessor.name == setterName) {
return accessor;
}
}
return null;
}
/// 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;
}
}
/// An [AbstractClassElementImpl] which is a class.
class ClassElementImpl extends AbstractClassElementImpl {
/// 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 = _Sentinel.constructorElement;
/// A flag indicating whether the types associated with the instance members
/// of this class have been inferred.
bool hasBeenInferred = false;
ElementLinkedData? linkedData;
/// 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) : super(name, offset);
@override
List<PropertyAccessorElement> get accessors {
if (!identical(_accessors, _Sentinel.propertyAccessorElement)) {
return _accessors;
}
var linkedData = this.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.readMembers(this);
return _accessors;
}
return _accessors;
}
@override
List<ConstructorElement> get constructors {
if (!identical(_constructors, _Sentinel.constructorElement)) {
return _constructors;
}
if (isMixinApplication) {
// Assign to break a possible infinite recursion during computing.
_constructors = const <ConstructorElement>[];
return _constructors = _computeMixinAppConstructors();
}
var linkedData = this.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.readMembers(this);
return _constructors;
}
if (_constructors.isEmpty) {
var constructor = ConstructorElementImpl('', -1);
constructor.isSynthetic = true;
constructor.enclosingElement = this;
_constructors = <ConstructorElement>[constructor];
}
return _constructors;
}
/// Set the constructors contained in this class to the given [constructors].
///
/// Should only be used for class elements that are not mixin applications.
set constructors(List<ConstructorElement> constructors) {
assert(!isMixinApplication);
for (ConstructorElement constructor in constructors) {
(constructor as ConstructorElementImpl).enclosingElement = this;
}
_constructors = constructors;
}
@override
List<FieldElement> get fields {
if (!identical(_fields, _Sentinel.fieldElement)) {
return _fields;
}
var linkedData = this.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.readMembers(this);
return _fields;
}
return _fields;
}
@override
bool get hasNonFinalField {
List<ClassElement> classesToVisit = <ClassElement>[];
HashSet<ClassElement> visitedClasses = HashSet<ClassElement>();
classesToVisit.add(this);
while (classesToVisit.isNotEmpty) {
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) {
classesToVisit.add(supertype.element);
}
}
}
// 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);
var definingClass = method?.enclosingElement as ClassElement?;
return definingClass != null && !definingClass.isDartCoreObject;
}
@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 interfacesInternal {
linkedData?.read(this);
return _interfaces;
}
@override
bool get isAbstract {
return hasModifier(Modifier.ABSTRACT);
}
/// Set whether this class is abstract.
set isAbstract(bool isAbstract) {
setModifier(Modifier.ABSTRACT, isAbstract);
}
@override
bool get isDartCoreObject => !isMixin && supertype == null;
bool get isEnumLike {
// Must be a concrete class.
if (isAbstract || isMixin) {
return false;
}
// With only private non-factory constructors.
for (var constructor in constructors) {
if (constructor.isPublic || constructor.isFactory) {
return false;
}
}
// With 2+ static const fields with the type of this class.
var numberOfElements = 0;
for (var field in fields) {
if (field.isStatic && field.isConst && field.type == thisType) {
numberOfElements++;
}
}
if (numberOfElements < 2) {
return false;
}
// No subclasses in the library.
for (var unit in library.units) {
for (var class_ in unit.classes) {
if (class_.supertype?.element == this) {
return false;
}
}
}
return true;
}
bool get isMacro {
return hasModifier(Modifier.MACRO);
}
set isMacro(bool isMacro) {
setModifier(Modifier.MACRO, isMacro);
}
@override
bool get isMixinApplication {
return hasModifier(Modifier.MIXIN_APPLICATION);
}
/// Set whether this class is a mixin application.
set isMixinApplication(bool isMixinApplication) {
setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
}
@override
bool get isSimplyBounded {
return hasModifier(Modifier.SIMPLY_BOUNDED);
}
set isSimplyBounded(bool isSimplyBounded) {
setModifier(Modifier.SIMPLY_BOUNDED, isSimplyBounded);
}
@override
bool get isValidMixin {
final supertype = this.supertype;
if (supertype != null && !supertype.isDartCoreObject) {
return false;
}
for (ConstructorElement constructor in constructors) {
if (!constructor.isSynthetic && !constructor.isFactory) {
return false;
}
}
return true;
}
@override
ElementKind get kind => ElementKind.CLASS;
@override
List<ElementAnnotation> get metadata {
linkedData?.read(this);
return super.metadata;
}
@override
List<MethodElement> get methods {
if (!identical(_methods, _Sentinel.methodElement)) {
return _methods;
}
var linkedData = this.linkedData;
if (linkedData is ClassElementLinkedData) {
linkedData.readMembers(this);
return _methods;
}
return _methods;
}
/// Set the methods contained in this class to the given [methods].
set methods(List<MethodElement> methods) {
assert(!isMixinApplication);
for (MethodElement method in methods) {
(method as MethodElementImpl).enclosingElement = this;
}
_methods = methods;
}
@override
List<InterfaceType> get mixins {
linkedData?.read(this);
return super.mixins;
}
@override
String get name {
return super.name!;
}
/// 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 {
linkedData?.read(this);
return super.supertype;
}
@override
List<TypeParameterElement> get typeParameters {
linkedData?.read(this);
return super.typeParameters;
}
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeClassElement(this);
}
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
this.reference = reference;
reference.element = this;
this.linkedData = linkedData;
}
/// 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 cycles).
List<ConstructorElement> _computeMixinAppConstructors(
[List<ClassElementImpl>? visitedClasses]) {
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);
return <ConstructorElement>[];
}
var superElement = supertype!.element as ClassElementImpl;
// First get the list of constructors of the superclass which need to be
// forwarded to this class.
Iterable<ConstructorElement> constructorsToForward;
if (!superElement.isMixinApplication) {
final library = this.library;
constructorsToForward = superElement.constructors
.where((constructor) => constructor.isAccessibleIn(library))
.where((constructor) => !constructor.isFactory);
} 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 {
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`.
var superClassParameters = superElement.typeParameters;
List<DartType> argumentTypes = List<DartType>.filled(
superClassParameters.length, DynamicTypeImpl.instance);
for (int i = 0; i < supertype!.typeArguments.length; i++) {
if (i >= argumentTypes.length) {
break;
}
argumentTypes[i] = supertype!.typeArguments[i];
}
var substitution =
Substitution.fromPairs(superClassParameters, argumentTypes);
bool typeHasInstanceVariables(InterfaceType type) =>
type.element.fields.any((e) => !e.isSynthetic);
// Now create an implicit constructor for every constructor found above,
// substituting type parameters as appropriate.
return constructorsToForward
.map((ConstructorElement superclassConstructor) {
var name = superclassConstructor.name;
var implicitConstructor = ConstructorElementImpl(name, -1);
implicitConstructor.isSynthetic = true;
implicitConstructor.name = name;
implicitConstructor.nameOffset = -1;
var containerRef = reference!.getChild('@constructor');
var implicitReference = containerRef.getChild(name);
implicitConstructor.reference = implicitReference;
implicitReference.element = implicitConstructor;
var hasMixinWithInstanceVariables = mixins.any(typeHasInstanceVariables);
implicitConstructor.isConst =
superclassConstructor.isConst && !hasMixinWithInstanceVariables;
List<ParameterElement> superParameters = superclassConstructor.parameters;
int count = superParameters.length;
var argumentsForSuperInvocation = <Expression>[];
if (count > 0) {
var implicitParameters = <ParameterElement>[];
for (int i = 0; i < count; i++) {
ParameterElement superParameter = superParameters[i];
ParameterElementImpl implicitParameter;
if (superParameter is ConstVariableElement) {
var constVariable = superParameter as ConstVariableElement;
implicitParameter = DefaultParameterElementImpl(
name: superParameter.name,
nameOffset: -1,
// ignore: deprecated_member_use_from_same_package
parameterKind: superParameter.parameterKind,
)..constantInitializer = constVariable.constantInitializer;
} else {
implicitParameter = ParameterElementImpl(
name: superParameter.name,
nameOffset: -1,
// ignore: deprecated_member_use_from_same_package
parameterKind: superParameter.parameterKind,
);
}
implicitParameter.isConst = superParameter.isConst;
implicitParameter.isFinal = superParameter.isFinal;
implicitParameter.isSynthetic = true;
implicitParameter.type =
substitution.substituteType(superParameter.type);
implicitParameters.add(implicitParameter);
argumentsForSuperInvocation.add(
astFactory.simpleIdentifier(
StringToken(TokenType.STRING, implicitParameter.name, -1),
)
..staticElement = implicitParameter
..staticType = implicitParameter.type,
);
}
implicitConstructor.parameters = implicitParameters;
}
implicitConstructor.enclosingElement = this;
// TODO(scheglov) Why do we manually map parameters types above?
implicitConstructor.superConstructor =
ConstructorMember.from(superclassConstructor, supertype!);
var isNamed = superclassConstructor.name.isNotEmpty;
implicitConstructor.constantInitializers = [
astFactory.superConstructorInvocation(
Tokens.super_(),
isNamed ? Tokens.period() : null,
isNamed
? (astFactory.simpleIdentifier(
StringToken(TokenType.STRING, superclassConstructor.name, -1),
)..staticElement = superclassConstructor)
: null,
ArgumentListImpl(
leftParenthesis: Tokens.openParenthesis(),
arguments: argumentsForSuperInvocation,
rightParenthesis: Tokens.closeParenthesis(),
),
)..staticElement = superclassConstructor,
];
return implicitConstructor;
}).toList(growable: false);
}
}
/// A concrete implementation of a [CompilationUnitElement].
class CompilationUnitElementImpl extends UriReferencedElementImpl
implements CompilationUnitElement, MacroTargetElementContainer {
/// The source that corresponds to this compilation unit.
@override
final 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.
@override
final Source librarySource;
/// A list containing all of the top-level accessors (getters and setters)
/// contained in this compilation unit.
List<PropertyAccessorElement> _accessors = const [];
/// A list containing all of the classes contained in this compilation unit.
List<ClassElement> _classes = const [];
/// A list containing all of the enums contained in this compilation unit.
List<ClassElement> _enums = const [];
/// A list containing all of the extensions contained in this compilation
/// unit.
List<ExtensionElement> _extensions = const [];
/// A list containing all of the top-level functions contained in this
/// compilation unit.
List<FunctionElement> _functions = const [];
/// A list containing all of the mixins contained in this compilation unit.
List<ClassElement> _mixins = const [];
/// A list containing all of the type aliases contained in this compilation
/// unit.
List<TypeAliasElement> _typeAliases = const [];
/// A list containing all of the variables contained in this compilation unit.
List<TopLevelVariableElement> _variables = const [];
ElementLinkedData? linkedData;
/// Initialize a newly created compilation unit element to have the given
/// [name].
CompilationUnitElementImpl({
required this.source,
required this.librarySource,
required this.lineInfo,
}) : super(null, -1);
@override
List<PropertyAccessorElement> get accessors {
return _accessors;
}
/// Set the top-level accessors (getters and setters) contained in this
/// compilation unit to the given [accessors].
set accessors(List<PropertyAccessorElement> accessors) {
for (PropertyAccessorElement accessor in accessors) {
(accessor as PropertyAccessorElementImpl).enclosingElement = this;
}
_accessors = accessors;
}
@override
List<ClassElement> get classes {
return _classes;
}
/// Set the classes contained in this compilation unit to [classes].
set classes(List<ClassElement> classes) {
for (ClassElement class_ in classes) {
// 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 (class_ is ClassElementImpl) {
class_.enclosingElement = this;
}
}
_classes = classes;
}
@override
LibraryElement get enclosingElement =>
super.enclosingElement as LibraryElement;
@override
CompilationUnitElementImpl get enclosingUnit {
return this;
}
@override
List<ClassElement> get enums {
return _enums;
}
/// Set the enums contained in this compilation unit to the given [enums].
set enums(List<ClassElement> enums) {
for (ClassElement enumDeclaration in enums) {
(enumDeclaration as EnumElementImpl).enclosingElement = this;
}
_enums = enums;
}
@override
List<ExtensionElement> get extensions {
return _extensions;
}
/// Set the extensions contained in this compilation unit to the given
/// [extensions].
set extensions(List<ExtensionElement> extensions) {
for (ExtensionElement extension in extensions) {
(extension as ExtensionElementImpl).enclosingElement = this;
}
_extensions = extensions;
}
@override
List<FunctionElement> get functions {
return _functions;
}
/// Set the top-level functions contained in this compilation unit to the
/// given[functions].
set functions(List<FunctionElement> functions) {
for (FunctionElement function in functions) {
(function as FunctionElementImpl).enclosingElement = this;
}
_functions = functions;
}
@override
int get hashCode => source.hashCode;
@override
String get identifier => '${source.uri}';
@override
ElementKind get kind => ElementKind.COMPILATION_UNIT;
@override
List<ElementAnnotation> get metadata {
linkedData?.read(this);
return super.metadata;
}
@override
List<ClassElement> get mixins {
return _mixins;
}
/// Set the mixins contained in this compilation unit to the given [mixins].
set mixins(List<ClassElement> mixins) {
for (var type in mixins) {
(type as MixinElementImpl).enclosingElement = this;
}
_mixins = mixins;
}
@override
AnalysisSession get session => enclosingElement.session;
@override
List<TopLevelVariableElement> get topLevelVariables {
return _variables;
}
/// Set the top-level variables contained in this compilation unit to the
/// given[variables].
set topLevelVariables(List<TopLevelVariableElement> variables) {
for (TopLevelVariableElement field in variables) {
(field as TopLevelVariableElementImpl).enclosingElement = this;
}
_variables = variables;
}
@override
List<TypeAliasElement> get typeAliases {
return _typeAliases;
}
/// Set the type aliases contained in this compilation unit to [typeAliases].
set typeAliases(List<TypeAliasElement> typeAliases) {
for (var typeAlias in typeAliases) {
(typeAlias as ElementImpl).enclosingElement = this;
}
_typeAliases = typeAliases;
}
@override
TypeParameterizedElementMixin? get typeParameterContext => null;
@override
bool operator ==(Object other) =>
other is CompilationUnitElementImpl && source == other.source;
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitCompilationUnitElement(this);
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeCompilationUnitElement(this);
}
@override
ClassElement? getEnum(String enumName) {
for (ClassElement enumDeclaration in enums) {
if (enumDeclaration.name == enumName) {
return enumDeclaration;
}
}
return null;
}
@override
ClassElement? getType(String className) {
for (ClassElement class_ in classes) {
if (class_.name == className) {
return class_;
}
}
return null;
}
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
this.reference = reference;
reference.element = this;
this.linkedData = linkedData;
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(accessors, visitor);
safelyVisitChildren(classes, visitor);
safelyVisitChildren(enums, visitor);
safelyVisitChildren(extensions, visitor);
safelyVisitChildren(functions, visitor);
safelyVisitChildren(mixins, visitor);
safelyVisitChildren(typeAliases, visitor);
safelyVisitChildren(topLevelVariables, visitor);
}
}
/// 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);
@override
Expression? get constantInitializer {
linkedData?.read(this);
return super.constantInitializer;
}
}
/// 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);
}
/// A concrete implementation of a [ConstructorElement].
class ConstructorElementImpl extends ExecutableElementImpl
with ConstructorElementMixin
implements ConstructorElement {
/// The super-constructor which this constructor is invoking, or `null` if
/// this constructor is not generative, or is redirecting, or the
/// super-constructor is not resolved, or the enclosing class is `Object`.
///
/// TODO(scheglov) We cannot have both super and redirecting constructors.
/// So, ideally we should have some kind of "either" or "variant" here.
ConstructorElement? _superConstructor;
/// 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 = const [];
@override
int? periodOffset;
@override
int? nameEnd;
/// For every constructor we initially set this flag to `true`, and then
/// set it to `false` during computing constant values if we detect that it
/// is a part of a cycle.
bool isCycleFree = true;
@override
bool isConstantEvaluated = false;
/// Initialize a newly created constructor element to have the given [name]
/// and [offset].
ConstructorElementImpl(String name, int offset) : super(name, offset);
/// 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 {
linkedData?.read(this);
return _constantInitializers;
}
set constantInitializers(List<ConstructorInitializer> constantInitializers) {
_constantInitializers = constantInitializers;
}
@override
ConstructorElement get declaration => this;
@override
String get displayName {
var className = enclosingElement.name;
var name = this.name;
if (name.isNotEmpty) {
return '$className.$name';
} else {
return className;
}
}
@override
AbstractClassElementImpl get enclosingElement =>
super.enclosingElement as AbstractClassElementImpl;
@override
bool get isConst {
return hasModifier(Modifier.CONST);
}
/// Set whether this constructor represents a 'const' constructor.
set isConst(bool isConst) {
setModifier(Modifier.CONST, isConst);
}
@override
bool get isFactory {
return hasModifier(Modifier.FACTORY);
}
/// Set whether this constructor represents a factory method.
set isFactory(bool isFactory) {
setModifier(Modifier.FACTORY, isFactory);
}
@override
ElementKind get kind => ElementKind.CONSTRUCTOR;
@override
int get nameLength {
final nameEnd = this.nameEnd;
if (nameEnd == null) {
return 0;
} else {
return nameEnd - nameOffset;
}
}
@override
Element get nonSynthetic {
return isSynthetic ? enclosingElement : this;
}
@override
ConstructorElement? get redirectedConstructor {
linkedData?.read(this);
return _redirectedConstructor;
}
set redirectedConstructor(ConstructorElement? redirectedConstructor) {
_redirectedConstructor = redirectedConstructor;
}
@override
InterfaceType get returnType =>
ElementTypeProvider.current.getExecutableReturnType(this)
as InterfaceType;
@override
set returnType(DartType returnType) {
assert(false);
}
@override
InterfaceType get returnTypeInternal {
return (_returnType ??= enclosingElement.thisType) as InterfaceType;
}
ConstructorElement? get superConstructor {
linkedData?.read(this);
return _superConstructor;
}
set superConstructor(ConstructorElement? superConstructor) {
_superConstructor = superConstructor;
}
@override
FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
@override
set type(FunctionType type) {
assert(false);
}
@override
FunctionType get typeInternal {
// TODO(scheglov) Remove "element" in the breaking changes branch.
return _type ??= FunctionTypeImpl(
typeFormals: typeParameters,
parameters: parameters,
returnType: returnType,
nullabilitySuffix: _noneOrStarSuffix,
);
}
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitConstructorElement(this);
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeConstructorElement(this);
}
/// Ensures that dependencies of this constructor, such as default values
/// of formal parameters, are evaluated.
void computeConstantDependencies() {
if (!isConstantEvaluated) {
computeConstants(context.declaredVariables, [this], library.featureSet);
}
}
}
/// Common implementation for methods defined in [ConstructorElement].
mixin ConstructorElementMixin implements ConstructorElement {
@override
bool get isDefaultConstructor {
// unnamed
if (name.isNotEmpty) {
return false;
}
// no required parameters
for (ParameterElement parameter in parameters) {
if (parameter.isRequired) {
return false;
}
}
// OK, can be used as default constructor
return true;
}
@override
bool get isGenerative {
return !isFactory;
}
}
/// 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);
@override
Expression? get constantInitializer {
linkedData?.read(this);
return super.constantInitializer;
}
}
/// Mixin used by elements that represent constant variables and have
/// initializers.
///
/// Note that in correct Dart code, all constant variables must have
/// initializers. However, analyzer also needs to handle incorrect Dart code,
/// in which case there might be some constant variables that lack initializers.
/// This interface is only used for constant variables that have initializers.
///
/// This class is not intended to be part of the public API for analyzer.
mixin ConstVariableElement implements ElementImpl, ConstantEvaluationTarget {
/// If this element represents a constant variable, and it has an initializer,
/// a copy of the initializer for the constant. Otherwise `null`.
///
/// Note that in correct Dart code, all constant variables must have
/// initializers. However, analyzer also needs to handle incorrect Dart code,
/// in which case there might be some constant variables that lack
/// initializers.
Expression? constantInitializer;
EvaluationResultImpl? _evaluationResult;
EvaluationResultImpl? get evaluationResult => _evaluationResult;
set evaluationResult(EvaluationResultImpl? evaluationResult) {
_evaluationResult = evaluationResult;
}
@override
bool get isConstantEvaluated => _evaluationResult != null;
/// 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) {
final library = this.library;
// TODO(scheglov) https://github.com/dart-lang/sdk/issues/47915
if (library == null) {
throw StateError(
'[library: null][this: ($runtimeType) $this]'
'[enclosingElement: $enclosingElement]'
'[reference: $reference]',
);
}
computeConstants(context.declaredVariables, [this], library.featureSet);
}
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({
required String name,
required int nameOffset,
required ParameterKind parameterKind,
}) : super(
name: name,
nameOffset: nameOffset,
parameterKind: parameterKind,
);
@override
String? get defaultValueCode {
return constantInitializer?.toSource();
}
}
/// 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({
required String? name,
required int nameOffset,
required ParameterKind parameterKind,
}) : super(
name: name,
nameOffset: nameOffset,
parameterKind: parameterKind,
);
@override
String? get defaultValueCode {
return constantInitializer?.toSource();
}
}
class DefaultSuperFormalParameterElementImpl
extends SuperFormalParameterElementImpl with ConstVariableElement {
/// Initialize a newly created parameter element to have the given [name] and
/// [nameOffset].
DefaultSuperFormalParameterElementImpl({
required String name,
required int nameOffset,
required ParameterKind parameterKind,
}) : super(
name: name,
nameOffset: nameOffset,
parameterKind: parameterKind,
);
@override
String? get defaultValueCode {
final constantInitializer = this.constantInitializer;
if (constantInitializer != null) {
return constantInitializer.toSource();
}
if (_superConstructorParameterDefaultValue != null) {
return superConstructorParameter?.defaultValueCode;
}
return null;
}
@override
EvaluationResultImpl? get evaluationResult {
if (constantInitializer != null) {
return super.evaluationResult;
}
var superConstructorParameter = this.superConstructorParameter?.declaration;
if (superConstructorParameter is ParameterElementImpl) {
return superConstructorParameter.evaluationResult;
}
return null;
}
DartObject? get _superConstructorParameterDefaultValue {
var superDefault = superConstructorParameter?.computeConstantValue();
var superDefaultType = superDefault?.type;
var libraryElement = library;
if (superDefaultType != null &&
libraryElement != null &&
libraryElement.typeSystem.isSubtypeOf(superDefaultType, type)) {
return superDefault;
}
return null;
}
@override
DartObject? computeConstantValue() {
if (constantInitializer != null) {
return super.computeConstantValue();
}
return _superConstructorParameterDefaultValue;
}
}
/// 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;
/// Initialize a newly created instance of this class. Instances of this class
/// should <b>not</b> be created except as part of creating the type
/// associated with this element. The single instance of this class should be
/// accessed through the method [instance].
DynamicElementImpl() : super(Keyword.DYNAMIC.lexeme, -1) {
setModifier(Modifier.SYNTHETIC, true);
}
@override
ElementKind get kind => ElementKind.DYNAMIC;
@override
T? accept<T>(ElementVisitor<T> visitor) => null;
}
/// A concrete implementation of an [ElementAnnotation].
class ElementAnnotationImpl implements ElementAnnotation {
/// The name of the top-level variable used to mark that a function always
/// throws, for dead code purposes.
static const String _ALWAYS_THROWS_VARIABLE_NAME = "alwaysThrows";
/// The name of the class used to mark an element as being deprecated.
static const String _DEPRECATED_CLASS_NAME = "Deprecated";
/// The name of the top-level variable used to mark an element as being
/// deprecated.
static const String _DEPRECATED_VARIABLE_NAME = "deprecated";
/// The name of the top-level variable used to mark an element as not to be
/// stored.
static const String _DO_NOT_STORE_VARIABLE_NAME = "doNotStore";
/// The name of the top-level variable used to mark a method as being a
/// factory.
static const String _FACTORY_VARIABLE_NAME = "factory";
/// The name of the top-level variable used to mark a class and its subclasses
/// as being immutable.
static const String _IMMUTABLE_VARIABLE_NAME = "immutable";
/// The name of the top-level variable used to mark an element as being
/// internal to its package.
static const String _INTERNAL_VARIABLE_NAME = "internal";
/// The name of the top-level variable used to mark a constructor as being
/// literal.
static const String _LITERAL_VARIABLE_NAME = "literal";
/// The name of the top-level variable used to mark a type as having
/// "optional" type arguments.
static const String _OPTIONAL_TYPE_ARGS_VARIABLE_NAME = "optionalTypeArgs";
/// The name of the top-level variable used to mark a function as running
/// a single test.
static const String _IS_TEST_VARIABLE_NAME = "isTest";
/// The name of the top-level variable used to mark a function as running
/// a test group.
static const String _IS_TEST_GROUP_VARIABLE_NAME = "isTestGroup";
/// The name of the class used to JS annotate an element.
static const String _JS_CLASS_NAME = "JS";
/// The name of `js` library, used to define JS annotations.
static const String _JS_LIB_NAME = "js";
/// The name of `meta` library, used to define analysis annotations.
static const String _META_LIB_NAME = "meta";
/// The name of `meta_meta` library, used to define annotations for other
/// annotations.
static const String _META_META_LIB_NAME = "meta_meta";
/// The name of the top-level variable used to mark a method as requiring
/// overriders to call super.
static const String _MUST_CALL_SUPER_VARIABLE_NAME = "mustCallSuper";
/// The name of `angular.meta` library, used to define angular analysis
/// annotations.
static const String _NG_META_LIB_NAME = "angular.meta";
/// The name of the top-level variable used to mark a member as being nonVirtual.
static const String _NON_VIRTUAL_VARIABLE_NAME = "nonVirtual";
/// The name of the top-level variable used to mark a method as being expected
/// to override an inherited method.
static const String _OVERRIDE_VARIABLE_NAME = "override";
/// The name of the top-level variable used to mark a method as being
/// protected.
static const String _PROTECTED_VARIABLE_NAME = "protected";
/// The name of the top-level variable used to mark a class as implementing a
/// proxy object.
static const String PROXY_VARIABLE_NAME = "proxy";
/// The name of the class used to mark a parameter as being required.
static const String _REQUIRED_CLASS_NAME = "Required";
/// The name of the top-level variable used to mark a parameter as being
/// required.
static const String _REQUIRED_VARIABLE_NAME = "required";
/// The name of the top-level variable used to mark a class as being sealed.
static const String _SEALED_VARIABLE_NAME = "sealed";
/// The name of the class used to annotate a class as an annotation with a
/// specific set of target element kinds.
static const String _TARGET_CLASS_NAME = 'Target';
/// The name of the class used to mark a returned element as requiring use.
static const String _USE_RESULT_CLASS_NAME = "UseResult";
/// The name of the top-level variable used to mark a returned element as
/// requiring use.
static const String _USE_RESULT_VARIABLE_NAME = "useResult";
/// The name of the top-level variable used to mark a member as being visible
/// for overriding only.
static const String _VISIBLE_FOR_OVERRIDING_NAME = 'visibleForOverriding';
/// The name of the top-level variable used to mark a method as being
/// visible for templates.
static const 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 const String _VISIBLE_FOR_TESTING_VARIABLE_NAME = "visibleForTesting";
@override
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.
late Annotation annotationAst;
/// The result of evaluating this annotation as a compile-time constant
/// expression, or `null` if the compilation unit containing the variable has
/// not been resolved.
EvaluationResultImpl? evaluationResult;
/// Initialize a newly created annotation. The given [compilationUnit] is the
/// compilation unit in which the annotation appears.
ElementAnnotationImpl(this.compilationUnit);
@override
List<AnalysisError> get constantEvaluationErrors =>
evaluationResult?.errors ?? const <AnalysisError>[];
@override
AnalysisContext get context => compilationUnit.library.context;
@override
bool get isAlwaysThrows => _isPackageMetaGetter(_ALWAYS_THROWS_VARIABLE_NAME);
@override
bool get isConstantEvaluated => evaluationResult != null;
@override
bool get isDeprecated {
final element = this.element;
if (element is ConstructorElement) {
return element.library.isDartCore &&
element.enclosingElement.name == _DEPRECATED_CLASS_NAME;
} else if (element is PropertyAccessorElement) {
return element.library.isDartCore &&
element.name == _DEPRECATED_VARIABLE_NAME;
}
return false;
}
@override
bool get isDoNotStore => _isPackageMetaGetter(_DO_NOT_STORE_VARIABLE_NAME);
@override
bool get isFactory => _isPackageMetaGetter(_FACTORY_VARIABLE_NAME);
@override
bool get isImmutable => _isPackageMetaGetter(_IMMUTABLE_VARIABLE_NAME);
@override
bool get isInternal => _isPackageMetaGetter(_INTERNAL_VARIABLE_NAME);
@override
bool get isIsTest => _isPackageMetaGetter(_IS_TEST_VARIABLE_NAME);
@override
bool get isIsTestGroup => _isPackageMetaGetter(_IS_TEST_GROUP_VARIABLE_NAME);
@override
bool get isJS =>
_isConstructor(libraryName: _JS_LIB_NAME, className: _JS_CLASS_NAME);
@override
bool get isLiteral => _isPackageMetaGetter(_LITERAL_VARIABLE_NAME);
@override
bool get isMustCallSuper =>
_isPackageMetaGetter(_MUST_CALL_SUPER_VARIABLE_NAME);
@override
bool get isNonVirtual => _isPackageMetaGetter(_NON_VIRTUAL_VARIABLE_NAME);
@override
bool get isOptionalTypeArgs =>
_isPackageMetaGetter(_OPTIONAL_TYPE_ARGS_VARIABLE_NAME);
@override
bool get isOverride => _isDartCoreGetter(_OVERRIDE_VARIABLE_NAME);
/// Return `true` if this is an annotation of the form
/// `@pragma("vm:entry-point")`.
bool get isPragmaVmEntryPoint {
if (_isConstructor(libraryName: 'dart.core', className: 'pragma')) {
var value = computeConstantValue();
var nameValue = value?.getField('name');
return nameValue?.toStringValue() == 'vm:entry-point';
}
return false;
}
@override
bool get isProtected => _isPackageMetaGetter(_PROTECTED_VARIABLE_NAME);
@override
bool get isProxy => _isDartCoreGetter(PROXY_VARIABLE_NAME);
@override
bool get isRequired =>
_isConstructor(
libraryName: _META_LIB_NAME, className: _REQUIRED_CLASS_NAME) ||
_isPackageMetaGetter(_REQUIRED_VARIABLE_NAME);
@override
bool get isSealed => _isPackageMetaGetter(_SEALED_VARIABLE_NAME);
@override
bool get isTarget => _isConstructor(
libraryName: _META_META_LIB_NAME, className: _TARGET_CLASS_NAME);
@override
bool get isUseResult =>
_isConstructor(
libraryName: _META_LIB_NAME, className: _USE_RESULT_CLASS_NAME) ||
_isPackageMetaGetter(_USE_RESULT_VARIABLE_NAME);
@override
bool get isVisibleForOverriding =>
_isPackageMetaGetter(_VISIBLE_FOR_OVERRIDING_NAME);
@override
bool get isVisibleForTemplate => _isTopGetter(
libraryName: _NG_META_LIB_NAME,
name: _VISIBLE_FOR_TEMPLATE_VARIABLE_NAME);
@override
bool get isVisibleForTesting =>
_isPackageMetaGetter(_VISIBLE_FOR_TESTING_VARIABLE_NAME);
@override
LibraryElement get library => compilationUnit.library;
/// Get the library containing this annotation.
@override
Source get librarySource => compilationUnit.librarySource;
@override
Source get source => compilationUnit.source;
@override
DartObject? computeConstantValue() {
if (evaluationResult == null) {
computeConstants(context.declaredVariables, [this],
compilationUnit.library.featureSet);
}
return evaluationResult?.value;
}
@override
String toSource() => annotationAst.toSource();
@override
String toString() => '@$element';
bool _isConstructor({
required String libraryName,
required String className,
}) {
final element = this.element;
return element is ConstructorElement &&
element.enclosingElement.name == className &&
element.library.name == libraryName;
}
bool _isDartCoreGetter(String name) {
return _isTopGetter(
libraryName: 'dart.core',
name: name,
);
}
bool _isPackageMetaGetter(String name) {
return _isTopGetter(
libraryName: _META_LIB_NAME,
name: name,
);
}
bool _isTopGetter({
required String libraryName,
required String name,
}) {
final element = this.element;
return element is PropertyAccessorElement &&
element.name == name &&
element.library.name == libraryName;
}
}
/// A base class for concrete implementations of an [Element].
abstract class ElementImpl implements Element {
static const _metadataFlag_isReady = 1 << 0;
static const _metadataFlag_hasDeprecated = 1 << 1;
static const _metadataFlag_hasOverride = 1 << 2;
/// An Unicode right arrow.
@deprecated
static final String RIGHT_ARROW = " \u2192 ";
static int _NEXT_ID = 0;
@override
final int id = _NEXT_ID++;
/// The enclosing element of this element, or `null` if this element is at the
/// root of the element structure.
ElementImpl? _enclosingElement;
Reference? reference;
/// 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 = const [];
/// Cached flags denoting presence of specific annotations in [_metadata].
int _metadataFlags = 0;
/// 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(this._name, this._nameOffset, {this.reference}) {
reference?.element = this;
}
/// 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 {
return _enclosingElement!.context;
}
@override
Element get declaration => this;
@override
String get displayName => _name ?? '';
@override
String? get documentationComment => _docComment;
/// The documentation comment source for this element.
set documentationComment(String? doc) {
_docComment = doc;
}
@override
Element? get enclosingElement => _enclosingElement;
/// Set the enclosing element of this element to the given [element].
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 {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isAlwaysThrows) {
return true;
}
}
return false;
}
@override
bool get hasDeprecated {
return (_getMetadataFlags() & _metadataFlag_hasDeprecated) != 0;
}
@override
bool get hasDoNotStore {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isDoNotStore) {
return true;
}
}
return false;
}
@override
bool get hasFactory {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isFactory) {
return true;
}
}
return false;
}
@override
int get hashCode {
// TODO: We might want to re-visit this optimization in the future.
// We cache the hash code value as this is a very frequently called method.
return _cachedHashCode ??= location.hashCode;
}
@override
bool get hasInternal {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isInternal) {
return true;
}
}
return false;
}
@override
bool get hasIsTest {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isIsTest) {
return true;
}
}
return false;
}
@override
bool get hasIsTestGroup {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isIsTestGroup) {
return true;
}
}
return false;
}
@override
bool get hasJS {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isJS) {
return true;
}
}
return false;
}
@override
bool get hasLiteral {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isLiteral) {
return true;
}
}
return false;
}
@override
bool get hasMustCallSuper {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isMustCallSuper) {
return true;
}
}
return false;
}
@override
bool get hasNonVirtual {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isNonVirtual) {
return true;
}
}
return false;
}
@override
bool get hasOptionalTypeArgs {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isOptionalTypeArgs) {
return true;
}
}
return false;
}
@override
bool get hasOverride {
return (_getMetadataFlags() & _metadataFlag_hasOverride) != 0;
}
/// Return `true` if this element has an annotation of the form
/// `@pragma("vm:entry-point")`.
bool get hasPragmaVmEntryPoint {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation is ElementAnnotationImpl &&
annotation.isPragmaVmEntryPoint) {
return true;
}
}
return false;
}
@override
bool get hasProtected {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isProtected) {
return true;
}
}
return false;
}
@override
bool get hasRequired {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isRequired) {
return true;
}
}
return false;
}
@override
bool get hasSealed {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isSealed) {
return true;
}
}
return false;
}
@override
bool get hasUseResult {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isUseResult) {
return true;
}
}
return false;
}
@override
bool get hasVisibleForOverriding {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isVisibleForOverriding) {
return true;
}
}
return false;
}
@override
bool get hasVisibleForTemplate {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isVisibleForTemplate) {
return true;
}
}
return false;
}
@override
bool get hasVisibleForTesting {
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isVisibleForTesting) {
return true;
}
}
return false;
}
/// Return an identifier that uniquely identifies this element among the
/// children of this element's parent.
String get identifier => name!;
bool get isNonFunctionTypeAliasesEnabled {
return library!.featureSet.isEnabled(Feature.nonfunction_type_aliases);
}
@override
bool get isPrivate {
final name = this.name;
if (name == null) {
return true;
}
return Identifier.isPrivateName(name);
}
@override
bool get isPublic => !isPrivate;
@override
bool get isSynthetic {
return hasModifier(Modifier.SYNTHETIC);
}
/// Set whether this element is synthetic.
set isSynthetic(bool isSynthetic) {
setModifier(Modifier.SYNTHETIC, isSynthetic);
}
bool get isTempAugmentation {
return hasModifier(Modifier.TEMP_AUGMENTATION);
}
set isTempAugmentation(bool value) {
setModifier(Modifier.TEMP_AUGMENTATION, value);
}
@override
LibraryElementImpl? get library => thisOrAncestorOfType();
@override
Source? get librarySource => library?.source;
@override
ElementLocation get location {
return _cachedLocation ??= ElementLocationImpl.con1(this);
}
@override
List<ElementAnnotation> get metadata {
return _metadata;
}
set metadata(List<ElementAnnotation> metadata) {
_metadata = metadata;
}
@override
String? get name => _name;
/// Changes the name of this element.
set name(String? name) {
_name = name;
}
@override
int get nameLength => displayName.length;
@override
int get nameOffset => _nameOffset;
/// Sets the offset of the name of this element in the file that contains the
/// declaration of this element.
set nameOffset(int offset) {
_nameOffset = offset;
}
@override
Element get nonSynthetic => this;
@override
AnalysisSession? get session {
return enclosingElement?.session;
}
@override
Source? get source {
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;
}
NullabilitySuffix get _noneOrStarSuffix {
return library!.isNonNullableByDefault == true
? NullabilitySuffix.none
: NullabilitySuffix.star;
}
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
return other is Element && other.kind == kind && other.location == location;
}
/// Append a textual representation of this element to the given [builder].
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeAbstractElement(this);
}
/// 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
String getDisplayString({
required bool withNullability,
bool multiline = false,
}) {
var builder = ElementDisplayStringBuilder(
skipAllDynamicArguments: false,
withNullability: withNullability,
multiline: multiline,
);
appendTo(builder);
return builder.toString();
}
@override
String getExtendedDisplayName(String? shortName) {
shortName ??= displayName;
final source = this.source;
return "$shortName (${source?.fullName})";
}
/// 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) {
for (Element child in children) {
child.accept(visitor);
}
}
/// Set the code range for this element.
void setCodeRange(int offset, int length) {
_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
E thisOrAncestorMatching<E extends Element>(
bool Function(Element) predicate,
) {
Element? element = this;
while (element != null && !predicate(element)) {
element = element.enclosingElement;
}
return element as E;
}
@override
E? thisOrAncestorOfType<E extends Element>() {
Element? element = this;
while (element != null && element is! E) {
element = element.enclosingElement;
}
return element as E?;
}
@override
String toString() {
return getDisplayString(withNullability: true);
}
@override
void visitChildren(ElementVisitor visitor) {
// There are no children to visit
}
/// Return flags that denote presence of a few specific annotations.
int _getMetadataFlags() {
var result = _metadataFlags;
// Has at least `_metadataFlag_isReady`.
if (result != 0) {
return result;
}
final metadata = this.metadata;
for (var i = 0; i < metadata.length; i++) {
var annotation = metadata[i];
if (annotation.isDeprecated) {
result |= _metadataFlag_hasDeprecated;
} else if (annotation.isOverride) {
result |= _metadataFlag_hasOverride;
}
}
result |= _metadataFlag_isReady;
return _metadataFlags = result;
}
}
/// Abstract base class for elements whose type is guaranteed to be a function
/// type.
abstract class ElementImplWithFunctionType implements Element {
/// Gets the element's return type, without going through the indirection of
/// [ElementTypeProvider].
///
/// In most cases, the element's `returnType` getter should be used instead.
DartType get returnTypeInternal;
/// Gets the element's type, without going through the indirection of
/// [ElementTypeProvider].
///
/// In most cases, the element's `type` getter should be used instead.
FunctionType get typeInternal;
}
/// A concrete implementation of an [ElementLocation].
class ElementLocationImpl implements ElementLocation {
/// The character used to separate components in the encoded form.
static const int _SEPARATOR_CHAR = 0x3B;
/// The path to the element whose location is represented by this object.
late final 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 = <String>[];
Element? ancestor = element;
while (ancestor != null) {
components.insert(0, (ancestor as ElementImpl).identifier);
ancestor = ancestor.enclosingElement;
}
_components = components;
}
/// Initialize a newly created location from the given [encoding].
ElementLocationImpl.con2(String encoding) {
_components = _decode(encoding);
}
/// Initialize a newly created location from the given [components].
ElementLocationImpl.con3(List<String> components) {
_components = components;
}
@override
List<String> get components => _components;
@override
String get encoding {
StringBuffer buffer = 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 => Object.hashAll(_components);
@override
bool operator ==(Object other) {
if (identical(this, other)) {
return true;
}
if (other is ElementLocationImpl) {
List<String> otherComponents = other._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 = <String>[];
StringBuffer buffer = 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 = 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 {
ElementLinkedData? linkedData;
List<ConstructorElement> _constructors = _Sentinel.constructorElement;
/// 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) : super(name, offset);
@override
List<PropertyAccessorElement> get accessors {
return _accessors;
}
List<FieldElement> get constants {
return fields.where((field) => field.isEnumConstant).toList();
}
@override
List<ConstructorElement> get constructors {
return _constructors;
}
set constructors(List<ConstructorElement> constructors) {
for (var constructor in constructors) {
(constructor as ConstructorElementImpl).enclosingElement = this;
}
_constructors = constructors;
}
@override
List<FieldElement> get fields {
return _fields;
}
@override
bool get hasNonFinalField => false;
@override
bool get hasStaticMember => true;
@override
bool get isAbstract => false;
@override
bool get isEnum => true;
@override
bool get isMixinApplication => false;
@override
bool get isSimplyBounded {
return hasModifier(Modifier.SIMPLY_BOUNDED);
}
set isSimplyBounded(bool isSimplyBounded) {
setModifier(Modifier.SIMPLY_BOUNDED, isSimplyBounded);
}
@override
bool get isValidMixin => false;
@override
ElementKind get kind => ElementKind.ENUM;
@override
List<ElementAnnotation> get metadata {
linkedData?.read(this);
return super.metadata;
}
@override
List<MethodElement> get methods {
return _methods;
}
/// Set the methods contained in this class to the given [methods].
set methods(List<MethodElement> methods) {
for (MethodElement method in methods) {
(method as MethodElementImpl).enclosingElement = this;
}
_methods = methods;
}
@override
String get name {
return super.name!;
}
@override
InterfaceType? get supertype {
linkedData?.read(this);
return super.supertype;
}
@override
List<TypeParameterElement> get typeParameters {
linkedData?.read(this);
return super.typeParameters;
}
ConstFieldElementImpl? get valuesField {
for (var field in fields) {
if (field is ConstFieldElementImpl &&
field.name == 'values' &&
field.isSyntheticEnumField) {
return field;
}
}
return null;
}
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeEnumElement(this);
}
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
this.reference = reference;
reference.element = this;
this.linkedData = linkedData;
}
}
/// A base class for concrete implementations of an [ExecutableElement].
abstract class ExecutableElementImpl extends _ExistingElementImpl
with TypeParameterizedElementMixin, HasCompletionData
implements ExecutableElement, ElementImplWithFunctionType {
/// A list containing all of the parameters defined by this executable
/// element.
List<ParameterElement> _parameters = const [];
/// The inferred return type of this executable element.
DartType? _returnType;
/// The type of function defined by this executable element.
FunctionType? _type;
ElementLinkedData? linkedData;
/// Initialize a newly created executable element to have the given [name] and
/// [offset].
ExecutableElementImpl(String name, int offset, {Reference? reference})
: super(name, offset, reference: reference);
@override
Element get enclosingElement => super.enclosingElement!;
@override
bool get hasImplicitReturnType {
return hasModifier(Modifier.IMPLICIT_TYPE);
}
/// Set whether this executable element has an implicit return type.
set hasImplicitReturnType(bool hasImplicitReturnType) {
setModifier(Modifier.IMPLICIT_TYPE, hasImplicitReturnType);
}
bool get invokesSuperSelf {
return hasModifier(Modifier.INVOKES_SUPER_SELF);
}
set invokesSuperSelf(bool value) {
setModifier(Modifier.INVOKES_SUPER_SELF, value);
}
@override
bool get isAbstract {
return hasModifier(Modifier.ABSTRACT);
}
@override
bool get isAsynchronous {
return hasModifier(Modifier.ASYNCHRONOUS);
}
/// Set whether this executable element's body is asynchronous.
set isAsynchronous(bool isAsynchronous) {
setModifier(Modifier.ASYNCHRONOUS, isAsynchronous);
}
@override
bool get isExternal {
return hasModifier(Modifier.EXTERNAL);
}
/// Set whether this executable element is external.
set isExternal(bool isExternal) {
setModifier(Modifier.EXTERNAL, isExternal);
}
@override
bool get isGenerator {
return hasModifier(Modifier.GENERATOR);
}
/// Set whether this method's body is a generator.
set isGenerator(bool isGenerator) {
setModifier(Modifier.GENERATOR, isGenerator);
}
@override
bool get isOperator => false;
@override
bool get isStatic {
return hasModifier(Modifier.STATIC);
}
set isStatic(bool isStatic) {
setModifier(Modifier.STATIC, isStatic);
}
@override
bool get isSynchronous => !isAsynchronous;
@override
List<ElementAnnotation> get metadata {
linkedData?.read(this);
return super.metadata;
}
@override
String get name {
return super.name!;
}
@override
List<ParameterElement> get parameters =>
ElementTypeProvider.current.getExecutableParameters(this);
/// Set the parameters defined by this executable element to the given
/// [parameters].
set parameters(List<ParameterElement> parameters) {
for (ParameterElement parameter in parameters) {
(parameter as ParameterElementImpl).enclosingElement = this;
}
_parameters = parameters;
}
List<ParameterElement> get parameters_unresolved {
return _parameters;
}
/// Gets the element's parameters, without going through the indirection of
/// [ElementTypeProvider].
///
/// In most cases, the [parameters] getter should be used instead.
List<ParameterElement> get parametersInternal {
linkedData?.read(this);
return _parameters;
}
@override
DartType get returnType =>
ElementTypeProvider.current.getExecutableReturnType(this);
set returnType(DartType returnType) {
_returnType = returnType;
// We do this because of return type inference. At the moment when we
// create a local function element we don't know yet its return type,
// because we have not done static type analysis yet.
// It somewhere it between we access the type of this element, so it gets
// cached in the element. When we are done static type analysis, we then
// should clear this cached type to make it right.
// TODO(scheglov) Remove when type analysis is done in the single pass.
_type = null;
}
@override
DartType get returnTypeInternal {
linkedData?.read(this);
return _returnType!;
}
@override
FunctionType get type => ElementTypeProvider.current.getExecutableType(this);
set type(FunctionType type) {
_type = type;
}
@override
FunctionType get typeInternal {
if (_type != null) return _type!;
return _type = FunctionTypeImpl(
typeFormals: typeParameters,
parameters: parameters,
returnType: returnType,
nullabilitySuffix: _noneOrStarSuffix,
);
}
/// Set the type parameters defined by this executable element to the given
/// [typeParameters].
set typeParameters(List<TypeParameterElement> typeParameters) {
for (TypeParameterElement parameter in typeParameters) {
(parameter as TypeParameterElementImpl).enclosingElement = this;
}
_typeParameterElements = typeParameters;
}
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeExecutableElement(this, displayName);
}
void setLinkedData(Reference reference, ElementLinkedData linkedData) {
this.reference = reference;
reference.element = this;
this.linkedData = linkedData;
}
@override
void visitChildren(ElementVisitor visitor) {
super.visitChildren(visitor);
safelyVisitChildren(typeParameters, visitor);
safelyVisitChildren(parameters, visitor);
}
}
/// A concrete implementation of an [ExportElement].
class ExportElementImpl extends UriReferencedElementImpl
implements ExportElement {
@override
LibraryElement? exportedLibrary;
@override
List<NamespaceCombinator> combinators = const [];
/// Initialize a newly created export element at the given [offset].
ExportElementImpl(int offset) : super(null, offset);
@override
CompilationUnitElementImpl get enclosingUnit {
var enclosingLibrary = enclosingElement as LibraryElementImpl;
return enclosingLibrary._definingCompilationUnit;
}
@override
String get identifier => exportedLibrary!.name;
@override
ElementKind get kind => ElementKind.EXPORT;
@override
T? accept<T>(ElementVisitor<T> visitor) => visitor.visitExportElement(this);
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeExportElement(this);
}
}
/// A concrete implementation of an [ExtensionElement].
class ExtensionElementImpl extends _ExistingElementImpl
with TypeParameterizedElementMixin, HasCompletionData
implements ExtensionElement {
/// The type being extended.
DartType? _extendedType;
/// A list containing all of the accessors (getters and setters) contained in
/// this extension.
List<PropertyAccessorElement> _accessors = const [];
/// A list containing all of the fields contained in this extension.
List<FieldElement> _fields = const [];
/// A list containing all of the methods contained in this extension.
List<MethodElement> _methods = const [];
ElementLinkedData? linkedData;
/// Initialize a newly created extension element to have the given [name] at
/// the given [offset] in the file that contains the declaration of this
/// element.
ExtensionElementImpl(String? name, int nameOffset) : super(name, nameOffset);
@override
List<PropertyAccessorElement> get accessors {
return _accessors;
}
set accessors(List<PropertyAccessorElement> accessors) {
for (PropertyAccessorElement accessor in accessors) {
(accessor as PropertyAccessorElementImpl).enclosingElement = this;
}
_accessors = accessors;
}
@override
String get displayName => name ?? '';
@override
CompilationUnitElementImpl get enclosingElement {
return _enclosingElement as CompilationUnitElementImpl;
}
@override
DartType get extendedType =>
ElementTypeProvider.current.getExtendedType(this);
set extendedType(DartType extendedType) {
_extendedType = extendedType;
}
DartType get extendedTypeInternal {
linkedData?.read(this);
return _extendedType!;
}
@override
List<FieldElement> get fields {
return _fields;
}
set fields(List<FieldElement> fields) {
for (FieldElement field in fields) {
(field as FieldElementImpl).enclosingElement = this;
}
_fields = fields;
}
@override
String get identifier {
if (reference != null) {
return reference!.name;
}
return super.identifier;
}
@override
bool get isSimplyBounded => true;
@override
ElementKind get kind => ElementKind.EXTENSION;
@override
List<ElementAnnotation> get metadata {
linkedData?.read(this);
return super.metadata;
}
@override
List<MethodElement> get methods {
return _methods;
}
/// Set the methods contained in this extension to the given [methods].
set methods(List<MethodElement> methods) {
for (MethodElement method in methods) {
(method as MethodElementImpl).enclosingElement = this;
}
_methods = methods;
}
@override
List<TypeParameterElement> get typeParameters {
linkedData?.read(this);
return super.typeParameters;
}
/// Set the type parameters defined by this extension to the given
/// [typeParameters].
set typeParameters(List<TypeParameterElement> typeParameters) {
for (TypeParameterElement typeParameter in typeParameters) {
(typeParameter as TypeParameterElementImpl).enclosingElement = this;
}
_typeParameterElements = typeParameters;
}
@override
T? accept<T>(ElementVisitor<T> visitor) {
return visitor.visitExtensionElement(this);
}
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeExtensionElement(this);
}
@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++)