blob: 96e4eeb78dcaced902d689c1c8dbbce49fec4b13 [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 'package:analyzer/dart/analysis/session.dart';
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/element2.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/source/source.dart';
import 'package:analyzer/src/dart/element/display_string_builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type_algebra.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisContext;
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:pub_semver/pub_semver.dart';
/// A constructor element defined in a parameterized type where the values of
/// the type parameters are known.
class ConstructorMember extends ExecutableMember
with ConstructorElementMixin
implements ConstructorElement, ConstructorFragment {
/// Initialize a newly created element to represent a constructor, based on
/// the [declaration], and applied [substitution].
ConstructorMember({
required ConstructorElement declaration,
required MapSubstitution augmentationSubstitution,
required MapSubstitution substitution,
}) : super(declaration, augmentationSubstitution, substitution,
const <TypeParameterElement>[]);
@override
ConstructorElement? get augmentation {
return declaration.augmentationTarget;
}
@override
ConstructorElement? get augmentationTarget {
return declaration.augmentationTarget;
}
@override
ConstructorElement get declaration => super.declaration as ConstructorElement;
@override
String get displayName => declaration.displayName;
@override
ConstructorElement2 get element => super.element as ConstructorElement2;
@Deprecated('Use enclosingElement3 instead')
@override
InterfaceElement get enclosingElement => declaration.enclosingElement;
@override
InterfaceElement get enclosingElement3 => declaration.enclosingElement3;
@override
InstanceFragment? get enclosingFragment =>
super.enclosingFragment as InstanceFragment?;
@override
bool get isConst => declaration.isConst;
@override
bool get isConstantEvaluated => declaration.isConstantEvaluated;
@override
bool get isFactory => declaration.isFactory;
@override
String get name => declaration.name;
@override
int? get nameEnd => declaration.nameEnd;
@override
ConstructorFragment? get nextFragment =>
super.nextFragment as ConstructorFragment;
@override
int? get periodOffset => declaration.periodOffset;
@override
ConstructorFragment? get previousFragment =>
super.previousFragment as ConstructorFragment;
@override
ConstructorElement? get redirectedConstructor {
var element = declaration.redirectedConstructor;
return _from2(element);
}
@override
InterfaceType get returnType => type.returnType as InterfaceType;
@override
Source get source => _declaration.source!;
@override
ConstructorElement? get superConstructor {
var element = declaration.superConstructor;
return _from2(element);
}
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitConstructorElement(this);
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeConstructorElement(this);
}
ConstructorMember? _from2(ConstructorElement? element) {
if (element == null) {
return null;
}
ConstructorElement declaration;
MapSubstitution substitution;
if (element is ConstructorMember) {
declaration = element._declaration as ConstructorElement;
var map = <TypeParameterElement, DartType>{};
var elementMap = element._substitution.map;
for (var typeParameter in elementMap.keys) {
var type = elementMap[typeParameter]!;
map[typeParameter] = _substitution.substituteType(type);
}
substitution = Substitution.fromMap(map);
} else {
declaration = element;
substitution = _substitution;
}
return ConstructorMember(
declaration: declaration,
augmentationSubstitution: augmentationSubstitution,
substitution: substitution,
);
}
/// If the given [constructor]'s type is different when any type parameters
/// from the defining type's declaration are replaced with the actual type
/// arguments from the [definingType], create a constructor member
/// representing the given constructor. Return the member that was created, or
/// the original constructor if no member was created.
static ConstructorElement from(
ConstructorElement constructor, InterfaceType definingType) {
if (definingType.typeArguments.isEmpty) {
return constructor;
}
var augmentationSubstitution = Substitution.empty;
if (constructor is ConstructorMember) {
augmentationSubstitution = constructor.augmentationSubstitution;
constructor = constructor.declaration;
}
return ConstructorMember(
declaration: constructor,
augmentationSubstitution: augmentationSubstitution,
substitution: Substitution.fromInterfaceType(definingType),
);
}
}
/// An executable element defined in a parameterized type where the values of
/// the type parameters are known.
abstract class ExecutableMember extends Member
implements ExecutableElement, ExecutableFragment {
@override
final List<TypeParameterElement> typeParameters;
FunctionType? _type;
/// Initialize a newly created element to represent a callable element (like a
/// method or function or property), based on the [declaration], and applied
/// [substitution].
///
/// The [typeParameters] are fresh, and [substitution] is already applied to
/// their bounds. The [substitution] includes replacing [declaration] type
/// parameters with the provided fresh [typeParameters].
ExecutableMember(
ExecutableElement super.declaration,
super.augmentationSubstitution,
super.substitution,
this.typeParameters,
);
@override
List<Element> get children => parameters;
@override
// TODO(augmentations): This needs to return member built from the children
// with the same type arguments as this member.
List<Fragment> get children3 =>
(declaration as ExecutableElementImpl).children3;
@override
ExecutableElement get declaration => super.declaration as ExecutableElement;
@override
String get displayName => declaration.displayName;
@override
Element2 get element => (declaration as ExecutableElementImpl).element;
@override
Fragment? get enclosingFragment =>
(declaration as ExecutableElementImpl?)?.enclosingFragment;
@override
bool get hasImplicitReturnType => declaration.hasImplicitReturnType;
@override
bool get isAbstract => declaration.isAbstract;
@override
bool get isAsynchronous => declaration.isAsynchronous;
@override
bool get isAugmentation => declaration.isAugmentation;
@override
bool get isExtensionTypeMember => declaration.isExtensionTypeMember;
@override
bool get isExternal => declaration.isExternal;
@override
bool get isGenerator => declaration.isGenerator;
@override
bool get isOperator => declaration.isOperator;
@override
bool get isSimplyBounded => declaration.isSimplyBounded;
@override
bool get isStatic => declaration.isStatic;
@override
bool get isSynchronous => declaration.isSynchronous;
@override
LibraryElement get library => _declaration.library!;
@override
LibraryFragment get libraryFragment =>
(declaration as ExecutableElementImpl).libraryFragment;
@override
Source get librarySource => _declaration.librarySource!;
@override
int get nameOffset => declaration.nameOffset;
@override
// TODO(augmentations): This needs to return a member built from the next
// fragment with the same type arguments as this member.
Fragment? get nextFragment =>
(declaration as ExecutableElementImpl).nextFragment;
@override
List<ParameterElement> get parameters {
return declaration.parameters.map<ParameterElement>((p) {
if (p is FieldFormalParameterElement) {
return FieldFormalParameterMember(
p, augmentationSubstitution, _substitution);
}
if (p is SuperFormalParameterElement) {
return SuperFormalParameterMember(
p, augmentationSubstitution, _substitution);
}
return ParameterMember(p, augmentationSubstitution, _substitution);
}).toList();
}
@override
List<FormalParameterFragment> get parameters2 =>
declaration.parameters.cast<FormalParameterFragment>();
@override
// TODO(augmentations): This needs to return a member built from the previous
// fragment with the same type arguments as this member.
Fragment? get previousFragment =>
(declaration as ExecutableElementImpl).previousFragment;
@override
DartType get returnType {
var result = declaration.returnType;
result = augmentationSubstitution.substituteType(result);
result = _substitution.substituteType(result);
return result;
}
@override
FunctionType get type {
if (_type != null) return _type!;
_type = _substitution.substituteType(declaration.type) as FunctionType;
return _type!;
}
@override
List<TypeParameterFragment> get typeParameters2 =>
(declaration as ExecutableElementImpl).typeParameters2;
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeExecutableElement(this, displayName);
}
static ExecutableElement from2(
ExecutableElement element,
MapSubstitution substitution,
) {
var augmentationSubstitution = Substitution.empty;
var combined = substitution;
if (element is ExecutableMember) {
ExecutableMember member = element;
element = member.declaration;
augmentationSubstitution = member.augmentationSubstitution;
var map = <TypeParameterElement, DartType>{};
for (var entry in member._substitution.map.entries) {
map[entry.key] = substitution.substituteType(entry.value);
}
map.addAll(substitution.map);
combined = Substitution.fromMap(map);
}
if (augmentationSubstitution.map.isEmpty && combined.map.isEmpty) {
return element;
}
if (element is ConstructorElement) {
return ConstructorMember(
declaration: element,
augmentationSubstitution: augmentationSubstitution,
substitution: combined,
);
} else if (element is MethodElement) {
return MethodMember(element, augmentationSubstitution, combined);
} else if (element is PropertyAccessorElement) {
return PropertyAccessorMember(
element, augmentationSubstitution, combined);
} else {
throw UnimplementedError('(${element.runtimeType}) $element');
}
}
static ExecutableElement fromAugmentation(
ExecutableElement element,
MapSubstitution augmentationSubstitution,
) {
if (augmentationSubstitution.map.isEmpty) {
return element;
}
if (element is ConstructorElement) {
return ConstructorMember(
declaration: element,
augmentationSubstitution: augmentationSubstitution,
substitution: Substitution.empty,
);
} else if (element is MethodElement) {
return MethodMember(
element, augmentationSubstitution, Substitution.empty);
} else if (element is PropertyAccessorElement) {
return PropertyAccessorMember(
element, augmentationSubstitution, Substitution.empty);
} else {
throw UnimplementedError('(${element.runtimeType}) $element');
}
}
}
/// A parameter element defined in a parameterized type where the values of the
/// type parameters are known.
class FieldFormalParameterMember extends ParameterMember
implements FieldFormalParameterElement {
factory FieldFormalParameterMember(
FieldFormalParameterElement declaration,
MapSubstitution augmentationSubstitution,
MapSubstitution substitution,
) {
var freshTypeParameters = _SubstitutedTypeParameters(
declaration.typeParameters,
substitution,
);
return FieldFormalParameterMember._(
declaration,
augmentationSubstitution,
freshTypeParameters.substitution,
freshTypeParameters.elements,
);
}
FieldFormalParameterMember._(
FieldFormalParameterElement super.declaration,
super.augmentationSubstitution,
super.substitution,
super.typeParameters,
) : super._();
@override
FieldElement? get field {
var field = (declaration as FieldFormalParameterElement).field;
if (field == null) {
return null;
}
return FieldMember(field, augmentationSubstitution, _substitution);
}
@override
bool get hasDefaultValue => declaration.hasDefaultValue;
@override
bool get isCovariant => declaration.isCovariant;
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitFieldFormalParameterElement(this);
}
/// A field element defined in a parameterized type where the values of the type
/// parameters are known.
class FieldMember extends VariableMember
implements FieldElement, FieldFragment {
/// Initialize a newly created element to represent a field, based on the
/// [declaration], with applied [substitution].
FieldMember(
FieldElement super.declaration,
super.augmentationSubstitution,
super.substitution,
);
@override
FieldElement? get augmentation {
return declaration.augmentationTarget;
}
@override
FieldElement? get augmentationTarget {
return declaration.augmentationTarget;
}
@override
List<Fragment> get children3 => (declaration as FieldFragment).children3;
@override
FieldElement get declaration => super.declaration as FieldElement;
@override
String get displayName => declaration.displayName;
@override
FieldElement2 get element => (declaration as FieldFragment).element;
@Deprecated('Use enclosingElement3 instead')
@override
Element get enclosingElement => declaration.enclosingElement;
@override
Element get enclosingElement3 => declaration.enclosingElement3;
@override
Fragment? get enclosingFragment =>
(declaration as FieldFragment).enclosingFragment;
@override
PropertyAccessorElement? get getter {
var baseGetter = declaration.getter;
if (baseGetter == null) {
return null;
}
return PropertyAccessorMember(
baseGetter, augmentationSubstitution, _substitution);
}
@override
GetterFragment? get getter2 => (declaration as FieldFragment).getter2;
@override
bool get hasInitializer => declaration.hasInitializer;
@override
bool get isAbstract => declaration.isAbstract;
@override
bool get isAugmentation => declaration.isAugmentation;
@override
bool get isCovariant => declaration.isCovariant;
@override
bool get isEnumConstant => declaration.isEnumConstant;
@override
bool get isExternal => declaration.isExternal;
@override
bool get isPromotable => declaration.isPromotable;
@override
LibraryElement get library => _declaration.library!;
@override
LibraryFragment get libraryFragment =>
(declaration as FieldFragment).libraryFragment;
@override
String get name => declaration.name;
@override
FieldFragment? get nextFragment =>
(declaration as FieldFragment).nextFragment;
@override
FieldFragment? get previousFragment =>
(declaration as FieldFragment).previousFragment;
@override
PropertyAccessorElement? get setter {
var baseSetter = declaration.setter;
if (baseSetter == null) {
return null;
}
return PropertyAccessorMember(
baseSetter, augmentationSubstitution, _substitution);
}
@override
SetterFragment? get setter2 => (declaration as FieldFragment).setter2;
@override
Source? get source => _declaration.source;
@override
T? accept<T>(ElementVisitor<T> visitor) => visitor.visitFieldElement(this);
/// If the given [field]'s type is different when any type parameters from the
/// defining type's declaration are replaced with the actual type arguments
/// from the [definingType], create a field member representing the given
/// field. Return the member that was created, or the base field if no member
/// was created.
static FieldElement from(FieldElement field, InterfaceType definingType) {
if (definingType.typeArguments.isEmpty) {
return field;
}
return FieldMember(
field,
field is FieldMember
? field.augmentationSubstitution
: Substitution.empty,
Substitution.fromInterfaceType(definingType),
);
}
static FieldElement from2(
FieldElement element,
MapSubstitution substitution,
) {
if (substitution.map.isEmpty) {
return element;
}
return FieldMember(
element,
element is FieldMember
? element.augmentationSubstitution
: Substitution.empty,
substitution,
);
}
static FieldElement fromAugmentation(
FieldElement element,
MapSubstitution augmentationSubstitution,
) {
if (augmentationSubstitution.map.isEmpty) {
return element;
}
return FieldMember(element, augmentationSubstitution, Substitution.empty);
}
}
class FunctionMember extends ExecutableMember implements FunctionElement {
FunctionMember(FunctionElement declaration)
: super(
declaration,
Substitution.empty,
Substitution.empty,
declaration.typeParameters,
);
@override
FunctionElement? get augmentation {
return declaration.augmentationTarget;
}
@override
FunctionElement? get augmentationTarget {
return declaration.augmentationTarget;
}
@override
FunctionElement get declaration => super.declaration as FunctionElement;
@Deprecated('Use enclosingElement3 instead')
@override
Element get enclosingElement => declaration.enclosingElement;
@override
Element get enclosingElement3 => declaration.enclosingElement3;
@override
bool get isDartCoreIdentical => declaration.isDartCoreIdentical;
@override
bool get isEntryPoint => declaration.isEntryPoint;
@override
String get name => declaration.name;
@override
Source get source => _declaration.source!;
@override
T? accept<T>(ElementVisitor<T> visitor) {
return visitor.visitFunctionElement(this);
}
}
/// An element defined in a parameterized type where the values of the type
/// parameters are known.
abstract class Member implements Element {
/// The element on which the parameterized element was created.
final Element _declaration;
final MapSubstitution augmentationSubstitution;
/// The substitution for type parameters referenced in the base element.
final MapSubstitution _substitution;
/// Initialize a newly created element to represent a member, based on the
/// [declaration], and applied [_substitution].
Member(this._declaration, this.augmentationSubstitution, this._substitution) {
if (_declaration is Member) {
throw StateError('Members must be created from a declaration, but is '
'(${_declaration.runtimeType}) "$_declaration".');
}
}
@override
List<Element> get children => const [];
@override
AnalysisContext get context => _declaration.context;
@override
Element get declaration => _declaration;
@override
String get displayName => _declaration.displayName;
@override
String? get documentationComment => _declaration.documentationComment;
@Deprecated('Use enclosingElement3 instead')
@override
Element? get enclosingElement => _declaration.enclosingElement;
@override
Element? get enclosingElement3 => _declaration.enclosingElement3;
@override
bool get hasAlwaysThrows => _declaration.hasAlwaysThrows;
@override
bool get hasDeprecated => _declaration.hasDeprecated;
@override
bool get hasDoNotStore => _declaration.hasDoNotStore;
@override
bool get hasDoNotSubmit => _declaration.hasDoNotSubmit;
@override
bool get hasFactory => _declaration.hasFactory;
@override
bool get hasImmutable => _declaration.hasImmutable;
@override
bool get hasInternal => _declaration.hasInternal;
@override
bool get hasIsTest => _declaration.hasIsTest;
@override
bool get hasIsTestGroup => _declaration.hasIsTestGroup;
@override
bool get hasJS => _declaration.hasJS;
@override
bool get hasLiteral => _declaration.hasLiteral;
@override
bool get hasMustBeConst => _declaration.hasMustBeConst;
@override
bool get hasMustBeOverridden => _declaration.hasMustBeOverridden;
@override
bool get hasMustCallSuper => _declaration.hasMustCallSuper;
@override
bool get hasNonVirtual => _declaration.hasNonVirtual;
@override
bool get hasOptionalTypeArgs => _declaration.hasOptionalTypeArgs;
@override
bool get hasOverride => _declaration.hasOverride;
@override
bool get hasProtected => _declaration.hasProtected;
@override
bool get hasRedeclare => _declaration.hasRedeclare;
@override
bool get hasReopen => _declaration.hasReopen;
@override
bool get hasRequired => _declaration.hasRequired;
@override
bool get hasSealed => _declaration.hasSealed;
@override
bool get hasUseResult => _declaration.hasUseResult;
@override
bool get hasVisibleForOverriding => _declaration.hasVisibleForOverriding;
@override
bool get hasVisibleForTemplate => _declaration.hasVisibleForTemplate;
@override
bool get hasVisibleForTesting => _declaration.hasVisibleForTesting;
@override
bool get hasVisibleOutsideTemplate => _declaration.hasVisibleOutsideTemplate;
@override
int get id => _declaration.id;
@override
bool get isPrivate => _declaration.isPrivate;
@override
bool get isPublic => _declaration.isPublic;
@override
bool get isSynthetic => _declaration.isSynthetic;
@override
ElementKind get kind => _declaration.kind;
@override
LibraryElement? get library => _declaration.library;
@override
Source? get librarySource => _declaration.librarySource;
@override
ElementLocation get location => _declaration.location!;
@override
List<ElementAnnotation> get metadata => _declaration.metadata;
@override
String? get name => _declaration.name;
@override
int get nameLength => _declaration.nameLength;
@override
int get nameOffset => _declaration.nameOffset;
@override
Element get nonSynthetic => _declaration.nonSynthetic;
@override
AnalysisSession? get session => _declaration.session;
@override
Version? get sinceSdkVersion => _declaration.sinceSdkVersion;
/// The substitution for type parameters referenced in the base element.
MapSubstitution get substitution => _substitution;
/// Append a textual representation of this element to the given [builder].
void appendTo(ElementDisplayStringBuilder builder);
@override
String getDisplayString({
@Deprecated('Only non-nullable by default mode is supported')
bool withNullability = true,
bool multiline = false,
bool preferTypeAlias = false,
}) {
var builder = ElementDisplayStringBuilder(
multiline: multiline,
preferTypeAlias: preferTypeAlias,
);
appendTo(builder);
return builder.toString();
}
@override
String getExtendedDisplayName(String? shortName) =>
_declaration.getExtendedDisplayName(shortName);
@override
bool isAccessibleIn(LibraryElement library) =>
_declaration.isAccessibleIn(library);
@override
E? thisOrAncestorMatching<E extends Element>(
bool Function(Element) predicate,
) {
return declaration.thisOrAncestorMatching(predicate);
}
@override
E? thisOrAncestorMatching3<E extends Element>(
bool Function(Element) predicate,
) {
return declaration.thisOrAncestorMatching3(predicate);
}
@override
E? thisOrAncestorOfType<E extends Element>() =>
declaration.thisOrAncestorOfType<E>();
@override
E? thisOrAncestorOfType3<E extends Element>() =>
declaration.thisOrAncestorOfType3<E>();
@override
String toString() {
return getDisplayString();
}
/// Use the given [visitor] to visit all of the children of this element.
/// There is no guarantee of the order in which the children will be visited.
@override
void visitChildren(ElementVisitor visitor) {
for (Element child in children) {
child.accept(visitor);
}
}
}
/// A method element defined in a parameterized type where the values of the
/// type parameters are known.
class MethodMember extends ExecutableMember
implements MethodElement, MethodFragment {
factory MethodMember(
MethodElement declaration,
MapSubstitution augmentationSubstitution,
MapSubstitution substitution,
) {
var freshTypeParameters = _SubstitutedTypeParameters(
declaration.typeParameters,
substitution,
);
return MethodMember._(
declaration,
augmentationSubstitution,
freshTypeParameters.substitution,
freshTypeParameters.elements,
);
}
MethodMember._(
MethodElement super.declaration,
super.augmentationSubstitution,
super.substitution,
super.typeParameters,
);
@override
MethodElement? get augmentation {
// TODO(scheglov): implement
throw UnimplementedError();
}
@override
MethodElement? get augmentationTarget {
return declaration.augmentationTarget;
}
@override
MethodElement get declaration => super.declaration as MethodElement;
@override
MethodElement2 get element => super.element as MethodElement2;
@Deprecated('Use enclosingElement3 instead')
@override
Element get enclosingElement => declaration.enclosingElement;
@override
Element get enclosingElement3 => declaration.enclosingElement3;
@override
InstanceFragment? get enclosingFragment =>
super.enclosingFragment as InstanceFragment?;
@override
String get name => declaration.name;
@override
MethodFragment? get nextFragment => super.nextFragment as MethodFragment;
@override
MethodFragment? get previousFragment =>
super.previousFragment as MethodFragment;
@override
Source get source => _declaration.source!;
@override
T? accept<T>(ElementVisitor<T> visitor) => visitor.visitMethodElement(this);
/// If the given [method]'s type is different when any type parameters from
/// the defining type's declaration are replaced with the actual type
/// arguments from the [definingType], create a method member representing the
/// given method. Return the member that was created, or the base method if no
/// member was created.
static MethodElement? from(
MethodElement? method, InterfaceType definingType) {
if (method == null || definingType.typeArguments.isEmpty) {
return method;
}
return MethodMember(
method,
method is MethodMember
? method.augmentationSubstitution
: Substitution.empty,
Substitution.fromInterfaceType(definingType),
);
}
static MethodElement from2(
MethodElement element,
MapSubstitution substitution,
) {
if (substitution.map.isEmpty) {
return element;
}
return MethodMember(
element,
element is MethodMember
? element.augmentationSubstitution
: Substitution.empty,
substitution,
);
}
}
/// A parameter element defined in a parameterized type where the values of the
/// type parameters are known.
class ParameterMember extends VariableMember
with ParameterElementMixin
implements ParameterElement {
@override
final List<TypeParameterElement> typeParameters;
factory ParameterMember(
ParameterElement declaration,
MapSubstitution augmentationSubstitution,
MapSubstitution substitution,
) {
var freshTypeParameters = _SubstitutedTypeParameters(
declaration.typeParameters,
substitution,
);
return ParameterMember._(
declaration,
augmentationSubstitution,
freshTypeParameters.substitution,
freshTypeParameters.elements,
);
}
/// Initialize a newly created element to represent a parameter, based on the
/// [declaration], with applied [substitution].
ParameterMember._(
ParameterElement super.declaration,
super.augmentationSubstitution,
super.substitution,
this.typeParameters,
);
@override
List<Element> get children => parameters;
@override
ParameterElement get declaration => super.declaration as ParameterElement;
@override
String? get defaultValueCode => declaration.defaultValueCode;
@Deprecated('Use enclosingElement3 instead')
@override
Element? get enclosingElement => declaration.enclosingElement;
@override
Element? get enclosingElement3 => declaration.enclosingElement3;
@override
bool get hasDefaultValue => declaration.hasDefaultValue;
@override
bool get isCovariant => declaration.isCovariant;
@override
bool get isInitializingFormal => declaration.isInitializingFormal;
@override
bool get isSuperFormal => declaration.isSuperFormal;
@override
String get name => declaration.name;
@deprecated
@override
ParameterKind get parameterKind {
return declaration.parameterKind;
}
@override
List<ParameterElement> get parameters {
var type = this.type;
if (type is FunctionType) {
return type.parameters;
}
return const <ParameterElement>[];
}
@override
Source? get source => _declaration.source;
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitParameterElement(this);
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeFormalParameter(this);
}
static ParameterElement from(
ParameterElement element, MapSubstitution substitution) {
var combined = substitution;
if (element is ParameterMember) {
var member = element;
element = member.declaration;
var map = <TypeParameterElement, DartType>{};
for (var entry in member._substitution.map.entries) {
map[entry.key] = substitution.substituteType(entry.value);
}
map.addAll(substitution.map);
combined = Substitution.fromMap(map);
}
if (combined.map.isEmpty) {
return element;
}
return ParameterMember(
element,
element is ParameterMember
? element.augmentationSubstitution
: Substitution.empty,
combined,
);
}
}
/// A property accessor element defined in a parameterized type where the values
/// of the type parameters are known.
class PropertyAccessorMember extends ExecutableMember
implements PropertyAccessorElement, GetterFragment, SetterFragment {
factory PropertyAccessorMember(
PropertyAccessorElement declaration,
MapSubstitution augmentationSubstitution,
MapSubstitution substitution,
) {
var freshTypeParameters = _SubstitutedTypeParameters(
declaration.typeParameters,
substitution,
);
return PropertyAccessorMember._(
declaration,
augmentationSubstitution,
freshTypeParameters.substitution,
freshTypeParameters.elements,
);
}
PropertyAccessorMember._(
PropertyAccessorElement super.declaration,
super.augmentationSubstitution,
super.substitution,
super.typeParameters,
);
@override
PropertyAccessorElement? get augmentation {
return declaration.augmentation;
}
@override
PropertyAccessorElement? get augmentationTarget {
return declaration.augmentationTarget;
}
@override
PropertyAccessorElement? get correspondingGetter {
var baseGetter = declaration.correspondingGetter;
if (baseGetter == null) {
return null;
}
return PropertyAccessorMember(
baseGetter, augmentationSubstitution, _substitution);
}
@override
GetterFragment? get correspondingGetter2 =>
(declaration as SetterFragment).correspondingGetter2;
@override
PropertyAccessorElement? get correspondingSetter {
var baseSetter = declaration.correspondingSetter;
if (baseSetter == null) {
return null;
}
return PropertyAccessorMember(
baseSetter, augmentationSubstitution, _substitution);
}
@override
SetterFragment? get correspondingSetter2 =>
(declaration as GetterFragment).correspondingSetter2;
@override
PropertyAccessorElement get declaration =>
super.declaration as PropertyAccessorElement;
@Deprecated('Use enclosingElement3 instead')
@override
Element get enclosingElement => declaration.enclosingElement;
@override
Element get enclosingElement3 => declaration.enclosingElement3;
@override
bool get isGetter => declaration.isGetter;
@override
bool get isSetter => declaration.isSetter;
@override
String get name => declaration.name;
@override
Source get source => _declaration.source!;
@override
PropertyInducingElement get variable {
return variable2!;
}
@override
PropertyInducingElement? get variable2 {
// TODO(scheglov): revisit
var variable = declaration.variable2;
if (variable is FieldElement) {
return FieldMember(variable, augmentationSubstitution, _substitution);
} else if (variable is TopLevelVariableElement) {
return TopLevelVariableMember(
variable, augmentationSubstitution, _substitution);
}
return variable;
}
@override
PropertyInducingFragment? get variable3 =>
(declaration as PropertyAccessorElementImpl).variable3;
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitPropertyAccessorElement(this);
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeExecutableElement(
this,
(isGetter ? 'get ' : 'set ') + variable.displayName,
);
}
/// If the given [accessor]'s type is different when any type parameters from
/// the defining type's declaration are replaced with the actual type
/// arguments from the [definingType], create an accessor member representing
/// the given accessor. Return the member that was created, or the base
/// accessor if no member was created.
static PropertyAccessorElement? from(
PropertyAccessorElement? accessor, InterfaceType definingType) {
if (accessor == null || definingType.typeArguments.isEmpty) {
return accessor;
}
return PropertyAccessorMember(
accessor,
accessor is PropertyAccessorMember
? accessor.augmentationSubstitution
: Substitution.empty,
Substitution.fromInterfaceType(definingType),
);
}
}
class SuperFormalParameterMember extends ParameterMember
implements SuperFormalParameterElement {
factory SuperFormalParameterMember(
SuperFormalParameterElement declaration,
MapSubstitution augmentationSubstitution,
MapSubstitution substitution,
) {
var freshTypeParameters = _SubstitutedTypeParameters(
declaration.typeParameters,
substitution,
);
return SuperFormalParameterMember._(
declaration,
augmentationSubstitution,
freshTypeParameters.substitution,
freshTypeParameters.elements,
);
}
SuperFormalParameterMember._(
SuperFormalParameterElement super.declaration,
super.augmentationSubstitution,
super.substitution,
super.typeParameters,
) : super._();
@override
bool get hasDefaultValue => declaration.hasDefaultValue;
@override
bool get isCovariant => declaration.isCovariant;
@override
ParameterElement? get superConstructorParameter {
var superConstructorParameter =
(declaration as SuperFormalParameterElement).superConstructorParameter;
if (superConstructorParameter == null) {
return null;
}
return ParameterMember.from(superConstructorParameter, substitution);
}
@override
T? accept<T>(ElementVisitor<T> visitor) =>
visitor.visitSuperFormalParameterElement(this);
}
class TopLevelVariableMember extends VariableMember
implements TopLevelVariableElement {
TopLevelVariableMember(
super.declaration,
super.augmentationSubstitution,
super.substitution,
);
@override
TopLevelVariableElement? get augmentation {
return declaration.augmentationTarget;
}
@override
TopLevelVariableElement? get augmentationTarget {
return declaration.augmentationTarget;
}
@override
TopLevelVariableElement get declaration =>
_declaration as TopLevelVariableElement;
@override
String get displayName => declaration.displayName;
@override
PropertyAccessorElement? get getter {
var baseGetter = declaration.getter;
if (baseGetter == null) {
return null;
}
return PropertyAccessorMember(
baseGetter, augmentationSubstitution, _substitution);
}
@override
bool get hasInitializer => declaration.hasInitializer;
@override
bool get isAugmentation => declaration.isAugmentation;
@override
bool get isExternal => declaration.isExternal;
@override
LibraryElement get library => _declaration.library!;
@override
String get name => declaration.name;
@override
PropertyAccessorElement? get setter {
var baseSetter = declaration.setter;
if (baseSetter == null) {
return null;
}
return PropertyAccessorMember(
baseSetter, augmentationSubstitution, _substitution);
}
@override
Source get source => _declaration.source!;
@override
T? accept<T>(ElementVisitor<T> visitor) {
return visitor.visitTopLevelVariableElement(this);
}
}
/// A variable element defined in a parameterized type where the values of the
/// type parameters are known.
abstract class VariableMember extends Member implements VariableElement {
DartType? _type;
/// Initialize a newly created element to represent a variable, based on the
/// [declaration], with applied [substitution].
VariableMember(
VariableElement super.declaration,
super.augmentationSubstitution,
super.substitution,
);
@override
VariableElement get declaration => super.declaration as VariableElement;
@override
bool get hasImplicitType => declaration.hasImplicitType;
@override
bool get isConst => declaration.isConst;
@override
bool get isConstantEvaluated => declaration.isConstantEvaluated;
@override
bool get isFinal => declaration.isFinal;
@override
bool get isLate => declaration.isLate;
@override
bool get isStatic => declaration.isStatic;
@override
DartType get type {
if (_type != null) return _type!;
var result = declaration.type;
result = augmentationSubstitution.substituteType(result);
result = _substitution.substituteType(result);
return _type = result;
}
@override
void appendTo(ElementDisplayStringBuilder builder) {
builder.writeVariableElement(this);
}
@override
DartObject? computeConstantValue() => declaration.computeConstantValue();
}
class _SubstitutedTypeParameters {
final List<TypeParameterElement> elements;
final MapSubstitution substitution;
factory _SubstitutedTypeParameters(
List<TypeParameterElement> elements,
MapSubstitution substitution,
) {
if (elements.isEmpty) {
return _SubstitutedTypeParameters._(elements, substitution);
}
// Create type formals with specialized bounds.
// For example `<U extends T>` where T comes from an outer scope.
var newElements = <TypeParameterElement>[];
var newTypes = <TypeParameterType>[];
for (int i = 0; i < elements.length; i++) {
var element = elements[i];
var newElement = TypeParameterElementImpl.synthetic(element.name);
newElements.add(newElement);
newTypes.add(
newElement.instantiate(
nullabilitySuffix: NullabilitySuffix.none,
),
);
}
// Update bounds to reference new TypeParameterElement(s).
var substitution2 = Substitution.fromPairs(elements, newTypes);
for (int i = 0; i < newElements.length; i++) {
var element = elements[i];
var newElement = newElements[i] as TypeParameterElementImpl;
var bound = element.bound;
if (bound != null) {
var newBound = substitution2.substituteType(bound);
newBound = substitution.substituteType(newBound);
newElement.bound = newBound;
}
}
if (substitution.map.isEmpty) {
return _SubstitutedTypeParameters._(newElements, substitution2);
}
return _SubstitutedTypeParameters._(
newElements,
Substitution.fromMap({
...substitution.map,
...substitution2.map,
}),
);
}
_SubstitutedTypeParameters._(this.elements, this.substitution);
}