| // 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/dart/element/type_provider.dart'; |
| import 'package:analyzer/dart/element/type_system.dart'; |
| import 'package:analyzer/error/error.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/export.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:analyzer/src/util/file_paths.dart' as file_paths; |
| 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 super.name, super.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 { |
| return library.session.classHierarchy.implementedInterfaces(this); |
| } |
| |
| @override |
| String get displayName => name; |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| CompilationUnitElementImpl get enclosingElement { |
| return _enclosingElement as CompilationUnitElementImpl; |
| } |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| CompilationUnitElementImpl get enclosingElement2 { |
| return _enclosingElement as CompilationUnitElementImpl; |
| } |
| |
| @override |
| CompilationUnitElementImpl get enclosingElement3 { |
| 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; |
| } |
| |
| /// Return `true` if this class represents the class 'Function' defined in the |
| /// dart:core library. |
| bool get isDartCoreFunctionImpl { |
| return name == 'Function' && library.isDartCore; |
| } |
| |
| @override |
| bool get isDartCoreObject => false; |
| |
| @Deprecated('Use `is EnumElement` instead') |
| @override |
| bool get isEnum => false; |
| |
| @Deprecated('Use `is MixinElement` instead') |
| @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( |
| element2: this, |
| typeArguments: typeArguments, |
| nullabilitySuffix: nullabilitySuffix, |
| ); |
| } |
| |
| @override |
| MethodElement? lookUpConcreteMethod( |
| String methodName, LibraryElement library) => |
| _first(_implementationsOfMethod(methodName).where( |
| (MethodElement method) => |
| !method.isAbstract && method.isAccessibleIn2(library))); |
| |
| @override |
| PropertyAccessorElement? lookUpGetter( |
| String getterName, LibraryElement library) => |
| _first(_implementationsOfGetter(getterName).where( |
| (PropertyAccessorElement getter) => getter.isAccessibleIn2(library))); |
| |
| @override |
| PropertyAccessorElement? lookUpInheritedConcreteGetter( |
| String getterName, LibraryElement library) => |
| _first(_implementationsOfGetter(getterName).where( |
| (PropertyAccessorElement getter) => |
| !getter.isAbstract && |
| !getter.isStatic && |
| getter.isAccessibleIn2(library) && |
| getter.enclosingElement3 != 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.isAccessibleIn2(library) && |
| method.enclosingElement3 != this)); |
| |
| @override |
| PropertyAccessorElement? lookUpInheritedConcreteSetter( |
| String setterName, LibraryElement library) => |
| _first(_implementationsOfSetter(setterName).where( |
| (PropertyAccessorElement setter) => |
| !setter.isAbstract && |
| !setter.isStatic && |
| setter.isAccessibleIn2(library) && |
| setter.enclosingElement3 != this)); |
| |
| @override |
| MethodElement? lookUpInheritedMethod( |
| String methodName, LibraryElement library) => |
| _first(_implementationsOfMethod(methodName).where( |
| (MethodElement method) => |
| !method.isStatic && |
| method.isAccessibleIn2(library) && |
| method.enclosingElement3 != this)); |
| |
| @override |
| MethodElement? lookUpMethod(String methodName, LibraryElement library) => |
| _first(_implementationsOfMethod(methodName) |
| .where((MethodElement method) => method.isAccessibleIn2(library))); |
| |
| @override |
| PropertyAccessorElement? lookUpSetter( |
| String setterName, LibraryElement library) => |
| _first(_implementationsOfSetter(setterName).where( |
| (PropertyAccessorElement setter) => setter.isAccessibleIn2(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.isAccessibleIn2(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.isAccessibleIn2(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.isAccessibleIn2(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* { |
| final visitedClasses = <InterfaceElement>{}; |
| InterfaceElement? classElement = this; |
| 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.element2.getGetter(getterName); |
| if (getter != null) { |
| yield getter; |
| } |
| } |
| if (classElement is ClassElement) { |
| classElement = classElement.supertype?.element2; |
| } else { |
| break; |
| } |
| } |
| } |
| |
| /// 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* { |
| final visitedClasses = <InterfaceElement>{}; |
| InterfaceElement? classElement = this; |
| 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.element2.getMethod(methodName); |
| if (method != null) { |
| yield method; |
| } |
| } |
| if (classElement is ClassElement) { |
| classElement = classElement.supertype?.element2; |
| } else { |
| break; |
| } |
| } |
| } |
| |
| /// 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* { |
| final visitedClasses = <InterfaceElement>{}; |
| InterfaceElement? classElement = this; |
| 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.element2.getSetter(setterName); |
| if (setter != null) { |
| yield setter; |
| } |
| } |
| if (classElement is ClassElement) { |
| classElement = classElement.supertype?.element2; |
| } else { |
| break; |
| } |
| } |
| } |
| |
| 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; |
| } |
| } |
| |
| class AugmentationImportElementImpl extends _ExistingElementImpl |
| implements AugmentationImportElement { |
| @override |
| final int importKeywordOffset; |
| |
| @override |
| final DirectiveUri uri; |
| |
| AugmentationImportElementImpl({ |
| required this.importKeywordOffset, |
| required this.uri, |
| }) : super(null, importKeywordOffset); |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| LibraryOrAugmentationElementImpl get enclosingElement { |
| return super.enclosingElement2 as LibraryOrAugmentationElementImpl; |
| } |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| LibraryOrAugmentationElementImpl get enclosingElement2 { |
| return super.enclosingElement2 as LibraryOrAugmentationElementImpl; |
| } |
| |
| @override |
| LibraryOrAugmentationElementImpl get enclosingElement3 { |
| return super.enclosingElement3 as LibraryOrAugmentationElementImpl; |
| } |
| |
| @override |
| LibraryAugmentationElementImpl? get importedAugmentation { |
| final uri = this.uri; |
| if (uri is DirectiveUriWithAugmentationImpl) { |
| return uri.augmentation; |
| } |
| return null; |
| } |
| |
| @override |
| ElementKind get kind => ElementKind.AUGMENTATION_IMPORT; |
| |
| @override |
| T? accept<T>(ElementVisitor<T> visitor) => |
| visitor.visitAugmentationImportElement(this); |
| } |
| |
| /// 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(super.name, super.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 |
| ClassAugmentationElement? get augmentation { |
| // TODO(scheglov) implement |
| throw UnimplementedError(); |
| } |
| |
| @override |
| AugmentedClassElement get augmented { |
| // TODO(scheglov) implement |
| throw UnimplementedError(); |
| } |
| |
| @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 { |
| final classesToVisit = <InterfaceElement>[]; |
| final visitedClasses = <InterfaceElement>{}; |
| classesToVisit.add(this); |
| while (classesToVisit.isNotEmpty) { |
| final 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) { |
| classesToVisit.add(mixinType.element2); |
| } |
| // check super |
| if (currentElement is ClassElement) { |
| final supertype = currentElement.supertype; |
| if (supertype != null) { |
| classesToVisit.add(supertype.element2); |
| } |
| } |
| } |
| } |
| // 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?.enclosingElement3 as ClassElement?; |
| return definingClass != null && !definingClass.isDartCoreObject; |
| } |
| |
| @Deprecated('Not useful for clients') |
| @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 { |
| return name == 'Object' && library.isDartCore; |
| } |
| |
| bool get isEnumLike { |
| // Must be a concrete class. |
| // TODO(scheglov) `is MixinElement` after the separation. |
| if (isAbstract || this is MixinElement) { |
| 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?.element2 == 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!.element2 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.isAccessibleIn2(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.element2.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<EnumElement> _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<MixinElement> _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; |
| } |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| LibraryElement get enclosingElement => |
| super.enclosingElement2 as LibraryElement; |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| LibraryOrAugmentationElement get enclosingElement2 => |
| super.enclosingElement2 as LibraryOrAugmentationElement; |
| |
| @override |
| LibraryOrAugmentationElement get enclosingElement3 => |
| super.enclosingElement3 as LibraryOrAugmentationElement; |
| |
| @override |
| CompilationUnitElementImpl get enclosingUnit { |
| return this; |
| } |
| |
| @Deprecated('Use enums2 instead') |
| @override |
| List<ClassElement> get enums { |
| return _enums.map((e) => e as ClassElement).toList(); |
| } |
| |
| @override |
| List<EnumElement> get enums2 { |
| return _enums; |
| } |
| |
| /// Set the enums contained in this compilation unit to the given [enums]. |
| set enums2(List<EnumElement> enums) { |
| for (final element in enums) { |
| (element 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; |
| } |
| |
| @Deprecated('Use mixins2 instead') |
| @override |
| List<ClassElement> get mixins { |
| return _mixins.map((e) => e as ClassElement).toList(); |
| } |
| |
| @override |
| List<MixinElement> get mixins2 { |
| return _mixins; |
| } |
| |
| /// Set the mixins contained in this compilation unit to the given [mixins]. |
| set mixins2(List<MixinElement> mixins) { |
| for (var type in mixins) { |
| (type as MixinElementImpl).enclosingElement = this; |
| } |
| _mixins = mixins; |
| } |
| |
| @override |
| AnalysisSession get session => enclosingElement3.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? getClass(String className) { |
| for (final class_ in classes) { |
| if (class_.name == className) { |
| return class_; |
| } |
| } |
| return null; |
| } |
| |
| @Deprecated('Use getEnum2() instead') |
| @override |
| ClassElement? getEnum(String enumName) { |
| for (ClassElement enumDeclaration in enums) { |
| if (enumDeclaration.name == enumName) { |
| return enumDeclaration; |
| } |
| } |
| return null; |
| } |
| |
| @override |
| EnumElement? getEnum2(String name) { |
| for (final element in enums2) { |
| if (element.name == name) { |
| return element; |
| } |
| } |
| return null; |
| } |
| |
| @Deprecated('Use getClass() instead') |
| @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(enums2, visitor); |
| safelyVisitChildren(extensions, visitor); |
| safelyVisitChildren(functions, visitor); |
| safelyVisitChildren(mixins2, 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(super.name, super.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(super.name, super.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(super.name, super.offset); |
| |
| @override |
| ConstructorAugmentationElement? get augmentation { |
| // TODO(scheglov) implement |
| throw UnimplementedError(); |
| } |
| |
| /// 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 = enclosingElement3.name; |
| var name = this.name; |
| if (name.isNotEmpty) { |
| return '$className.$name'; |
| } else { |
| return className; |
| } |
| } |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| AbstractClassElementImpl get enclosingElement => |
| super.enclosingElement2 as AbstractClassElementImpl; |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| AbstractClassElementImpl get enclosingElement2 => |
| super.enclosingElement2 as AbstractClassElementImpl; |
| |
| @override |
| InterfaceElement get enclosingElement3 => |
| super.enclosingElement3 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 ? enclosingElement3 : 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 ??= enclosingElement3.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(super.name, super.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: $enclosingElement3]' |
| '[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 super.name, |
| required super.nameOffset, |
| required super.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 super.name, |
| required super.nameOffset, |
| required super.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 super.name, |
| required super.nameOffset, |
| required super.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; |
| } |
| } |
| |
| class DeferredImportElementPrefixImpl extends ImportElementPrefixImpl |
| implements DeferredImportElementPrefix { |
| DeferredImportElementPrefixImpl({ |
| required super.element, |
| }); |
| } |
| |
| class DirectiveUriImpl implements DirectiveUri {} |
| |
| class DirectiveUriWithAugmentationImpl extends DirectiveUriWithSourceImpl |
| implements DirectiveUriWithAugmentation { |
| @override |
| late LibraryAugmentationElementImpl augmentation; |
| |
| DirectiveUriWithAugmentationImpl({ |
| required super.relativeUriString, |
| required super.relativeUri, |
| required super.source, |
| required this.augmentation, |
| }); |
| } |
| |
| class DirectiveUriWithLibraryImpl extends DirectiveUriWithSourceImpl |
| implements DirectiveUriWithLibrary { |
| @override |
| late LibraryElementImpl library; |
| |
| DirectiveUriWithLibraryImpl({ |
| required super.relativeUriString, |
| required super.relativeUri, |
| required super.source, |
| required this.library, |
| }); |
| |
| DirectiveUriWithLibraryImpl.read({ |
| required super.relativeUriString, |
| required super.relativeUri, |
| required super.source, |
| }); |
| } |
| |
| class DirectiveUriWithRelativeUriImpl |
| extends DirectiveUriWithRelativeUriStringImpl |
| implements DirectiveUriWithRelativeUri { |
| @override |
| final Uri relativeUri; |
| |
| DirectiveUriWithRelativeUriImpl({ |
| required super.relativeUriString, |
| required this.relativeUri, |
| }); |
| } |
| |
| class DirectiveUriWithRelativeUriStringImpl extends DirectiveUriImpl |
| implements DirectiveUriWithRelativeUriString { |
| @override |
| final String relativeUriString; |
| |
| DirectiveUriWithRelativeUriStringImpl({ |
| required this.relativeUriString, |
| }); |
| } |
| |
| class DirectiveUriWithSourceImpl extends DirectiveUriWithRelativeUriImpl |
| implements DirectiveUriWithSource { |
| @override |
| final Source source; |
| |
| DirectiveUriWithSourceImpl({ |
| required super.relativeUriString, |
| required super.relativeUri, |
| required this.source, |
| }); |
| } |
| |
| class DirectiveUriWithUnitImpl extends DirectiveUriWithRelativeUriImpl |
| implements DirectiveUriWithUnit { |
| @override |
| final CompilationUnitElementImpl unit; |
| |
| DirectiveUriWithUnitImpl({ |
| required super.relativeUriString, |
| required super.relativeUri, |
| required this.unit, |
| }); |
| |
| @override |
| Source get source => unit.source; |
| } |
| |
| /// 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 |
| /// subclasses to override this method. |
| static const String _MUST_BE_OVERRIDDEN = "mustBeOverridden"; |
| |
| /// 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.enclosingElement3.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 isMustBeOverridden => _isPackageMetaGetter(_MUST_BE_OVERRIDDEN); |
| |
| @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.enclosingElement3.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; |
| } |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| Element? get enclosingElement => _enclosingElement; |
| |
| /// Set the enclosing element of this element to the given [element]. |
| set enclosingElement(Element? element) { |
| _enclosingElement = element as ElementImpl?; |
| } |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| Element? get enclosingElement2 => _enclosingElement; |
| |
| @override |
| Element? get enclosingElement3 => _enclosingElement; |
| |
| /// 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 hasMustBeOverridden { |
| final metadata = this.metadata; |
| for (var i = 0; i < metadata.length; i++) { |
| var annotation = metadata[i]; |
| if (annotation.isMustBeOverridden) { |
| 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 enclosingElement3?.session; |
| } |
| |
| @override |
| Source? get source { |
| return enclosingElement3?.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 ElementImpl && |
| 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); |
| |
| @Deprecated('Use isAccessibleIn2() instead') |
| @override |
| bool isAccessibleIn(LibraryElement? library) { |
| if (Identifier.isPrivateName(name!)) { |
| return library == this.library; |
| } |
| return true; |
| } |
| |
| @override |
| bool isAccessibleIn2(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.enclosingElement3; |
| } |
| return element as E?; |
| } |
| |
| @override |
| E? thisOrAncestorOfType<E extends Element>() { |
| Element? element = this; |
| while (element != null && element is! E) { |
| if (element is CompilationUnitElement) { |
| element = element.enclosingElement3; |
| } else { |
| element = element.enclosingElement3; |
| } |
| } |
| 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.enclosingElement3; |
| } |
| _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 implements EnumElement { |
| 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(super.name, super.offset); |
| |
| @override |
| List<PropertyAccessorElement> get accessors { |
| return _accessors; |
| } |
| |
| @override |
| Never get augmentation { |
| // TODO(scheglov) implement |
| throw UnimplementedError(); |
| } |
| |
| @override |
| Never get augmented { |
| // TODO(scheglov) implement |
| throw UnimplementedError(); |
| } |
| |
| 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; |
| |
| @Deprecated('Not useful for clients') |
| @override |
| bool get hasStaticMember => true; |
| |
| @override |
| bool get isAbstract => false; |
| |
| @Deprecated('Use `is EnumElement` instead') |
| @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 |
| T? accept<T>(ElementVisitor<T> visitor) { |
| visitor.visitClassElement(this); |
| return visitor.visitEnumElement(this); |
| } |
| |
| @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 super.name, super.offset, {super.reference}); |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| Element get enclosingElement => super.enclosingElement2!; |
| |
| @Deprecated('Use enclosingElement3 instead') |
| @override |
| Element get enclosingElement2 => super.enclosingElement2!; |
| |
| @override |
| Element get enclosingElement3 => super.enclosingElement3!; |
| |
| @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 |
|