Linter Demo Errors: 0Warnings: 67File: /home/fstrocco/Dart/dart/benchmark/analyzer/lib/src/generated/element.dart // 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. // This code was auto-generated, is not intended to be edited, and is subject to // significant change. Please see the README file for more information. library engine.element; import 'dart:collection'; import 'package:analyzer/src/generated/utilities_general.dart'; import 'package:analyzer/task/model.dart' show AnalysisTarget; import 'ast.dart'; import 'constant.dart' show EvaluationResultImpl; import 'engine.dart' show AnalysisContext, AnalysisEngine, AnalysisException; import 'html.dart' show XmlAttributeNode, XmlTagNode; import 'java_core.dart'; import 'java_engine.dart'; import 'resolver.dart'; import 'scanner.dart' show Keyword; import 'sdk.dart' show DartSdk; import 'source.dart'; import 'utilities_collection.dart'; import 'utilities_dart.dart'; /** * For AST nodes that could be in both the getter and setter contexts * ([IndexExpression]s and [SimpleIdentifier]s), the additional resolved * elements are stored in the AST node, in an [AuxiliaryElements]. Because * resolved elements are either statically resolved or resolved using propagated * type information, this class is a wrapper for a pair of [ExecutableElement]s, * not just a single [ExecutableElement]. */ class AuxiliaryElements { /** * The element based on propagated type information, or `null` if the AST * structure has not been resolved or if the node could not be resolved. */ final ExecutableElement propagatedElement; /** * The element based on static type information, or `null` if the AST * structure has not been resolved or if the node could not be resolved. */ final ExecutableElement staticElement; /** * Initialize a newly created pair to have both the [staticElement] and the * [propagatedElement]. */ AuxiliaryElements(this.staticElement, this.propagatedElement); } /** * A [Type] that represents the type 'bottom'. */ class BottomTypeImpl extends TypeImpl { /** * The unique instance of this class. */ static BottomTypeImpl _INSTANCE = new BottomTypeImpl._(); /** * Return the unique instance of this class. */ static BottomTypeImpl get instance => _INSTANCE; /** * Prevent the creation of instances of this class. */ BottomTypeImpl._() : super(null, ""); @override int get hashCode => 0; @override bool get isBottom => true; @override bool operator ==(Object object) => identical(object, this); @override bool internalEquals(Object object, Set visitedElementPairs) => identical(object, this); @override int internalHashCode(List visitedTypes) => hashCode; @override bool isMoreSpecificThan(DartType type, [Set thisExpansions, Set typeExpansions, bool withDynamic = false, Set visitedElements]) => true; @override bool isSubtypeOf(DartType type, [Set thisExpansions, Set typeExpansions]) => true; @override bool isSupertypeOf(DartType type) => false; @override BottomTypeImpl substitute2( List argumentTypes, List parameterTypes) => this; } /** * An element that represents a class. */ abstract class ClassElement implements Element { /** * Return a list containing all of the accessors (getters and setters) * declared in this class. */ List get accessors; /** * Return a list containing all the supertypes defined for this class and its * supertypes. This includes superclasses, mixins and interfaces. */ List get allSupertypes; /** * Return a list containing all of the constructors declared in this class. */ List get constructors; /** * Return a list containing all of the fields declared in this class. */ List get fields; /** * Return `true` if this class or its superclass declares a non-final instance * field. */ bool get hasNonFinalField; /** * Return `true` if this class has reference to super (so, for example, cannot * be used as a mixin). */ bool get hasReferenceToSuper; /** * Return `true` if this class declares a static member. */ bool get hasStaticMember; /** * Return a list containing all of the interfaces that are implemented by this * class. * * Note: Because the element model represents the state of the code, it * is possible for it to be semantically invalid. In particular, it is not * safe to assume that the inheritance structure of a class does not contain a * cycle. Clients that traverse the inheritance structure must explicitly * guard against infinite loops. */ List get interfaces; /** * Return `true` if this class is abstract. A class is abstract if it has an * explicit `abstract` modifier. Note, that this definition of abstract * is different from has unimplemented members. */ bool get isAbstract; /** * Return `true` if this class is defined by an enum declaration. */ bool get isEnum; /** * Return `true` if this class [isProxy], or if it inherits the proxy * annotation from a supertype. */ bool get isOrInheritsProxy; /** * Return `true` if this element has an annotation of the form '@proxy'. */ bool get isProxy; /** * Return `true` if this class is defined by a typedef construct. */ bool get isTypedef; /** * Return `true` if this class can validly be used as a mixin when defining * another class. The behavior of this method is defined by the Dart Language * Specification in section 9: * * It is a compile-time error if a declared or derived mixin refers to super. * It is a compile-time error if a declared or derived mixin explicitly * declares a constructor. It is a compile-time error if a mixin is derived * from a class whose superclass is not Object. * */ bool get isValidMixin; /** * Return a list containing all of the methods declared in this class. */ List get methods; /** * Return a list containing all of the mixins that are applied to the class * being extended in order to derive the superclass of this class. * * Note: Because the element model represents the state of the code, it * is possible for it to be semantically invalid. In particular, it is not * safe to assume that the inheritance structure of a class does not contain a * cycle. Clients that traverse the inheritance structure must explicitly * guard against infinite loops. */ List get mixins; /** * Return the resolved [ClassDeclaration] or [EnumDeclaration] node that * declares this [ClassElement]. * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. */ @override NamedCompilationUnitMember get node; /** * Return the superclass of this class, or `null` if the class represents the * class 'Object'. All other classes will have a non-`null` superclass. If the * superclass was not explicitly declared then the implicit superclass * 'Object' will be returned. * * Note: Because the element model represents the state of the code, it * is possible for it to be semantically invalid. In particular, it is not * safe to assume that the inheritance structure of a class does not contain a * cycle. Clients that traverse the inheritance structure must explicitly * guard against infinite loops. */ InterfaceType get supertype; /** * Return the type defined by the class. */ InterfaceType get type; /** * Return a list containing all of the type parameters declared for this * class. */ List get typeParameters; /** * Return the unnamed constructor declared in this class, or `null` if this * class does not declare an unnamed constructor but does declare named * constructors. The returned constructor will be synthetic if this class does * not declare any constructors, in which case it will represent the default * constructor for the class. */ ConstructorElement get unnamedConstructor; /** * Return the field (synthetic or explicit) defined in this class that has the * given [name], or `null` if this class does not define a field with the * given name. */ FieldElement getField(String name); /** * Return the element representing the getter with the given [name] that is * declared in this class, or `null` if this class does not declare a getter * with the given name. */ PropertyAccessorElement getGetter(String name); /** * Return the element representing the method with the given [name] that is * declared in this class, or `null` if this class does not declare a method * with the given name. */ MethodElement getMethod(String name); /** * Return the named constructor declared in this class with the given [name], * or `null` if this class does not declare a named constructor with the given * name. */ ConstructorElement getNamedConstructor(String name); /** * Return the element representing the setter with the given [name] that is * declared in this class, or `null` if this class does not declare a setter * with the given name. */ PropertyAccessorElement getSetter(String name); /** * Determine whether the given [constructor], which exists in the superclass * of this class, is accessible to constructors in this class. */ bool isSuperConstructorAccessible(ConstructorElement constructor); /** * Return the element representing the method that results from looking up the * given [methodName] in this class with respect to the given [library], * ignoring abstract methods, or `null` if the look up fails. The behavior of * this method is defined by the Dart Language Specification in section * 16.15.1: * * The result of looking up method m in class C with respect to * library L is: If C declares an instance method named m * that is accessible to L, then that method is the result of the * lookup. Otherwise, if C has a superclass S, then the result * of the lookup is the result of looking up method m in S with * respect to L. Otherwise, we say that the lookup has failed. * */ MethodElement lookUpConcreteMethod(String methodName, LibraryElement library); /** * Return the element representing the getter that results from looking up the * given [getterName] in this class with respect to the given [library], or * `null` if the look up fails. The behavior of this method is defined by the * Dart Language Specification in section 16.15.2: * * The result of looking up getter (respectively setter) m in class * C with respect to library L is: If C declares an * instance getter (respectively setter) named m that is accessible to * L, then that getter (respectively setter) is the result of the * lookup. Otherwise, if C has a superclass S, then the result * of the lookup is the result of looking up getter (respectively setter) * m in S with respect to L. Otherwise, we say that the * lookup has failed. * */ PropertyAccessorElement lookUpGetter( String getterName, LibraryElement library); /** * Return the element representing the getter that results from looking up the * given [getterName] in the superclass of this class with respect to the * given [library], ignoring abstract getters, or `null` if the look up fails. * The behavior of this method is defined by the Dart Language Specification * in section 16.15.2: * * The result of looking up getter (respectively setter) m in class * C with respect to library L is: If C declares an * instance getter (respectively setter) named m that is accessible to * L, then that getter (respectively setter) is the result of the * lookup. Otherwise, if C has a superclass S, then the result * of the lookup is the result of looking up getter (respectively setter) * m in S with respect to L. Otherwise, we say that the * lookup has failed. * */ PropertyAccessorElement lookUpInheritedConcreteGetter( String getterName, LibraryElement library); /** * Return the element representing the method that results from looking up the * given [methodName] in the superclass of this class with respect to the * given [library], ignoring abstract methods, or `null` if the look up fails. * The behavior of this method is defined by the Dart Language Specification * in section 16.15.1: * * The result of looking up method m in class C with respect to * library L is: If C declares an instance method named * m that is accessible to L, then that method is the result of * the lookup. Otherwise, if C has a superclass S, then the * result of the lookup is the result of looking up method m in * S with respect to L. Otherwise, we say that the lookup has * failed. * */ MethodElement lookUpInheritedConcreteMethod( String methodName, LibraryElement library); /** * Return the element representing the setter that results from looking up the * given [setterName] in the superclass of this class with respect to the * given [library], ignoring abstract setters, or `null` if the look up fails. * The behavior of this method is defined by the Dart Language Specification * in section 16.15.2: * * The result of looking up getter (respectively setter) m in class * C with respect to library L is: If C declares an * instance getter (respectively setter) named m that is accessible to * L, then that getter (respectively setter) is the result of the * lookup. Otherwise, if C has a superclass S, then the result * of the lookup is the result of looking up getter (respectively setter) * m in S with respect to L. Otherwise, we say that the * lookup has failed. * */ PropertyAccessorElement lookUpInheritedConcreteSetter( String setterName, LibraryElement library); /** * Return the element representing the method that results from looking up the * given [methodName] in the superclass of this class with respect to the * given [library], or `null` if the look up fails. The behavior of this * method is defined by the Dart Language Specification in section 16.15.1: * * The result of looking up method m in class C with respect to * library L is: If C declares an instance method named * m that is accessible to L, then that method is the result of * the lookup. Otherwise, if C has a superclass S, then the * result of the lookup is the result of looking up method m in * S with respect to L. Otherwise, we say that the lookup has * failed. * */ MethodElement lookUpInheritedMethod( String methodName, LibraryElement library); /** * Return the element representing the method that results from looking up the * given [methodName] in this class with respect to the given [library], or * `null` if the look up fails. The behavior of this method is defined by the * Dart Language Specification in section 16.15.1: * * The result of looking up method m in class C with respect to * library L is: If C declares an instance method named * m that is accessible to L, then that method is the result of * the lookup. Otherwise, if C has a superclass S, then the * result of the lookup is the result of looking up method m in * S with respect to L. Otherwise, we say that the lookup has * failed. * */ MethodElement lookUpMethod(String methodName, LibraryElement library); /** * Return the element representing the setter that results from looking up the * given [setterName] in this class with respect to the given [library], or * `null` if the look up fails. The behavior of this method is defined by the * Dart Language Specification in section 16.15.2: * * The result of looking up getter (respectively setter) m in class * C with respect to library L is: If C declares an * instance getter (respectively setter) named m that is accessible to * L, then that getter (respectively setter) is the result of the * lookup. Otherwise, if C has a superclass S, then the result * of the lookup is the result of looking up getter (respectively setter) * m in S with respect to L. Otherwise, we say that the * lookup has failed. * */ PropertyAccessorElement lookUpSetter( String setterName, LibraryElement library); } /** * A concrete implementation of a [ClassElement]. */ class ClassElementImpl extends ElementImpl implements ClassElement { /** * An empty list of class elements. */ static const List EMPTY_ARRAY = const []; /** * A list containing all of the accessors (getters and setters) contained in * this class. */ List _accessors = PropertyAccessorElementImpl.EMPTY_ARRAY; /** * A list containing all of the constructors contained in this class. */ List _constructors = ConstructorElementImpl.EMPTY_ARRAY; /** * A list containing all of the fields contained in this class. */ List _fields = FieldElementImpl.EMPTY_ARRAY; /** * 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 mixins = InterfaceType.EMPTY_ARRAY; /** * A list containing all of the interfaces that are implemented by this class. */ List interfaces = InterfaceType.EMPTY_ARRAY; /** * A list containing all of the methods contained in this class. */ List _methods = MethodElementImpl.EMPTY_ARRAY; /** * The superclass of the class, or `null` if the class does not have an * explicit superclass. */ InterfaceType supertype; /** * The type defined by the class. */ InterfaceType type; /** * A list containing all of the type parameters defined for this class. */ List _typeParameters = TypeParameterElementImpl.EMPTY_ARRAY; /** * The [SourceRange] of the `with` clause, `null` if there is no one. */ SourceRange withClauseRange; /** * Initialize a newly created class element to have the given [name] at the * given [offset] in the file that contains the declaration of this element. */ ClassElementImpl(String name, int offset) : super(name, offset); /** * Initialize a newly created class element to have the given [name]. */ ClassElementImpl.forNode(Identifier name) : super.forNode(name); /** * Set whether this class is abstract. */ void set abstract(bool isAbstract) { setModifier(Modifier.ABSTRACT, isAbstract); } @override List get accessors => _accessors; /** * Set the accessors contained in this class to the given [accessors]. */ void set accessors(List accessors) { for (PropertyAccessorElement accessor in accessors) { (accessor as PropertyAccessorElementImpl).enclosingElement = this; } this._accessors = accessors; } @override List get allSupertypes { List list = new List(); _collectAllSupertypes(list); return list; } @override List get constructors => _constructors; /** * Set the constructors contained in this class to the given [constructors]. */ void set constructors(List constructors) { for (ConstructorElement constructor in constructors) { (constructor as ConstructorElementImpl).enclosingElement = this; } this._constructors = constructors; } /** * Set whether this class is defined by an enum declaration. */ void set enum2(bool isEnum) { setModifier(Modifier.ENUM, isEnum); } @override List get fields => _fields; /** * Set the fields contained in this class to the given [fields]. */ void set fields(List fields) { for (FieldElement field in fields) { (field as FieldElementImpl).enclosingElement = this; } this._fields = fields; } @override bool get hasNonFinalField { List classesToVisit = new List(); HashSet visitedClasses = new HashSet(); classesToVisit.add(this); while (!classesToVisit.isEmpty) { ClassElement currentElement = classesToVisit.removeAt(0); if (visitedClasses.add(currentElement)) { // check fields for (FieldElement field in currentElement.fields) { if (!field.isFinal && !field.isConst && !field.isStatic && !field.isSynthetic) { return true; } } // check mixins for (InterfaceType mixinType in currentElement.mixins) { ClassElement mixinElement = mixinType.element; classesToVisit.add(mixinElement); } // check super InterfaceType supertype = currentElement.supertype; if (supertype != null) { ClassElement superElement = supertype.element; if (superElement != null) { classesToVisit.add(superElement); } } } } // not found return false; } @override bool get hasReferenceToSuper => hasModifier(Modifier.REFERENCES_SUPER); /** * Set whether this class references 'super'. */ void set hasReferenceToSuper(bool isReferencedSuper) { setModifier(Modifier.REFERENCES_SUPER, isReferencedSuper); } @override bool get hasStaticMember { for (MethodElement method in _methods) { if (method.isStatic) { return true; } } for (PropertyAccessorElement accessor in _accessors) { if (accessor.isStatic) { return true; } } return false; } @override bool get isAbstract => hasModifier(Modifier.ABSTRACT); @override bool get isEnum => hasModifier(Modifier.ENUM); @override bool get isOrInheritsProxy => _safeIsOrInheritsProxy(this, new HashSet()); @override bool get isProxy { for (ElementAnnotation annotation in metadata) { if (annotation.isProxy) { return true; } } return false; } @override bool get isTypedef => hasModifier(Modifier.TYPEDEF); @override bool get isValidMixin => hasModifier(Modifier.MIXIN); @override ElementKind get kind => ElementKind.CLASS; @override List get methods => _methods; /** * Set the methods contained in this class to the given [methods]. */ void set methods(List methods) { for (MethodElement method in methods) { (method as MethodElementImpl).enclosingElement = this; } this._methods = methods; } bool get mixinErrorsReported => hasModifier(Modifier.MIXIN_ERRORS_REPORTED); /** * Set whether an error has reported explaining why this class is an * invalid mixin application. */ void set mixinErrorsReported(bool value) { setModifier(Modifier.MIXIN_ERRORS_REPORTED, value); } @override NamedCompilationUnitMember get node { if (isEnum) { return getNodeMatching((node) => node is EnumDeclaration); } else { return getNodeMatching( (node) => node is ClassDeclaration || node is ClassTypeAlias); } } /** * Set whether this class is defined by a typedef construct. */ void set typedef(bool isTypedef) { setModifier(Modifier.TYPEDEF, isTypedef); } @override List get typeParameters => _typeParameters; /** * Set the type parameters defined for this class to the given * [typeParameters]. */ void set typeParameters(List typeParameters) { for (TypeParameterElement typeParameter in typeParameters) { (typeParameter as TypeParameterElementImpl).enclosingElement = this; } this._typeParameters = typeParameters; } @override ConstructorElement get unnamedConstructor { for (ConstructorElement element in constructors) { String name = element.displayName; if (name == null || name.isEmpty) { return element; } } return null; } /** * Set whether this class is a valid mixin. */ void set validMixin(bool isValidMixin) { setModifier(Modifier.MIXIN, isValidMixin); } @override accept(ElementVisitor visitor) => visitor.visitClassElement(this); @override void appendTo(StringBuffer buffer) { String name = displayName; if (name == null) { buffer.write("{unnamed class}"); } else { buffer.write(name); } int variableCount = _typeParameters.length; if (variableCount > 0) { buffer.write("<"); for (int i = 0; i < variableCount; i++) { if (i > 0) { buffer.write(", "); } (_typeParameters[i] as TypeParameterElementImpl).appendTo(buffer); } buffer.write(">"); } } @override ElementImpl getChild(String identifier) { // // The casts in this method are safe because the set methods would have // thrown a CCE if any of the elements in the arrays were not of the // expected types. // for (PropertyAccessorElement accessor in _accessors) { if ((accessor as PropertyAccessorElementImpl).identifier == identifier) { return accessor as PropertyAccessorElementImpl; } } for (ConstructorElement constructor in _constructors) { if ((constructor as ConstructorElementImpl).identifier == identifier) { return constructor as ConstructorElementImpl; } } for (FieldElement field in _fields) { if ((field as FieldElementImpl).identifier == identifier) { return field as FieldElementImpl; } } for (MethodElement method in _methods) { if ((method as MethodElementImpl).identifier == identifier) { return method as MethodElementImpl; } } for (TypeParameterElement typeParameter in _typeParameters) { if ((typeParameter as TypeParameterElementImpl).identifier == identifier) { return typeParameter as TypeParameterElementImpl; } } return null; } @override FieldElement getField(String name) { for (FieldElement fieldElement in _fields) { if (name == fieldElement.name) { return fieldElement; } } return null; } @override PropertyAccessorElement getGetter(String getterName) { for (PropertyAccessorElement accessor in _accessors) { if (accessor.isGetter && accessor.name == getterName) { return accessor; } } return null; } @override MethodElement getMethod(String methodName) { for (MethodElement method in _methods) { if (method.name == methodName) { return method; } } return null; } @override ConstructorElement getNamedConstructor(String name) { for (ConstructorElement element in constructors) { String elementName = element.name; if (elementName != null && elementName == name) { return element; } } return null; } @override PropertyAccessorElement getSetter(String setterName) { // TODO (jwren) revisit- should we append '=' here or require clients to // include it? // Do we need the check for isSetter below? if (!StringUtilities.endsWithChar(setterName, 0x3D)) { setterName += '='; } for (PropertyAccessorElement accessor in _accessors) { if (accessor.isSetter && accessor.name == setterName) { return accessor; } } return null; } @override bool isSuperConstructorAccessible(ConstructorElement constructor) { // If this class has no mixins, then all superclass constructors are // accessible. if (mixins.isEmpty) { return true; } // Otherwise only constructors that lack optional parameters are // accessible (see dartbug.com/19576). for (ParameterElement parameter in constructor.parameters) { if (parameter.parameterKind != ParameterKind.REQUIRED) { return false; } } return true; } @override MethodElement lookUpConcreteMethod( String methodName, LibraryElement library) => _internalLookUpConcreteMethod(methodName, library, true); @override PropertyAccessorElement lookUpGetter( String getterName, LibraryElement library) => _internalLookUpGetter(getterName, library, true); @override PropertyAccessorElement lookUpInheritedConcreteGetter( String getterName, LibraryElement library) => _internalLookUpConcreteGetter(getterName, library, false); @override MethodElement lookUpInheritedConcreteMethod( String methodName, LibraryElement library) => _internalLookUpConcreteMethod(methodName, library, false); @override PropertyAccessorElement lookUpInheritedConcreteSetter( String setterName, LibraryElement library) => _internalLookUpConcreteSetter(setterName, library, false); @override MethodElement lookUpInheritedMethod( String methodName, LibraryElement library) => _internalLookUpMethod(methodName, library, false); @override MethodElement lookUpMethod(String methodName, LibraryElement library) => _internalLookUpMethod(methodName, library, true); @override PropertyAccessorElement lookUpSetter( String setterName, LibraryElement library) => _internalLookUpSetter(setterName, library, true); @override void visitChildren(ElementVisitor visitor) { super.visitChildren(visitor); safelyVisitChildren(_accessors, visitor); safelyVisitChildren(_constructors, visitor); safelyVisitChildren(_fields, visitor); safelyVisitChildren(_methods, visitor); safelyVisitChildren(_typeParameters, visitor); } void _collectAllSupertypes(List supertypes) { List typesToVisit = new List(); List visitedClasses = new List(); typesToVisit.add(this.type); while (!typesToVisit.isEmpty) { InterfaceType currentType = typesToVisit.removeAt(0); ClassElement currentElement = currentType.element; if (!visitedClasses.contains(currentElement)) { visitedClasses.add(currentElement); if (!identical(currentType, this.type)) { supertypes.add(currentType); } InterfaceType supertype = currentType.superclass; if (supertype != null) { typesToVisit.add(supertype); } for (InterfaceType type in currentElement.interfaces) { typesToVisit.add(type); } for (InterfaceType type in currentElement.mixins) { ClassElement element = type.element; if (!visitedClasses.contains(element)) { supertypes.add(type); } } } } } PropertyAccessorElement _internalLookUpConcreteGetter( String getterName, LibraryElement library, bool includeThisClass) { PropertyAccessorElement getter = _internalLookUpGetter(getterName, library, includeThisClass); while (getter != null && getter.isAbstract) { Element definingClass = getter.enclosingElement; if (definingClass is! ClassElementImpl) { return null; } getter = (definingClass as ClassElementImpl)._internalLookUpGetter( getterName, library, false); } return getter; } MethodElement _internalLookUpConcreteMethod( String methodName, LibraryElement library, bool includeThisClass) { MethodElement method = _internalLookUpMethod(methodName, library, includeThisClass); while (method != null && method.isAbstract) { ClassElement definingClass = method.enclosingElement; if (definingClass == null) { return null; } method = definingClass.lookUpInheritedMethod(methodName, library); } return method; } PropertyAccessorElement _internalLookUpConcreteSetter( String setterName, LibraryElement library, bool includeThisClass) { PropertyAccessorElement setter = _internalLookUpSetter(setterName, library, includeThisClass); while (setter != null && setter.isAbstract) { Element definingClass = setter.enclosingElement; if (definingClass is! ClassElementImpl) { return null; } setter = (definingClass as ClassElementImpl)._internalLookUpSetter( setterName, library, false); } return setter; } PropertyAccessorElement _internalLookUpGetter( String getterName, LibraryElement library, bool includeThisClass) { HashSet visitedClasses = new HashSet(); ClassElement currentElement = this; if (includeThisClass) { PropertyAccessorElement element = currentElement.getGetter(getterName); if (element != null && element.isAccessibleIn(library)) { return element; } } while (currentElement != null && visitedClasses.add(currentElement)) { for (InterfaceType mixin in currentElement.mixins.reversed) { ClassElement mixinElement = mixin.element; if (mixinElement != null) { PropertyAccessorElement element = mixinElement.getGetter(getterName); if (element != null && element.isAccessibleIn(library)) { return element; } } } InterfaceType supertype = currentElement.supertype; if (supertype == null) { return null; } currentElement = supertype.element; PropertyAccessorElement element = currentElement.getGetter(getterName); if (element != null && element.isAccessibleIn(library)) { return element; } } return null; } MethodElement _internalLookUpMethod( String methodName, LibraryElement library, bool includeThisClass) { HashSet visitedClasses = new HashSet(); ClassElement currentElement = this; if (includeThisClass) { MethodElement element = currentElement.getMethod(methodName); if (element != null && element.isAccessibleIn(library)) { return element; } } while (currentElement != null && visitedClasses.add(currentElement)) { for (InterfaceType mixin in currentElement.mixins.reversed) { ClassElement mixinElement = mixin.element; if (mixinElement != null) { MethodElement element = mixinElement.getMethod(methodName); if (element != null && element.isAccessibleIn(library)) { return element; } } } InterfaceType supertype = currentElement.supertype; if (supertype == null) { return null; } currentElement = supertype.element; MethodElement element = currentElement.getMethod(methodName); if (element != null && element.isAccessibleIn(library)) { return element; } } return null; } PropertyAccessorElement _internalLookUpSetter( String setterName, LibraryElement library, bool includeThisClass) { HashSet visitedClasses = new HashSet(); ClassElement currentElement = this; if (includeThisClass) { PropertyAccessorElement element = currentElement.getSetter(setterName); if (element != null && element.isAccessibleIn(library)) { return element; } } while (currentElement != null && visitedClasses.add(currentElement)) { for (InterfaceType mixin in currentElement.mixins.reversed) { ClassElement mixinElement = mixin.element; if (mixinElement != null) { PropertyAccessorElement element = mixinElement.getSetter(setterName); if (element != null && element.isAccessibleIn(library)) { return element; } } } InterfaceType supertype = currentElement.supertype; if (supertype == null) { return null; } currentElement = supertype.element; PropertyAccessorElement element = currentElement.getSetter(setterName); if (element != null && element.isAccessibleIn(library)) { return element; } } return null; } bool _safeIsOrInheritsProxy( ClassElement classElt, HashSet visitedClassElts) { if (visitedClassElts.contains(classElt)) { return false; } visitedClassElts.add(classElt); if (classElt.isProxy) { return true; } else if (classElt.supertype != null && _safeIsOrInheritsProxy(classElt.supertype.element, visitedClassElts)) { return true; } List supertypes = classElt.interfaces; for (int i = 0; i < supertypes.length; i++) { if (_safeIsOrInheritsProxy(supertypes[i].element, visitedClassElts)) { return true; } } supertypes = classElt.mixins; for (int i = 0; i < supertypes.length; i++) { if (_safeIsOrInheritsProxy(supertypes[i].element, visitedClassElts)) { return true; } } return false; } } /** * An element that is contained within a [ClassElement]. */ abstract class ClassMemberElement implements Element { /** * Return the type in which this member is defined. */ @override ClassElement get enclosingElement; /** * Return `true` if this element is a static element. A static element is an * element that is not associated with a particular instance, but rather with * an entire library or class. */ bool get isStatic; } /** * An element representing a compilation unit. */ abstract class CompilationUnitElement implements Element, UriReferencedElement { /** * Return a list containing all of the top-level accessors (getters and * setters) contained in this compilation unit. */ List get accessors; /** * Return the library in which this compilation unit is defined. */ @override LibraryElement get enclosingElement; /** * Return a list containing all of the enums contained in this compilation * unit. */ List get enums; /** * Return a list containing all of the top-level functions contained in this * compilation unit. */ List get functions; /** * Return a list containing all of the function type aliases contained in this * compilation unit. */ List get functionTypeAliases; /** * Return `true` if this compilation unit defines a top-level function named * `loadLibrary`. */ bool get hasLoadLibraryFunction; /** * Return the resolved [CompilationUnit] node that declares this element. * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. */ @override CompilationUnit get node; /** * Return a list containing all of the top-level variables contained in this * compilation unit. */ List get topLevelVariables; /** * Return a list containing all of the classes contained in this compilation * unit. */ List get types; /** * Return the enum defined in this compilation unit that has the given [name], * or `null` if this compilation unit does not define an enum with the given * name. */ ClassElement getEnum(String name); /** * Return the class defined in this compilation unit that has the given * [name], or `null` if this compilation unit does not define a class with the * given name. */ ClassElement getType(String name); } /** * A concrete implementation of a [CompilationUnitElement]. */ class CompilationUnitElementImpl extends UriReferencedElementImpl implements CompilationUnitElement { /** * An empty list of compilation unit elements. */ static const List EMPTY_ARRAY = const []; /** * The source that corresponds to this compilation unit. */ Source source; /** * A list containing all of the top-level accessors (getters and setters) * contained in this compilation unit. */ List _accessors = PropertyAccessorElementImpl.EMPTY_ARRAY; /** * A list containing all of the enums contained in this compilation unit. */ List _enums = ClassElementImpl.EMPTY_ARRAY; /** * A list containing all of the top-level functions contained in this * compilation unit. */ List _functions = FunctionElementImpl.EMPTY_ARRAY; /** * A list containing all of the function type aliases contained in this * compilation unit. */ List _typeAliases = FunctionTypeAliasElementImpl.EMPTY_ARRAY; /** * A list containing all of the types contained in this compilation unit. */ List _types = ClassElementImpl.EMPTY_ARRAY; /** * A list containing all of the variables contained in this compilation unit. */ List _variables = TopLevelVariableElementImpl.EMPTY_ARRAY; /** * Initialize a newly created compilation unit element to have the given * [name]. */ CompilationUnitElementImpl(String name) : super(name, -1); @override List get accessors => _accessors; /** * Set the top-level accessors (getters and setters) contained in this * compilation unit to the given [accessors]. */ void set accessors(List accessors) { for (PropertyAccessorElement accessor in accessors) { (accessor as PropertyAccessorElementImpl).enclosingElement = this; } this._accessors = accessors; } @override LibraryElement get enclosingElement => super.enclosingElement as LibraryElement; @override List get enums => _enums; /** * Set the enums contained in this compilation unit to the given [enums]. */ void set enums(List enums) { for (ClassElement enumDeclaration in enums) { (enumDeclaration as ClassElementImpl).enclosingElement = this; } this._enums = enums; } @override List get functions => _functions; /** * Set the top-level functions contained in this compilation unit to the given * [functions]. */ void set functions(List functions) { for (FunctionElement function in functions) { (function as FunctionElementImpl).enclosingElement = this; } this._functions = functions; } @override List get functionTypeAliases => _typeAliases; @override int get hashCode => source.hashCode; @override bool get hasLoadLibraryFunction { for (int i = 0; i < _functions.length; i++) { if (_functions[i].name == FunctionElement.LOAD_LIBRARY_NAME) { return true; } } return false; } @override String get identifier => source.encoding; @override ElementKind get kind => ElementKind.COMPILATION_UNIT; @override CompilationUnit get node => unit; @override List get topLevelVariables => _variables; /** * Set the top-level variables contained in this compilation unit to the given * [variables]. */ void set topLevelVariables(List variables) { for (TopLevelVariableElement field in variables) { (field as TopLevelVariableElementImpl).enclosingElement = this; } this._variables = variables; } /** * Set the function type aliases contained in this compilation unit to the * given [typeAliases]. */ void set typeAliases(List typeAliases) { for (FunctionTypeAliasElement typeAlias in typeAliases) { (typeAlias as FunctionTypeAliasElementImpl).enclosingElement = this; } this._typeAliases = typeAliases; } @override List get types => _types; /** * Set the types contained in this compilation unit to the given [types]. */ void set types(List types) { for (ClassElement type in types) { (type as ClassElementImpl).enclosingElement = this; } this._types = types; } @override bool operator ==(Object object) => object is CompilationUnitElementImpl && source == object.source; @override accept(ElementVisitor visitor) => visitor.visitCompilationUnitElement(this); @override void appendTo(StringBuffer buffer) { if (source == null) { buffer.write("{compilation unit}"); } else { buffer.write(source.fullName); } } @override ElementImpl getChild(String identifier) { // // The casts in this method are safe because the set methods would have // thrown a CCE if any of the elements in the arrays were not of the // expected types. // for (PropertyAccessorElement accessor in _accessors) { if ((accessor as PropertyAccessorElementImpl).identifier == identifier) { return accessor as PropertyAccessorElementImpl; } } for (VariableElement variable in _variables) { if ((variable as VariableElementImpl).identifier == identifier) { return variable as VariableElementImpl; } } for (ExecutableElement function in _functions) { if ((function as ExecutableElementImpl).identifier == identifier) { return function as ExecutableElementImpl; } } for (FunctionTypeAliasElement typeAlias in _typeAliases) { if ((typeAlias as FunctionTypeAliasElementImpl).identifier == identifier) { return typeAlias as FunctionTypeAliasElementImpl; } } for (ClassElement type in _types) { if ((type as ClassElementImpl).identifier == identifier) { return type as ClassElementImpl; } } for (ClassElement type in _enums) { if ((type as ClassElementImpl).identifier == identifier) { return type as ClassElementImpl; } } return null; } @override ClassElement getEnum(String enumName) { for (ClassElement enumDeclaration in _enums) { if (enumDeclaration.name == enumName) { return enumDeclaration; } } return null; } @override ClassElement getType(String className) { for (ClassElement type in _types) { if (type.name == className) { return type; } } return null; } /** * Replace the given [from] top-level variable with [to] in this compilation unit. */ void replaceTopLevelVariable( TopLevelVariableElement from, TopLevelVariableElement to) { int index = _variables.indexOf(from); _variables[index] = to; } @override void visitChildren(ElementVisitor visitor) { super.visitChildren(visitor); safelyVisitChildren(_accessors, visitor); safelyVisitChildren(_enums, visitor); safelyVisitChildren(_functions, visitor); safelyVisitChildren(_typeAliases, visitor); safelyVisitChildren(_types, visitor); safelyVisitChildren(_variables, visitor); } } /** * A [FieldElement] for a 'const' field that has an initializer. */ class ConstFieldElementImpl extends FieldElementImpl with ConstVariableElement { /** * The result of evaluating this variable's initializer. */ EvaluationResultImpl _result; /** * Initialize a newly created field element to have the given [name]. */ ConstFieldElementImpl.con1(Identifier name) : super.forNode(name); /** * Initialize a newly created synthetic field element to have the given * [name] and [offset]. */ ConstFieldElementImpl.con2(String name, int offset) : super(name, offset); @override EvaluationResultImpl get evaluationResult => _result; @override void set evaluationResult(EvaluationResultImpl result) { this._result = result; } } /** * A [LocalVariableElement] for a local 'const' variable that has an * initializer. */ class ConstLocalVariableElementImpl extends LocalVariableElementImpl with ConstVariableElement { /** * The result of evaluating this variable's initializer. */ EvaluationResultImpl _result; /** * Initialize a newly created local variable element to have the given [name] * and [offset]. */ ConstLocalVariableElementImpl(String name, int offset) : super(name, offset); /** * Initialize a newly created local variable element to have the given [name]. */ ConstLocalVariableElementImpl.forNode(Identifier name) : super.forNode(name); @override EvaluationResultImpl get evaluationResult => _result; @override void set evaluationResult(EvaluationResultImpl result) { this._result = result; } } /** * An element representing a constructor or a factory method defined within a * class. */ abstract class ConstructorElement implements ClassMemberElement, ExecutableElement { /** * Return `true` if this constructor is a const constructor. */ bool get isConst; /** * Return `true` if this constructor can be used as a default constructor - * unnamed and has no required parameters. */ bool get isDefaultConstructor; /** * Return `true` if this constructor represents a factory constructor. */ bool get isFactory; /** * Return the offset of the character immediately following the last character * of this constructor's name, or `null` if not named. */ int get nameEnd; /** * Return the resolved [ConstructorDeclaration] node that declares this * [ConstructorElement] . * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. */ @override ConstructorDeclaration get node; /** * Return the offset of the `.` before this constructor name, or `null` if * not named. */ int get periodOffset; /** * Return the constructor to which this constructor is redirecting, or `null` * if this constructor does not redirect to another constructor or if the * library containing this constructor has not yet been resolved. */ ConstructorElement get redirectedConstructor; } /** * A concrete implementation of a [ConstructorElement]. */ class ConstructorElementImpl extends ExecutableElementImpl implements ConstructorElement { /** * An empty list of constructor elements. */ static const List EMPTY_ARRAY = const []; /** * The constructor to which this constructor is redirecting. */ ConstructorElement redirectedConstructor; /** * The initializers for this constructor (used for evaluating constant * instance creation expressions). */ List constantInitializers; /** * The offset of the `.` before this constructor name or `null` if not named. */ int periodOffset; /** * Return the offset of the character immediately following the last character * of this constructor's name, or `null` if not named. */ int nameEnd; /** * True if this constructor has been found by constant evaluation to be free * of redirect cycles, and is thus safe to evaluate. */ bool isCycleFree = false; /** * Initialize a newly created constructor element to have the given [name] and * [offset]. */ ConstructorElementImpl(String name, int offset) : super(name, offset); /** * Initialize a newly created constructor element to have the given [name]. */ ConstructorElementImpl.forNode(Identifier name) : super.forNode(name); /** * Set whether this constructor represents a 'const' constructor. */ void set const2(bool isConst) { setModifier(Modifier.CONST, isConst); } @override ClassElement get enclosingElement => super.enclosingElement as ClassElement; /** * Set whether this constructor represents a factory method. */ void set factory(bool isFactory) { setModifier(Modifier.FACTORY, isFactory); } @override bool get isConst => hasModifier(Modifier.CONST); @override bool get isDefaultConstructor { // unnamed String name = this.name; if (name != null && name.length != 0) { return false; } // no required parameters for (ParameterElement parameter in parameters) { if (parameter.parameterKind == ParameterKind.REQUIRED) { return false; } } // OK, can be used as default constructor return true; } @override bool get isFactory => hasModifier(Modifier.FACTORY); @override bool get isStatic => false; @override ElementKind get kind => ElementKind.CONSTRUCTOR; @override ConstructorDeclaration get node => getNodeMatching((node) => node is ConstructorDeclaration); @override accept(ElementVisitor visitor) => visitor.visitConstructorElement(this); @override void appendTo(StringBuffer buffer) { if (enclosingElement == null) { String message; String name = displayName; if (name != null && !name.isEmpty) { message = 'Found constructor element named $name with no enclosing element'; } else { message = 'Found unnamed constructor element with no enclosing element'; } AnalysisEngine.instance.logger.logError(message); buffer.write(''); } else { buffer.write(enclosingElement.displayName); } String name = displayName; if (name != null && !name.isEmpty) { buffer.write("."); buffer.write(name); } super.appendTo(buffer); } } /** * A constructor element defined in a parameterized type where the values of the * type parameters are known. */ class ConstructorMember extends ExecutableMember implements ConstructorElement { /** * Initialize a newly created element to represent a constructor, based on the * [baseElement], defined by the [definingType]. */ ConstructorMember(ConstructorElement baseElement, InterfaceType definingType) : super(baseElement, definingType); @override ConstructorElement get baseElement => super.baseElement as ConstructorElement; @override InterfaceType get definingType => super.definingType as InterfaceType; @override ClassElement get enclosingElement => baseElement.enclosingElement; @override bool get isConst => baseElement.isConst; @override bool get isDefaultConstructor => baseElement.isDefaultConstructor; @override bool get isFactory => baseElement.isFactory; @override int get nameEnd => baseElement.nameEnd; @override ConstructorDeclaration get node => baseElement.node; @override int get periodOffset => baseElement.periodOffset; @override ConstructorElement get redirectedConstructor => from(baseElement.redirectedConstructor, definingType); @override accept(ElementVisitor visitor) => visitor.visitConstructorElement(this); @override String toString() { ConstructorElement baseElement = this.baseElement; List parameters = this.parameters; FunctionType type = this.type; StringBuffer buffer = new StringBuffer(); buffer.write(baseElement.enclosingElement.displayName); String name = displayName; if (name != null && !name.isEmpty) { buffer.write("."); buffer.write(name); } buffer.write("("); int parameterCount = parameters.length; for (int i = 0; i < parameterCount; i++) { if (i > 0) { buffer.write(", "); } buffer.write(parameters[i]); } buffer.write(")"); if (type != null) { buffer.write(Element.RIGHT_ARROW); buffer.write(type.returnType); } return buffer.toString(); } /** * If the given [constructor]'s type is different when any type parameters * from the defining type's declaration are replaced with the actual type * arguments from the [definingType], create a constructor member representing * the given constructor. Return the member that was created, or the original * constructor if no member was created. */ static ConstructorElement from( ConstructorElement constructor, InterfaceType definingType) { if (constructor == null || definingType.typeArguments.length == 0) { return constructor; } FunctionType baseType = constructor.type; if (baseType == null) { // TODO(brianwilkerson) We need to understand when this can happen. return constructor; } List argumentTypes = definingType.typeArguments; List parameterTypes = definingType.element.type.typeArguments; FunctionType substitutedType = baseType.substitute2(argumentTypes, parameterTypes); if (baseType == substitutedType) { return constructor; } // TODO(brianwilkerson) Consider caching the substituted type in the // instance. It would use more memory but speed up some operations. // We need to see how often the type is being re-computed. return new ConstructorMember(constructor, definingType); } } /** * A [TopLevelVariableElement] for a top-level 'const' variable that has an * initializer. */ class ConstTopLevelVariableElementImpl extends TopLevelVariableElementImpl with ConstVariableElement { /** * The result of evaluating this variable's initializer. */ EvaluationResultImpl _result; /** * Initialize a newly created top-level variable element to have the given * [name]. */ ConstTopLevelVariableElementImpl(Identifier name) : super.forNode(name); @override EvaluationResultImpl get evaluationResult => _result; @override void set evaluationResult(EvaluationResultImpl result) { this._result = result; } } /** * Mixin used by elements that represent constant variables and have * initializers. * * Note that in correct Dart code, all constant variables must have * initializers. However, analyzer also needs to handle incorrect Dart code, * in which case there might be some constant variables that lack initializers. * This interface is only used for constant variables that have initializers. * * This class is not intended to be part of the public API for analyzer. */ abstract class ConstVariableElement implements PotentiallyConstVariableElement { /** * 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; } /** * The type associated with elements in the element model. */ abstract class DartType { /** * Return the name of this type as it should appear when presented to users in * contexts such as error messages. */ String get displayName; /** * Return the element representing the declaration of this type, or `null` if * the type has not, or cannot, be associated with an element. The former case * will occur if the element model is not yet complete; the latter case will * occur if this object represents an undefined type. */ Element get element; /** * Return `true` if this type represents the bottom type. */ bool get isBottom; /** * Return `true` if this type represents the type 'Function' defined in the * dart:core library. */ bool get isDartCoreFunction; /** * Return `true` if this type represents the type 'dynamic'. */ bool get isDynamic; /** * Return `true` if this type represents the type 'Object'. */ bool get isObject; /** * Return `true` if this type represents a typename that couldn't be resolved. */ bool get isUndefined; /** * Return `true` if this type represents the type 'void'. */ bool get isVoid; /** * Return the name of this type, or `null` if the type does not have a name, * such as when the type represents the type of an unnamed function. */ String get name; /** * Return the least upper bound of this type and the given [type], or `null` * if there is no least upper bound. */ DartType getLeastUpperBound(DartType type); /** * Return `true` if this type is assignable to the given [type]. A type * T may be assigned to a type S, written T ⇔ * S, iff either T <: S or S <: T. */ bool isAssignableTo(DartType type); /** * Return `true` if this type is more specific than the given [type]. */ bool isMoreSpecificThan(DartType type); /** * Return `true` if this type is a subtype of the given [type]. */ bool isSubtypeOf(DartType type); /** * Return `true` if this type is a supertype of the given [type]. A type * S is a supertype of T, written S :> T, iff * T is a subtype of S. */ bool isSupertypeOf(DartType type); /** * Return the type resulting from substituting the given [argumentTypes] for * the given [parameterTypes] in this type. The specification defines this * operation in section 2: * * The notation [x1, ..., xn/y1, ..., * yn]E denotes a copy of E in which all occurrences of * yi, 1 <= i <= n have been replaced with * xi. * * Note that, contrary to the specification, this method will not create a * copy of this type if no substitutions were required, but will return this * type directly. * * Note too that the current implementation of this method is only guaranteed * to work when the argument types are type variables. */ DartType substitute2( List argumentTypes, List parameterTypes); } /** * A [FieldFormalParameterElementImpl] for parameters that have an initializer. */ class DefaultFieldFormalParameterElementImpl extends FieldFormalParameterElementImpl { /** * The result of evaluating this variable's initializer. */ EvaluationResultImpl _result; /** * Initialize a newly created parameter element to have the given [name]. */ DefaultFieldFormalParameterElementImpl(Identifier name) : super(name); @override EvaluationResultImpl get evaluationResult => _result; @override void set evaluationResult(EvaluationResultImpl result) { this._result = result; } } /** * A [ParameterElement] for parameters that have an initializer. */ class DefaultParameterElementImpl extends ParameterElementImpl { /** * The result of evaluating this variable's initializer. */ EvaluationResultImpl _result; /** * Initialize a newly created parameter element to have the given [name]. */ DefaultParameterElementImpl(Identifier name) : super.forNode(name); @override EvaluationResultImpl get evaluationResult => _result; @override void set evaluationResult(EvaluationResultImpl result) { this._result = result; } } /** * The synthetic element representing the declaration of the type `dynamic`. */ class DynamicElementImpl extends ElementImpl { /** * Return the unique instance of this class. */ static DynamicElementImpl get instance => DynamicTypeImpl.instance.element as DynamicElementImpl; /** * The type defined by this element. */ DynamicTypeImpl type; /** * Initialize a newly created instance of this class. Instances of this class * should not 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 [getInstance]. */ DynamicElementImpl() : super(Keyword.DYNAMIC.syntax, -1) { setModifier(Modifier.SYNTHETIC, true); } @override ElementKind get kind => ElementKind.DYNAMIC; @override accept(ElementVisitor visitor) => null; } /** * The [Type] representing the type `dynamic`. */ class DynamicTypeImpl extends TypeImpl { /** * The unique instance of this class. */ static DynamicTypeImpl _INSTANCE = new DynamicTypeImpl._(); /** * Return the unique instance of this class. */ static DynamicTypeImpl get instance => _INSTANCE; /** * Prevent the creation of instances of this class. */ DynamicTypeImpl._() : super(new DynamicElementImpl(), Keyword.DYNAMIC.syntax) { (element as DynamicElementImpl).type = this; } @override int get hashCode => 1; @override bool get isDynamic => true; @override bool operator ==(Object object) => identical(object, this); @override bool internalEquals(Object object, Set visitedElementPairs) => identical(object, this); @override int internalHashCode(List visitedTypes) => hashCode; @override bool isMoreSpecificThan(DartType type, [Set thisExpansions, Set typeExpansions, bool withDynamic = false, Set visitedElements]) { // T is S if (identical(this, type)) { return true; } // else return withDynamic; } @override bool isSubtypeOf(DartType type, [Set thisExpansions, Set typeExpansions]) => true; @override bool isSupertypeOf(DartType type) => true; @override DartType substitute2( List argumentTypes, List parameterTypes) { int length = parameterTypes.length; for (int i = 0; i < length; i++) { if (parameterTypes[i] == this) { return argumentTypes[i]; } } return this; } } /** * The base class for all of the elements in the element model. Generally * speaking, the element model is a semantic model of the program that * represents things that are declared with a name and hence can be referenced * elsewhere in the code. * * There are two exceptions to the general case. First, there are elements in * the element model that are created for the convenience of various kinds of * analysis but that do not have any corresponding declaration within the source * code. Such elements are marked as being synthetic. Examples of * synthetic elements include * * default constructors in classes that do not define any explicit * constructors, * * getters and setters that are induced by explicit field declarations, * * fields that are induced by explicit declarations of getters and setters, * and * * functions representing the initialization expression for a variable. * * Second, there are elements in the element model that do not have a name. * These correspond to unnamed functions and exist in order to more accurately * represent the semantic structure of the program. */ abstract class Element implements AnalysisTarget { /** * An Unicode right arrow. */ static final String RIGHT_ARROW = " \u2192 "; /** * A comparator that can be used to sort elements by their name offset. * Elements with a smaller offset will be sorted to be before elements with a * larger name offset. */ static final Comparator SORT_BY_OFFSET = (Element firstElement, Element secondElement) => firstElement.nameOffset - secondElement.nameOffset; /** * Return the analysis context in which this element is defined. */ AnalysisContext get context; /** * Return the display name of this element, or `null` if this element does not * have a name. * * In most cases the name and the display name are the same. Differences * though are cases such as setters where the name of some setter `set f(x)` * is `f=`, instead of `f`. */ String get displayName; /** * Return the element that either physically or logically encloses this * element. This will be `null` if this element is a library because libraries * are the top-level elements in the model. */ Element get enclosingElement; /** * The unique integer identifier of this element. */ int get id; /** * Return `true` if this element has an annotation of the form '@deprecated' * or '@Deprecated('..')'. */ bool get isDeprecated; /** * Return `true` if this element has an annotation of the form '@override'. */ bool get isOverride; /** * Return `true` if this element is private. Private elements are visible only * within the library in which they are declared. */ bool get isPrivate; /** * Return `true` if this element is public. Public elements are visible within * any library that imports the library in which they are declared. */ bool get isPublic; /** * Return `true` if this element is synthetic. A synthetic element is an * element that is not represented in the source code explicitly, but is * implied by the source code, such as the default constructor for a class * that does not explicitly define any constructors. */ bool get isSynthetic; /** * Return the kind of element that this is. */ ElementKind get kind; /** * Return the library that contains this element. This will be the element * itself if it is a library element. This will be `null` if this element is * an HTML file because HTML files are not contained in libraries. */ LibraryElement get library; /** * Return an object representing the location of this element in the element * model. The object can be used to locate this element at a later time. */ ElementLocation get location; /** * Return a list containing all of the metadata associated with this element. * The array will be empty if the element does not have any metadata or if the * library containing this element has not yet been resolved. */ List get metadata; /** * Return the name of this element, or `null` if this element does not have a * name. */ String get name; /** * Return the offset of the name of this element in the file that contains the * declaration of this element, or `-1` if this element is synthetic, does not * have a name, or otherwise does not have an offset. */ int get nameOffset; /** * Return the resolved [AstNode] node that declares this element, or `null` if * this element is synthetic or isn't contained in a compilation unit, such as * a [LibraryElement]. * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. * * Note: This method cannot be used in an async environment. */ AstNode get node; /** * Return the source that contains this element, or `null` if this element is * not contained in a source. */ Source get source; /** * Return the resolved [CompilationUnit] that declares this element, or `null` * if this element is synthetic. * * This method is expensive, because resolved AST might have been already * evicted from cache, so parsing and resolving will be performed. */ CompilationUnit get unit; /** * Use the given [visitor] to visit this element. Return the value returned by * the visitor as a result of visiting this element. */ accept(ElementVisitor visitor); /** * Return the documentation comment for this element as it appears in the * original source (complete with the beginning and ending delimiters), or * `null` if this element does not have a documentation comment associated * with it. This can be a long-running operation if the information needed to * access the comment is not cached. * * Throws [AnalysisException] if the documentation comment could not be * determined because the analysis could not be performed */ String computeDocumentationComment(); /** * Return the most immediate ancestor of this element for which the * [predicate] returns `true`, or `null` if there is no such ancestor. Note * that this element will never be returned. */ Element getAncestor(Predicate predicate); /** * Return a display name for the given element that includes the path to the * compilation unit in which the type is defined. If [shortName] is `null` * then [getDisplayName] will be used as the name of this element. Otherwise * the provided name will be used. */ // TODO(brianwilkerson) Make the parameter optional. String getExtendedDisplayName(String shortName); /** * Return `true` if this element, assuming that it is within scope, is * accessible to code in the given [library]. This is defined by the Dart * Language Specification in section 3.2: * * A declaration m is accessible to library L if m is * declared in L or if m is public. * */ bool isAccessibleIn(LibraryElement library); /** * Use the given [visitor] to visit all of the children of this element. There * is no guarantee of the order in which the children will be visited. */ void visitChildren(ElementVisitor visitor); } /** * A single annotation associated with an element. */ abstract class ElementAnnotation { /** * Return the element representing the field, variable, or const constructor * being used as an annotation. */ Element get element; /** * Return `true` if this annotation marks the associated element as being * deprecated. */ bool get isDeprecated; /** * Return `true` if this annotation marks the associated method as being * expected to override an inherited method. */ bool get isOverride; /** * Return `true` if this annotation marks the associated class as implementing * a proxy object. */ bool get isProxy; } /** * A concrete implementation of an [ElementAnnotation]. */ class ElementAnnotationImpl implements ElementAnnotation { /** * An empty list of annotations. */ static const List EMPTY_ARRAY = const []; /** * The name of the class used to mark an element as being deprecated. */ static String _DEPRECATED_CLASS_NAME = "Deprecated"; /** * The name of the top-level variable used to mark an element as being * deprecated. */ static String _DEPRECATED_VARIABLE_NAME = "deprecated"; /** * The name of the top-level variable used to mark a method as being expected * to override an inherited method. */ static String _OVERRIDE_VARIABLE_NAME = "override"; /** * The name of the top-level variable used to mark a class as implementing a * proxy object. */ static String PROXY_VARIABLE_NAME = "proxy"; /** * The element representing the field, variable, or constructor being used as * an annotation. */ final Element element; /** * 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 [element] is the element * representing the field, variable, or constructor being used as an * annotation. */ ElementAnnotationImpl(this.element); @override bool get isDeprecated { if (element != null) { LibraryElement library = element.library; if (library != null && library.isDartCore) { if (element is ConstructorElement) { ConstructorElement constructorElement = element as ConstructorElement; if (constructorElement.enclosingElement.name == _DEPRECATED_CLASS_NAME) { return true; } } else if (element is PropertyAccessorElement && element.name == _DEPRECATED_VARIABLE_NAME) { return true; } } } return false; } @override bool get isOverride { if (element != null) { LibraryElement library = element.library; if (library != null && library.isDartCore) { if (element is PropertyAccessorElement && element.name == _OVERRIDE_VARIABLE_NAME) { return true; } } } return false; } @override bool get isProxy { if (element != null) { LibraryElement library = element.library; if (library != null && library.isDartCore) { if (element is PropertyAccessorElement && element.name == PROXY_VARIABLE_NAME) { return true; } } } return false; } @override String toString() => '@$element'; } /** * A base class for concrete implementations of an [Element]. */ abstract class ElementImpl implements Element { static int _NEXT_ID = 0; final int id = _NEXT_ID++; /** * The enclosing element of this element, or `null` if this element is at the * root of the element structure. */ ElementImpl _enclosingElement; /** * The name of this element. */ String _name; /** * The offset of the name of this element in the file that contains the * declaration of this element. */ int _nameOffset = 0; /** * A bit-encoded form of the modifiers associated with this element. */ int _modifiers = 0; /** * A list containing all of the metadata associated with this element. */ List metadata = ElementAnnotationImpl.EMPTY_ARRAY; /** * A cached copy of the calculated hashCode for this element. */ int _cachedHashCode; /** * A cached copy of the calculated location for this element. */ ElementLocation _cachedLocation; /** * Initialize a newly created element to have the given [name] at the given * [_nameOffset]. */ ElementImpl(String name, this._nameOffset) { this._name = StringUtilities.intern(name); } /** * Initialize a newly created element to have the given [name]. */ ElementImpl.forNode(Identifier name) : this(name == null ? "" : name.name, name == null ? -1 : name.offset); @override AnalysisContext get context { if (_enclosingElement == null) { return null; } return _enclosingElement.context; } @override String get displayName => _name; @override Element get enclosingElement => _enclosingElement; /** * Set the enclosing element of this element to the given [element]. */ void set enclosingElement(Element element) { _enclosingElement = element as ElementImpl; _cachedLocation = null; _cachedHashCode = null; } @override int get hashCode { // TODO: We might want to re-visit this optimization in the future. // We cache the hash code value as this is a very frequently called method. if (_cachedHashCode == null) { int hashIdentifier = identifier.hashCode; Element enclosing = enclosingElement; if (enclosing != null) { _cachedHashCode = hashIdentifier + enclosing.hashCode; } else { _cachedHashCode = hashIdentifier; } } return _cachedHashCode; } /** * Return an identifier that uniquely identifies this element among the * children of this element's parent. */ String get identifier => name; @override bool get isDeprecated { for (ElementAnnotation annotation in metadata) { if (annotation.isDeprecated) { return true; } } return false; } @override bool get isOverride { for (ElementAnnotation annotation in metadata) { if (annotation.isOverride) { return true; } } return false; } @override bool get isPrivate { String name = displayName; if (name == null) { return true; } return Identifier.isPrivateName(name); } @override bool get isPublic => !isPrivate; @override bool get isSynthetic => hasModifier(Modifier.SYNTHETIC); @override LibraryElement get library => getAncestor((element) => element is LibraryElement); @override ElementLocation get location { if (_cachedLocation == null) { _cachedLocation = new ElementLocationImpl.con1(this); } return _cachedLocation; } @override String get name => _name; void set name(String name) { this._name = name; _cachedLocation = null; _cachedHashCode = null; } /** * The offset of the name of this element in the file that contains the * declaration of this element. */ int get nameOffset => _nameOffset; /** * Sets the offset of the name of this element in the file that contains the * declaration of this element. */ void set nameOffset(int offset) { _nameOffset = offset; _cachedHashCode = null; _cachedLocation = null; } @override AstNode get node => getNodeMatching((node) => node is AstNode); @override Source get source { if (_enclosingElement == null) { return null; } return _enclosingElement.source; } /** * Set whether this element is synthetic. */ void set synthetic(bool isSynthetic) { setModifier(Modifier.SYNTHETIC, isSynthetic); } @override CompilationUnit get unit => context.resolveCompilationUnit(source, library); @override bool operator ==(Object object) { if (identical(this, object)) { return true; } if (object == null || hashCode != object.hashCode) { return false; } return object.runtimeType == runtimeType && (object as Element).location == location; } /** * Append a textual representation of this element to the given [buffer]. */ void appendTo(StringBuffer buffer) { if (_name == null) { buffer.write(""); } else { buffer.write(_name); } } @override String computeDocumentationComment() { AnalysisContext context = this.context; if (context == null) { return null; } return context.computeDocumentationComment(this); } /** * Set this element as the enclosing element for given [element]. */ void encloseElement(ElementImpl element) { element.enclosingElement = this; } @override Element getAncestor(Predicate predicate) { Element ancestor = _enclosingElement; while (ancestor != null && !predicate(ancestor)) { ancestor = ancestor.enclosingElement; } return ancestor; } /** * Return the child of this element that is uniquely identified by the given * [identifier], or `null` if there is no such child. */ ElementImpl getChild(String identifier) => null; @override String getExtendedDisplayName(String shortName) { if (shortName == null) { shortName = displayName; } Source source = this.source; if (source != null) { return "$shortName (${source.fullName})"; } return shortName; } /** * Return the resolved [AstNode] of the given type enclosing [getNameOffset]. */ AstNode getNodeMatching(Predicate predicate) { CompilationUnit unit = this.unit; if (unit == null) { return null; } int offset = nameOffset; AstNode node = new NodeLocator.con1(offset).searchWithin(unit); if (node == null) { return null; } return node.getAncestor(predicate); } /** * Return `true` if this element has the given [modifier] associated with it. */ bool hasModifier(Modifier modifier) => BooleanArray.getEnum(_modifiers, modifier); @override bool isAccessibleIn(LibraryElement library) { if (Identifier.isPrivateName(_name)) { return library == this.library; } return true; } /** * If the given [child] is not `null`, use the given [visitor] to visit it. */ void safelyVisitChild(Element child, ElementVisitor visitor) { if (child != null) { child.accept(visitor); } } /** * Use the given [visitor] to visit all of the [children] in the given array. */ void safelyVisitChildren(List children, ElementVisitor visitor) { if (children != null) { for (Element child in children) { child.accept(visitor); } } } /** * Set whether the given [modifier] is associated with this element to * correspond to the given [value]. */ void setModifier(Modifier modifier, bool value) { _modifiers = BooleanArray.setEnum(_modifiers, modifier, value); } @override String toString() { StringBuffer buffer = new StringBuffer(); appendTo(buffer); return buffer.toString(); } @override void visitChildren(ElementVisitor visitor) { // There are no children to visit } } /** * The enumeration `ElementKind` defines the various kinds of elements in the * element model. */ class ElementKind extends Enum { static const ElementKind CLASS = const ElementKind('CLASS', 0, "class"); static const ElementKind COMPILATION_UNIT = const ElementKind('COMPILATION_UNIT', 1, "compilation unit"); static const ElementKind CONSTRUCTOR = const ElementKind('CONSTRUCTOR', 2, "constructor"); static const ElementKind DYNAMIC = const ElementKind('DYNAMIC', 3, ""); static const ElementKind EMBEDDED_HTML_SCRIPT = const ElementKind('EMBEDDED_HTML_SCRIPT', 4, "embedded html script"); static const ElementKind ERROR = const ElementKind('ERROR', 5, ""); static const ElementKind EXPORT = const ElementKind('EXPORT', 6, "export directive"); static const ElementKind EXTERNAL_HTML_SCRIPT = const ElementKind('EXTERNAL_HTML_SCRIPT', 7, "external html script"); static const ElementKind FIELD = const ElementKind('FIELD', 8, "field"); static const ElementKind FUNCTION = const ElementKind('FUNCTION', 9, "function"); static const ElementKind GETTER = const ElementKind('GETTER', 10, "getter"); static const ElementKind HTML = const ElementKind('HTML', 11, "html"); static const ElementKind IMPORT = const ElementKind('IMPORT', 12, "import directive"); static const ElementKind LABEL = const ElementKind('LABEL', 13, "label"); static const ElementKind LIBRARY = const ElementKind('LIBRARY', 14, "library"); static const ElementKind LOCAL_VARIABLE = const ElementKind('LOCAL_VARIABLE', 15, "local variable"); static const ElementKind METHOD = const ElementKind('METHOD', 16, "method"); static const ElementKind NAME = const ElementKind('NAME', 17, ""); static const ElementKind PARAMETER = const ElementKind('PARAMETER', 18, "parameter"); static const ElementKind PREFIX = const ElementKind('PREFIX', 19, "import prefix"); static const ElementKind SETTER = const ElementKind('SETTER', 20, "setter"); static const ElementKind TOP_LEVEL_VARIABLE = const ElementKind('TOP_LEVEL_VARIABLE', 21, "top level variable"); static const ElementKind FUNCTION_TYPE_ALIAS = const ElementKind('FUNCTION_TYPE_ALIAS', 22, "function type alias"); static const ElementKind TYPE_PARAMETER = const ElementKind('TYPE_PARAMETER', 23, "type parameter"); static const ElementKind UNIVERSE = const ElementKind('UNIVERSE', 24, ""); static const List values = const [ CLASS, COMPILATION_UNIT, CONSTRUCTOR, DYNAMIC, EMBEDDED_HTML_SCRIPT, ERROR, EXPORT, EXTERNAL_HTML_SCRIPT, FIELD, FUNCTION, GETTER, HTML, IMPORT, LABEL, LIBRARY, LOCAL_VARIABLE, METHOD, NAME, PARAMETER, PREFIX, SETTER, TOP_LEVEL_VARIABLE, FUNCTION_TYPE_ALIAS, TYPE_PARAMETER, UNIVERSE ]; /** * The name displayed in the UI for this kind of element. */ final String displayName; /** * Initialize a newly created element kind to have the given [displayName]. */ const ElementKind(String name, int ordinal, this.displayName) : super(name, ordinal); /** * Return the kind of the given [element], or [ERROR] if the element is * `null`. This is a utility method that can reduce the need for null checks * in other places. */ static ElementKind of(Element element) { if (element == null) { return ERROR; } return element.kind; } } /** * The location of an element within the element model. */ abstract class ElementLocation { /** * Return the path to the element whose location is represented by this * object. Clients must not modify the returned array. */ List get components; /** * Return an encoded representation of this location that can be used to * create a location that is equal to this location. */ String get encoding; } /** * A concrete implementation of an [ElementLocation]. */ class ElementLocationImpl implements ElementLocation { /** * The character used to separate components in the encoded form. */ static int _SEPARATOR_CHAR = 0x3B; /** * The path to the element whose location is represented by this object. */ List _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 components = new List(); Element ancestor = element; while (ancestor != null) { components.insert(0, (ancestor as ElementImpl).identifier); ancestor = ancestor.enclosingElement; } this._components = components; } /** * Initialize a newly created location from the given [encoding]. */ ElementLocationImpl.con2(String encoding) { this._components = _decode(encoding); } /** * Initialize a newly created location from the given [components]. */ ElementLocationImpl.con3(List components) { this._components = components; } @override List get components => _components; @override String get encoding { StringBuffer buffer = new StringBuffer(); int length = _components.length; for (int i = 0; i < length; i++) { if (i > 0) { buffer.writeCharCode(_SEPARATOR_CHAR); } _encode(buffer, _components[i]); } return buffer.toString(); } @override int get hashCode { int result = 1; for (int i = 0; i < _components.length; i++) { String component = _components[i]; result = 31 * result + component.hashCode; } return result; } @override bool operator ==(Object object) { if (identical(this, object)) { return true; } if (object is! ElementLocationImpl) { return false; } ElementLocationImpl location = object as ElementLocationImpl; List otherComponents = location._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; } @override String toString() => encoding; /** * Decode the [encoding] of a location into a list of components and return * the components. */ List _decode(String encoding) { List components = new List(); StringBuffer buffer = new StringBuffer(); int index = 0; int length = encoding.length; while (index < length) { int currentChar = encoding.codeUnitAt(index); if (currentChar == _SEPARATOR_CHAR) { if (index + 1 < length && encoding.codeUnitAt(index + 1) == _SEPARATOR_CHAR) { buffer.writeCharCode(_SEPARATOR_CHAR); index += 2; } else { components.add(buffer.toString()); buffer = new StringBuffer(); index++; } } else { buffer.writeCharCode(currentChar); index++; } } components.add(buffer.toString()); return components; } /** * Append an encoded form of the given [component] to the given [buffer]. */ void _encode(StringBuffer buffer, String component) { int length = component.length; for (int i = 0; i < length; i++) { int currentChar = component.codeUnitAt(i); if (currentChar == _SEPARATOR_CHAR) { buffer.writeCharCode(_SEPARATOR_CHAR); } buffer.writeCharCode(currentChar); } } } /** * A pair of [Element]s. [Object.==] and * [Object.hashCode] so this class can be used in hashed data structures. */ class ElementPair { /** * The first [Element]. */ final Element _first; /** * The second [Element]. */ final Element _second; /** * A cached copy of the calculated hashCode for this element. */ int _cachedHashCode; /** * Initialize a newly created pair of elements consisting of the [_first] and * [_second] elements. */ ElementPair(this._first, this._second) { _cachedHashCode = JenkinsSmiHash.hash2(_first.hashCode, _second.hashCode); } /** * Return the first element. */ Element get firstElt => _first; @override int get hashCode { return _cachedHashCode; } /** * Return the second element */ Element get secondElt => _second; @override bool operator ==(Object object) { if (identical(object, this)) { return true; } return object is ElementPair && _first == object._first && _second == object._second; } } /** * An object that can be used to visit an element structure. */ abstract class ElementVisitor { R visitClassElement(ClassElement element); R visitCompilationUnitElement(CompilationUnitElement element); R visitConstructorElement(ConstructorElement element); R visitEmbeddedHtmlScriptElement(EmbeddedHtmlScriptElement element); R visitExportElement(ExportElement element); R visitExternalHtmlScriptElement(ExternalHtmlScriptElement element); R visitFieldElement(FieldElement element); R visitFieldFormalParameterElement(FieldFormalParameterElement element); R visitFunctionElement(FunctionElement element); R visitFunctionTypeAliasElement(FunctionTypeAliasElement element); R visitHtmlElement(HtmlElement element); R visitImportElement(ImportElement element); R visitLabelElement(LabelElement element); R visitLibraryElement(LibraryElement element); R visitLocalVariableElement(LocalVariableElement element); R visitMethodElement(MethodElement element); R visitMultiplyDefinedElement(MultiplyDefinedElement element); R visitParameterElement(ParameterElement element); R visitPrefixElement(PrefixElement element); R visitPropertyAccessorElement(PropertyAccessorElement element); R visitTopLevelVariableElement(TopLevelVariableElement element); R visitTypeParameterElement(TypeParameterElement element); } /** * A script tag in an HTML file having content that defines a Dart library. */ abstract class EmbeddedHtmlScriptElement implements HtmlScriptElement { /** * Return the library element defined by the content of the script tag. */ LibraryElement get scriptLibrary; } /** * A concrete implementation of an [EmbeddedHtmlScriptElement]. */ class EmbeddedHtmlScriptElementImpl extends HtmlScriptElementImpl implements EmbeddedHtmlScriptElement { /** * The library defined by the script tag's content. */ LibraryElement _scriptLibrary; /** * Initialize a newly created script element to represent the given [node]. */ EmbeddedHtmlScriptElementImpl(XmlTagNode node) : super(node); @override ElementKind get kind => ElementKind.EMBEDDED_HTML_SCRIPT; @override LibraryElement get scriptLibrary => _scriptLibrary; /** * Set the script library defined by the script tag's content to the given * [library]. */ void set scriptLibrary(LibraryElementImpl library) { library.enclosingElement = this; _scriptLibrary = library; } @override accept(ElementVisitor visitor) => visitor.visitEmbeddedHtmlScriptElement(this); @override void visitChildren(ElementVisitor visitor) { safelyVisitChild(_scriptLibrary, visitor); } } /** * An element representing an executable object, including functions, methods, * constructors, getters, and setters. */ abstract class ExecutableElement implements Element { /** * Return a list containing all of the functions defined within this * executable element. */ List get functions; /** * Return `true` if this executable element is abstract. * Executable elements are abstract if they are not external and have no body. */ bool get isAbstract; /** * Return `true` if this executable element has body marked as being * asynchronous. */ bool get isAsynchronous; /** * Return `true` if this executable element has a body marked as being a * generator. */ bool get isGenerator; /** * Return `true` if this executable element is an operator. The test may be * based on the name of the executable element, in which case the result will * be correct when the name is legal. */ bool get isOperator; /** * Return `true` if this element is a static element. A static element is an * element that is not associated with a particular instance, but rather with * an entire library or class. */ bool get isStatic; /** * Return `true` if this executable element has a body marked as being * synchronous. */ bool get isSynchronous; /** * Return a list containing all of the labels defined within this executable * element. */ List get labels; /** * Return a list containing all of the local variables defined within this * executable element. */ List get localVariables; /** * Return a list containing all of the parameters defined by this executable * element. */ List get parameters; /** * Return the return type defined by this executable element. */ DartType get returnType; /** * Return the type of function defined by this executable element. */ FunctionType get type; } /** * A base class for concrete implementations of an [ExecutableElement]. */ abstract class ExecutableElementImpl extends ElementImpl implements ExecutableElement { /** * An empty list of executable elements. */ static const List EMPTY_ARRAY = const []; /** * A list containing all of the functions defined within this executable * element. */ List _functions = FunctionElementImpl.EMPTY_ARRAY; /** * A list containing all of the labels defined within this executable element. */ List _labels = LabelElementImpl.EMPTY_ARRAY; /** * A list containing all of the local variables defined within this executable * element. */ List _localVariables = LocalVariableElementImpl.EMPTY_ARRAY; /** * A list containing all of the parameters defined by this executable element. */ List _parameters = ParameterElementImpl.EMPTY_ARRAY; /** * The return type defined by this executable element. */ DartType returnType; /** * The type of function defined by this executable element. */ FunctionType type; /** * Initialize a newly created executable element to have the given [name] and * [offset]. */ ExecutableElementImpl(String name, int offset) : super(name, offset); /** * Initialize a newly created executable element to have the given [name]. */ ExecutableElementImpl.forNode(Identifier name) : super.forNode(name); /** * Set whether this method's body is asynchronous. */ void set asynchronous(bool isAsynchronous) { setModifier(Modifier.ASYNCHRONOUS, isAsynchronous); } @override List get functions => _functions; /** * Set the functions defined within this executable element to the given * [functions]. */ void set functions(List functions) { for (FunctionElement function in functions) { (function as FunctionElementImpl).enclosingElement = this; } this._functions = functions; } /** * Set whether this method's body is a generator. */ void set generator(bool isGenerator) { setModifier(Modifier.GENERATOR, isGenerator); } @override bool get isAbstract => hasModifier(Modifier.ABSTRACT); @override bool get isAsynchronous => hasModifier(Modifier.ASYNCHRONOUS); @override bool get isGenerator => hasModifier(Modifier.GENERATOR); @override bool get isOperator => false; @override bool get isSynchronous => !hasModifier(Modifier.ASYNCHRONOUS); @override List get labels => _labels; /** * Set the labels defined within this executable element to the given * [labels]. */ void set labels(List labels) { for (LabelElement label in labels) { (label as LabelElementImpl).enclosingElement = this; } this._labels = labels; } @override List get localVariables => _localVariables; /** * Set the local variables defined within this executable element to the given * [variables]. */ void set localVariables(List variables) { for (LocalVariableElement variable in variables) { (variable as LocalVariableElementImpl).enclosingElement = this; } this._localVariables = variables; } @override List get parameters => _parameters; /** * Set the parameters defined by this executable element to the given * [parameters]. */ void set parameters(List parameters) { for (ParameterElement parameter in parameters) { (parameter as ParameterElementImpl).enclosingElement = this; } this._parameters = parameters; } @override void appendTo(StringBuffer buffer) { if (this.kind != ElementKind.GETTER) { buffer.write("("); String closing = null; ParameterKind kind = ParameterKind.REQUIRED; int parameterCount = _parameters.length; for (int i = 0; i < parameterCount; i++) { if (i > 0) { buffer.write(", "); } ParameterElementImpl parameter = _parameters[i] as ParameterElementImpl; ParameterKind parameterKind = parameter.parameterKind; if (parameterKind != kind) { if (closing != null) { buffer.write(closing); } if (parameterKind == ParameterKind.POSITIONAL) { buffer.write("["); closing = "]"; } else if (parameterKind == ParameterKind.NAMED) { buffer.write("{"); closing = "}"; } else { closing = null; } } kind = parameterKind; parameter.appendToWithoutDelimiters(buffer); } if (closing != null) { buffer.write(closing); } buffer.write(")"); } if (type != null) { buffer.write(Element.RIGHT_ARROW); buffer.write(type.returnType); } } @override ElementImpl getChild(String identifier) { for (ExecutableElement function in _functions) { if ((function as ExecutableElementImpl).identifier == identifier) { return function as ExecutableElementImpl; } } for (LabelElement label in _labels) { if ((label as LabelElementImpl).identifier == identifier) { return label as LabelElementImpl; } } for (VariableElement variable in _localVariables) { if ((variable as VariableElementImpl).identifier == identifier) { return variable as VariableElementImpl; } } for (ParameterElement parameter in _parameters) { if ((parameter as ParameterElementImpl).identifier == identifier) { return parameter as ParameterElementImpl; } } return null; } @override void visitChildren(ElementVisitor visitor) { super.visitChildren(visitor); safelyVisitChildren(_functions, visitor); safelyVisitChildren(_labels, visitor); safelyVisitChildren(_localVariables, visitor); safelyVisitChildren(_parameters, visitor); } } /** * An executable element defined in a parameterized type where the values of the * type parameters are known. */ abstract class ExecutableMember extends Member implements ExecutableElement { /** * Initialize a newly created element to represent a constructor, based on the * [baseElement], defined by the [definingType]. */ ExecutableMember(ExecutableElement baseElement, InterfaceType definingType) : super(baseElement, definingType); @override ExecutableElement get baseElement => super.baseElement as ExecutableElement; @override List get functions { // // Elements within this element should have type parameters substituted, // just like this element. // throw new UnsupportedOperationException(); // return getBaseElement().getFunctions(); } @override bool get isAbstract => baseElement.isAbstract; @override bool get isAsynchronous => baseElement.isAsynchronous; @override bool get isGenerator => baseElement.isGenerator; @override bool get isOperator => baseElement.isOperator; @override bool get isStatic => baseElement.isStatic; @override bool get isSynchronous => baseElement.isSynchronous; @override List get labels => baseElement.labels; @override List get localVariables { // // Elements within this element should have type parameters substituted, // just like this element. // throw new UnsupportedOperationException(); // return getBaseElement().getLocalVariables(); } @override List get parameters { List baseParameters = baseElement.parameters; int parameterCount = baseParameters.length; if (parameterCount == 0) { return baseParameters; } List parameterizedParameters = new List(parameterCount); for (int i = 0; i < parameterCount; i++) { parameterizedParameters[i] = ParameterMember.from(baseParameters[i], definingType); } return parameterizedParameters; } @override DartType get returnType => substituteFor(baseElement.returnType); @override FunctionType get type => substituteFor(baseElement.type); @override void visitChildren(ElementVisitor visitor) { // TODO(brianwilkerson) We need to finish implementing the accessors used // below so that we can safely invoke them. super.visitChildren(visitor); safelyVisitChildren(baseElement.functions, visitor); safelyVisitChildren(labels, visitor); safelyVisitChildren(baseElement.localVariables, visitor); safelyVisitChildren(parameters, visitor); } } /** * An export directive within a library. */ abstract class ExportElement implements Element, UriReferencedElement { /** * An empty list of export elements. */ static const List EMPTY_ARRAY = const []; /** * Return a list containing the combinators that were specified as part of the * export directive in the order in which they were specified. */ List get combinators; /** * Return the library that is exported from this library by this export * directive. */ LibraryElement get exportedLibrary; } /** * A concrete implementation of an [ExportElement]. */ class ExportElementImpl extends UriReferencedElementImpl implements ExportElement { /** * The library that is exported from this library by this export directive. */ LibraryElement exportedLibrary; /** * The combinators that were specified as part of the export directive in the * order in which they were specified. */ List combinators = NamespaceCombinator.EMPTY_ARRAY; /** * Initialize a newly created export element at the given [offset]. */ ExportElementImpl(int offset) : super(null, offset); @override String get identifier => exportedLibrary.name; @override ElementKind get kind => ElementKind.EXPORT; @override accept(ElementVisitor visitor) => visitor.visitExportElement(this); @override void appendTo(StringBuffer buffer) { buffer.write("export "); (exportedLibrary as LibraryElementImpl).appendTo(buffer); } } /** * A script tag in an HTML file having a `source` attribute that references a * Dart library source file. */ abstract class ExternalHtmlScriptElement implements HtmlScriptElement { /** * Return the source referenced by this element, or `null` if this element * does not reference a Dart library source file. */ Source get scriptSource; } /** * A concrete implementation of an [ExternalHtmlScriptElement]. */ class ExternalHtmlScriptElementImpl extends HtmlScriptElementImpl implements ExternalHtmlScriptElement { /** * The source specified in the `source` attribute or `null` if unspecified. */ Source scriptSource; /** * Initialize a newly created script element to correspond to the given * [node]. */ ExternalHtmlScriptElementImpl(XmlTagNode node) : super(node); @override ElementKind get kind => ElementKind.EXTERNAL_HTML_SCRIPT; @override accept(ElementVisitor visitor) => visitor.visitExternalHtmlScriptElement(this); } /** * A field defined within a type. */ abstract class FieldElement implements ClassMemberElement, PropertyInducingElement { /** * Return {@code true} if this element is an enum constant. */ bool get isEnumConstant; /** * Return the resolved [VariableDeclaration] or [EnumConstantDeclaration] * node that declares this [FieldElement]. * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. */ @override AstNode get node; } /** * A concrete implementation of a [FieldElement]. */ class FieldElementImpl extends PropertyInducingElementImpl with PotentiallyConstVariableElement implements FieldElement { /** * An empty list of field elements. */ static const List EMPTY_ARRAY = const []; /** * Initialize a newly created synthetic field element to have the given [name] * at the given [offset]. */ FieldElementImpl(String name, int offset) : super(name, offset); /** * Initialize a newly created field element to have the given [name]. */ FieldElementImpl.forNode(Identifier name) : super.forNode(name); @override ClassElement get enclosingElement => super.enclosingElement as ClassElement; @override bool get isEnumConstant => enclosingElement != null ? enclosingElement.isEnum : false; @override bool get isStatic => hasModifier(Modifier.STATIC); @override ElementKind get kind => ElementKind.FIELD; @override AstNode get node { if (isEnumConstant) { return getNodeMatching((node) => node is EnumConstantDeclaration); } else { return getNodeMatching((node) => node is VariableDeclaration); } } /** * Set whether this field is static. */ void set static(bool isStatic) { setModifier(Modifier.STATIC, isStatic); } @override accept(ElementVisitor visitor) => visitor.visitFieldElement(this); } /** * A field formal parameter defined within a constructor element. */ abstract class FieldFormalParameterElement implements ParameterElement { /** * Return the field element associated with this field formal parameter, or * `null` if the parameter references a field that doesn't exist. */ FieldElement get field; } /** * A [ParameterElementImpl] that has the additional information of the * [FieldElement] associated with the parameter. */ class FieldFormalParameterElementImpl extends ParameterElementImpl implements FieldFormalParameterElement { /** * The field associated with this field formal parameter. */ FieldElement field; /** * Initialize a newly created parameter element to have the given [name]. */ FieldFormalParameterElementImpl(Identifier name) : super.forNode(name); @override bool get isInitializingFormal => true; @override accept(ElementVisitor visitor) => visitor.visitFieldFormalParameterElement(this); } /** * A parameter element defined in a parameterized type where the values of the * type parameters are known. */ class FieldFormalParameterMember extends ParameterMember implements FieldFormalParameterElement { /** * Initialize a newly created element to represent a constructor, based on the * [baseElement], defined by the [definingType]. */ FieldFormalParameterMember( FieldFormalParameterElement baseElement, ParameterizedType definingType) : super(baseElement, definingType); @override FieldElement get field { FieldElement field = (baseElement as FieldFormalParameterElement).field; if (field is FieldElement) { return FieldMember.from(field, definingType); } return field; } @override accept(ElementVisitor visitor) => visitor.visitFieldFormalParameterElement(this); } /** * A field element defined in a parameterized type where the values of the type * parameters are known. */ class FieldMember extends VariableMember implements FieldElement { /** * Initialize a newly created element to represent a constructor, based on the * [baseElement], defined by the [definingType]. */ FieldMember(FieldElement baseElement, InterfaceType definingType) : super(baseElement, definingType); @override FieldElement get baseElement => super.baseElement as FieldElement; @override InterfaceType get definingType => super.definingType as InterfaceType; @override ClassElement get enclosingElement => baseElement.enclosingElement; @override PropertyAccessorElement get getter => PropertyAccessorMember.from(baseElement.getter, definingType); @override bool get isEnumConstant => baseElement.isEnumConstant; @override bool get isStatic => baseElement.isStatic; @override DartType get propagatedType => substituteFor(baseElement.propagatedType); @override PropertyAccessorElement get setter => PropertyAccessorMember.from(baseElement.setter, definingType); @override accept(ElementVisitor visitor) => visitor.visitFieldElement(this); @override String toString() => '$type $displayName'; /** * If the given [field]'s type is different when any type parameters from the * defining type's declaration are replaced with the actual type arguments * from the [definingType], create a field member representing the given * field. Return the member that was created, or the base field if no member * was created. */ static FieldElement from(FieldElement field, InterfaceType definingType) { if (!_isChangedByTypeSubstitution(field, definingType)) { return field; } // TODO(brianwilkerson) Consider caching the substituted type in the // instance. It would use more memory but speed up some operations. // We need to see how often the type is being re-computed. return new FieldMember(field, definingType); } /** * Determine whether the given [field]'s type is changed when type parameters * from the [definingType]'s declaration are replaced with the actual type * arguments from the defining type. */ static bool _isChangedByTypeSubstitution( FieldElement field, InterfaceType definingType) { List argumentTypes = definingType.typeArguments; if (field != null && argumentTypes.length != 0) { DartType baseType = field.type; List parameterTypes = definingType.element.type.typeArguments; if (baseType != null) { DartType substitutedType = baseType.substitute2(argumentTypes, parameterTypes); if (baseType != substitutedType) { return true; } } // If the field has a propagated type, then we need to check whether the // propagated type needs substitution. DartType basePropagatedType = field.propagatedType; if (basePropagatedType != null) { DartType substitutedPropagatedType = basePropagatedType.substitute2(argumentTypes, parameterTypes); if (basePropagatedType != substitutedPropagatedType) { return true; } } } return false; } } /** * A (non-method) function. This can be either a top-level function, a local * function, a closure, or the initialization expression for a field or * variable. */ abstract class FunctionElement implements ExecutableElement, LocalElement { /** * The name of the method that can be implemented by a class to allow its * instances to be invoked as if they were a function. */ static final String CALL_METHOD_NAME = "call"; /** * The name of the synthetic function defined for libraries that are deferred. */ static final String LOAD_LIBRARY_NAME = "loadLibrary"; /** * The name of the function used as an entry point. */ static const String MAIN_FUNCTION_NAME = "main"; /** * The name of the method that will be invoked if an attempt is made to invoke * an undefined method on an object. */ static final String NO_SUCH_METHOD_METHOD_NAME = "noSuchMethod"; /** * Return `true` if the function is an entry point, i.e. a top-level function * and has the name `main`. */ bool get isEntryPoint; /** * Return the resolved function declaration node that declares this element. * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. */ @override FunctionDeclaration get node; } /** * A concrete implementation of a [FunctionElement]. */ class FunctionElementImpl extends ExecutableElementImpl implements FunctionElement { /** * An empty list of function elements. */ static const List EMPTY_ARRAY = const []; /** * The offset to the beginning of the visible range for this element. */ int _visibleRangeOffset = 0; /** * The length of the visible range for this element, or `-1` if this element * does not have a visible range. */ int _visibleRangeLength = -1; /** * Initialize a newly created function element to have the given [name] and * [offset]. */ FunctionElementImpl(String name, int offset) : super(name, offset); /** * Initialize a newly created function element to have the given [name]. */ FunctionElementImpl.forNode(Identifier name) : super.forNode(name); /** * Initialize a newly created function element to have no name and the given * [offset]. This is used for function expressions, that have no name. */ FunctionElementImpl.forOffset(int nameOffset) : super("", nameOffset); @override String get identifier { String identifier = super.identifier; if (!isStatic) { identifier += "@$nameOffset"; } return identifier; } @override bool get isEntryPoint { return isStatic && displayName == FunctionElement.MAIN_FUNCTION_NAME; } @override bool get isStatic => enclosingElement is CompilationUnitElement; @override ElementKind get kind => ElementKind.FUNCTION; @override FunctionDeclaration get node => getNodeMatching((node) => node is FunctionDeclaration); @override SourceRange get visibleRange { if (_visibleRangeLength < 0) { return null; } return new SourceRange(_visibleRangeOffset, _visibleRangeLength); } @override accept(ElementVisitor visitor) => visitor.visitFunctionElement(this); @override void appendTo(StringBuffer buffer) { String name = displayName; if (name != null) { buffer.write(name); } super.appendTo(buffer); } /** * Set the visible range for this element to the range starting at the given * [offset] with the given [length]. */ void setVisibleRange(int offset, int length) { _visibleRangeOffset = offset; _visibleRangeLength = length; } } /** * The type of a function, method, constructor, getter, or setter. Function * types come in three variations: * * * The types of functions that only have required parameters. These have the * general form (T1, …, Tn) → T. * * The types of functions with optional positional parameters. These have the * general form (T1, …, Tn, [Tn+1 * …, Tn+k]) → T. * * The types of functions with named parameters. These have the general form * (T1, …, Tn, {Tx1 x1, …, * Txk xk}) → T. */ abstract class FunctionType implements ParameterizedType { /** * Return a map from the names of named parameters to the types of the named * parameters of this type of function. The entries in the map will be * iterated in the same order as the order in which the named parameters were * defined. If there were no named parameters declared then the map will be * empty. */ Map get namedParameterTypes; /** * Return a list containing the types of the normal parameters of this type of * function. The parameter types are in the same order as they appear in the * declaration of the function. */ List get normalParameterTypes; /** * Return a map from the names of optional (positional) parameters to the * types of the optional parameters of this type of function. The entries in * the map will be iterated in the same order as the order in which the * optional parameters were defined. If there were no optional parameters * declared then the map will be empty. */ List get optionalParameterTypes; /** * Return a list containing the parameters elements of this type of function. * The parameter types are in the same order as they appear in the declaration * of the function. */ List get parameters; /** * Return the type of object returned by this type of function. */ DartType get returnType; /** * Return `true` if this type is a subtype of the given [type]. * * A function type (T1, …, Tn) → T is * a subtype of the function type (S1, …, Sn) * → S, if all of the following conditions are met: * * * Either * * S is void, or * * T ⇔ S. * * * For all i, 1 <= i <= n, Ti ⇔ * Si. * * A function type (T1, …, Tn, * [Tn+1, …, Tn+k]) → T is a subtype of * the function type (S1, …, Sn, * [Sn+1, …, Sn+m]) → S, if all of the * following conditions are met: * * * Either * * S is void, or * * T ⇔ S. * * * k >= m and for all i, 1 <= i <= n+m, * Ti ⇔ Si. * * A function type (T1, …, Tn, * {Tx1 x1, …, Txk xk}) → T is a subtype * of the function type (S1, …, Sn, * {Sy1 y1, …, Sym ym}) → S, if all of * the following conditions are met: * * Either * * S is void, * * or T ⇔ S. * * * For all i, 1 <= i <= n, Ti ⇔ * Si. * * k >= m and yi in {x1, * …, xk}, 1 <= i <= m. * * For all yi in {y1, …, * ym}, yi = xj => Tj ⇔ Si. * * In addition, the following subtype rules apply: * * (T1, …, Tn, []) → T <: (T1, * …, Tn) → T. * (T1, …, Tn) → T <: (T1, * …, Tn, {}) → T. * (T1, …, Tn, {}) → T <: (T1, * …, Tn) → T. * (T1, …, Tn) → T <: (T1, * …, Tn, []) → T. * * All functions implement the class `Function`. However not all function * types are a subtype of `Function`. If an interface type I includes a * method named `call()`, and the type of `call()` is the function type * F, then I is considered to be a subtype of F. */ @override bool isSubtypeOf(DartType type); @override FunctionType substitute2( List argumentTypes, List parameterTypes); /** * Return the type resulting from substituting the given [argumentTypes] for * this type's parameters. This is fully equivalent to * `substitute(argumentTypes, getTypeArguments())`. */ FunctionType substitute3(List argumentTypes); } /** * A function type alias (`typedef`). */ abstract class FunctionTypeAliasElement implements Element { /** * Return the compilation unit in which this type alias is defined. */ @override CompilationUnitElement get enclosingElement; /** * Return the resolved function type alias node that declares this element. * * This method is expensive, because resolved AST might be evicted from cache, * so parsing and resolving will be performed. */ @override FunctionTypeAlias get node; /** * Return a list containing all of the parameters defined by this type alias. */ List get parameters; /** * Return the return type defined by this type alias. */ DartType get returnType; /** * Return the type of function defined by this type alias. */ FunctionType get type; /** * Return a list containing all of the type parameters defined for this type. */ List get typeParameters; } /** * A concrete implementation of a [FunctionTypeAliasElement]. */ class FunctionTypeAliasElementImpl extends ElementImpl implements FunctionTypeAliasElement { /** * An empty array of type alias elements. */ static List EMPTY_ARRAY = new List(0); /** * A list containing all of the parameters defined by this type alias. */ List _parameters = ParameterElementImpl.EMPTY_ARRAY; /** * The return type defined by this type alias. */ DartType returnType; /** * The type of function defined by this type alias. */ FunctionType type; /** * A list containing all of the type parameters defined for this type. */ List _typeParameters = TypeParameterElementImpl.EMPTY_ARRAY; /** * Initialize a newly created type alias element to have the given name. * * [name] the name of this element * [nameOffset] the offset of the name of this element in the file that * contains the declaration of this element */ FunctionTypeAliasElementImpl(String name, int nameOffset) : super(name, nameOffset); /** * Initialize a newly created type alias element to have the given [name]. */ FunctionTypeAliasElementImpl.forNode(Identifier name) : super.forNode(name); @override CompilationUnitElement get enclosingElement => super.enclosingElement as CompilationUnitElement; @override ElementKind get kind => ElementKind.FUNCTION_TYPE_ALIAS; @override FunctionTypeAlias get node => getNodeMatching((node) => node is FunctionTypeAlias); @override List get parameters => _parameters; /** * Set the parameters defined by this type alias to the given [parameters]. */ void set parameters(List parameters) { if (parameters != null) { for (ParameterElement parameter in parameters) { (parameter as ParameterElementImpl).enclosingElement = this; } } this._parameters = parameters; } @override List get typeParameters => _typeParameters; /** * Set the type parameters defined for this type to the given * [typeParameters]. */ void set typeParameters(List typeParameters) { for (TypeParameterElement typeParameter in typeParameters) { (typeParameter as TypeParameterElementImpl).enclosingElement = this; } this._typeParameters = typeParameters; } @override accept(ElementVisitor visitor) => visitor.visitFunctionTypeAliasElement(this); @override void appendTo(StringBuffer buffer) { buffer.write("typedef "); buffer.write(displayName); int typeParameterCount = _typeParameters.length; if (typeParameterCount > 0) { buffer.write("<"); for (int i = 0; i < typeParameterCount; i++) { if (i > 0) { buffer.write(", "); } (_typeParameters[i] as TypeParameterElementImpl).appendTo(buffer); } buffer.write(">"); } buffer.write("("); int parameterCount = _parameters.length; for (int i = 0; i < parameterCount; i++) { if (i > 0) { buffer.write(", "); } (_parameters[i] as ParameterElementImpl).appendTo(buffer); } buffer.write(")"); if (type != null) { buffer.write(Element.RIGHT_ARROW); buffer.write(type.returnType); } else if (returnType != null) { buffer.write(Element.RIGHT_ARROW); buffer.write(returnType); } } @override ElementImpl getChild(String identifier) { for (VariableElement parameter in _parameters) { if ((parameter as VariableElementImpl).identifier == identifier) { return parameter as VariableElementImpl; } } for (TypeParameterElement typeParameter in _typeParameters) { if ((typeParameter as TypeParameterElementImpl).identifier == identifier) { return typeParameter as TypeParameterElementImpl; } } return null; } /** * Set the parameters defined by this type alias to the given [parameters] * without becoming the parent of the parameters. This should only be used by * the [TypeResolverVisitor] when creating a synthetic type alias. */ void shareParameters(List parameters) { this._parameters = parameters; } /** * Set the type parameters defined for this type to the given [typeParameters] * without becoming the parent of the parameters. This should only be used by * the [TypeResolverVisitor] when creating a synthetic type alias. */ void shareTypeParameters(List typeParameters) { this._typeParameters = typeParameters; } @override void visitChildren(ElementVisitor visitor) { super.visitChildren(visitor); safelyVisitChildren(_parameters, visitor); safelyVisitChildren(_typeParameters, visitor); } } /** * The type of a function, method, constructor, getter, or setter. */ class FunctionTypeImpl extends TypeImpl implements FunctionType { /** * A list containing the actual types of the type arguments. */ List typeArguments = TypeImpl.EMPTY_ARRAY; /** * Initialize a newly created function type to be declared by the given * [element]. */ FunctionTypeImpl.con1(ExecutableElement element) : super(element, null); /** * Initialize a newly created function type to be declared by the given * [element]. */ FunctionTypeImpl.con2(FunctionTypeAliasElement element) : super(element, element == null ? null : element.name); /** * Return the base parameter elements of this function element. */ List get baseParameters { Element element = this.element; if (element is ExecutableElement) { return element.parameters; } else { return (element as FunctionTypeAliasElement).parameters; } } /** * Return the return type defined by this function's element. */ DartType get baseReturnType { Element element = this.element; if (element is ExecutableElement) { return element.returnType; } else { return (element as FunctionTypeAliasElement).returnType; } } @override String get displayName { String name = this.name; if (name == null || name.length == 0) { // Function types have an empty name when they are defined implicitly by // either a closure or as part of a parameter declaration. List normalParameterTypes = this.normalParameterTypes; List optionalParameterTypes = this.optionalParameterTypes; Map namedParameterTypes = this.namedParameterTypes; DartType returnType = this.returnType; StringBuffer buffer = new StringBuffer(); buffer.write("("); bool needsComma = false; if (normalParameterTypes.length > 0) { for (DartType type in normalParameterTypes) { if (needsComma) { buffer.write(", "); } else { needsComma = true; } buffer.write(type.displayName); } } if (optionalParameterTypes.length > 0) { if (needsComma) { buffer.write(", "); needsComma = false; } buffer.write("["); for (DartType type in optionalParameterTypes) { if (needsComma) { buffer.write(", "); } else { needsComma = true; } buffer.write(type.displayName); } buffer.write("]"); needsComma = true; } if (namedParameterTypes.length > 0) { if (needsComma) { buffer.write(", "); needsComma = false; } buffer.write("{"); namedParameterTypes.forEach((String name, DartType type) { if (needsComma) { buffer.write(", "); } else { needsComma = true; } buffer.write(name); buffer.write(": "); buffer.write(type.displayName); }); buffer.write("}"); needsComma = true; } buffer.write(")"); buffer.write(Element.RIGHT_ARROW); if (returnType == null) { buffer.write("null"); } else { buffer.write(returnType.displayName); } name = buffer.toString(); } return name; } @override int get hashCode => internalHashCode([]); @override Map get namedParameterTypes { LinkedHashMap namedParameterTypes = new LinkedHashMap(); List parameters = baseParameters; if (parameters.length == 0) { return namedParameterTypes; } List typeParameters = TypeParameterTypeImpl.getTypes(this.typeParameters); for (ParameterElement parameter in parameters) { if (parameter.parameterKind == ParameterKind.NAMED) { DartType type = parameter.type; if (typeArguments.length != 0 && typeArguments.length == typeParameters.length) { type = type.substitute2(typeArguments, typeParameters); } namedParameterTypes[parameter.name] = type; } } return namedParameterTypes; } @override List get normalParameterTypes { List parameters = baseParameters; if (parameters.length == 0) { return TypeImpl.EMPTY_ARRAY; } List typeParameters = TypeParameterTypeImpl.getTypes(this.typeParameters); List types = new List(); for (ParameterElement parameter in parameters) { if (parameter.parameterKind == ParameterKind.REQUIRED) { DartType type = parameter.type; if (typeArguments.length != 0 && typeArguments.length == typeParameters.length) { type = type.substitute2(typeArguments, typeParameters); } types.add(type); } } return types; } @override List get optionalParameterTypes { List parameters = baseParameters; if (parameters.length == 0) { return TypeImpl.EMPTY_ARRAY; } List typeParameters = TypeParameterTypeImpl.getTypes(this.typeParameters); List types = new List(); for (ParameterElement parameter in parameters) { if (parameter.parameterKind == ParameterKind.POSITIONAL) { DartType type = parameter.type; if (typeArguments.length != 0 && typeArguments.length == typeParameters.length) { type = type.substitute2(typeArguments, typeParameters); } types.add(type); } } return types; } @override List get parameters { List baseParameters = this.baseParameters; // no parameters, quick return int parameterCount = baseParameters.length; if (parameterCount == 0) { return baseParameters; } // create specialized parameters List specializedParameters = new List(parameterCount); for (int i = 0; i < parameterCount; i++) { specializedParameters[i] = ParameterMember.from(baseParameters[i], this); } return specializedParameters; } @override DartType get returnType { DartType baseReturnType = this.baseReturnType; if (baseReturnType == null) { // TODO(brianwilkerson) This is a patch. The return type should never be // null and we need to understand why it is and fix it. return DynamicTypeImpl.instance; } // If there are no arguments to substitute, or if the arguments size doesn't // match the parameter size, return the base return type. if (typeArguments.length == 0 || typeArguments.length != typeParameters.length) { return baseReturnType; } return baseReturnType.substitute2( typeArguments, TypeParameterTypeImpl.getTypes(typeParameters)); } @override List get typeParameters { Element element = this.element; if (element is FunctionTypeAliasElement) { return element.typeParameters; } ClassElement definingClass = element.getAncestor((element) => element is ClassElement); if (definingClass != null) { return definingClass.typeParameters; } return TypeParameterElementImpl.EMPTY_ARRAY; } @override bool operator ==(Object object) => internalEquals(object, new HashSet()); @override void appendTo(StringBuffer buffer, Set visitedTypes) { if (!visitedTypes.add(this)) { buffer.write(name == null ? '...' : name); return; } List normalParameterTypes = this.normalParameterTypes; List optionalParameterTypes = this.optionalParameterTypes; Map namedParameterTypes = this.namedParameterTypes; DartType returnType = this.returnType; buffer.write("("); bool needsComma = false; if (normalParameterTypes.length > 0) { for (DartType type in normalParameterTypes) { if (needsComma) { buffer.write(", "); } else { needsComma = true; } (type as TypeImpl).appendTo(buffer, visitedTypes); } } if (optionalParameterTypes.length > 0) { if (needsComma) { buffer.write(", "); needsComma = false; } buffer.write("["); for (DartType type in optionalParameterTypes) { if (needsComma) { buffer.write(", "); } else { needsComma = true; } (type as TypeImpl).appendTo(buffer, visitedTypes); } buffer.write("]"); needsComma = true; } if (namedParameterTypes.length > 0) { if (needsComma) { buffer.write(", "); needsComma = false; } buffer.write("{"); namedParameterTypes.forEach((String name, DartType type) { if (needsComma) { buffer.write(", "); } else { needsComma = true; } buffer.write(name); buffer.write(": "); (type as TypeImpl).appendTo(buffer, visitedTypes); }); buffer.write("}"); needsComma = true; } buffer.write(")"); buffer.write(Element.RIGHT_ARROW); if (returnType == null) { buffer.write("null"); } else { (returnType as TypeImpl).appendTo(buffer, visitedTypes); } } @override bool internalEquals(Object object, Set visitedElementPairs) { if (object is! FunctionTypeImpl) { return false; } FunctionTypeImpl otherType = object as FunctionTypeImpl; // If the visitedTypePairs already has the pair (this, type), // use the elements to determine equality ElementPair elementPair = new ElementPair(element, otherType.element); if (!visitedElementPairs.add(elementPair)) { return elementPair.firstElt == elementPair.secondElt; } // Compute the result bool result = TypeImpl.equalArrays(normalParameterTypes, otherType.normalParameterTypes, visitedElementPairs) && TypeImpl.equalArrays(optionalParameterTypes, otherType.optionalParameterTypes, visitedElementPairs) && _equals(namedParameterTypes, otherType.namedParameterTypes, visitedElementPairs) && (returnType as TypeImpl).internalEquals( otherType.returnType, visitedElementPairs); // Remove the pair from our visited pairs list visitedElementPairs.remove(elementPair); // Return the result return result; } @override int internalHashCode(List visitedTypes) { if (element == null) { return 0; } else if (visitedTypes.contains(this)) { return 3; } visitedTypes.add(this); // Reference the arrays of parameters List normalParameterTypes = this.normalParameterTypes; List optionalParameterTypes = this.optionalParameterTypes; Iterable namedParameterTypes = this.namedParameterTypes.values; // Generate the hashCode int code = (returnType as TypeImpl).internalHashCode(visitedTypes); for (int i = 0; i < normalParameterTypes.length; i++) { code = (code << 1) + (normalParameterTypes[i] as TypeImpl).internalHashCode(visitedTypes); } for (int i = 0; i < optionalParameterTypes.length; i++) { code = (code << 1) + (optionalParameterTypes[i] as TypeImpl) .internalHashCode(visitedTypes); } for (DartType type in namedParameterTypes) { code = (code << 1) + (type as TypeImpl).internalHashCode(visitedTypes); } return code; } @override bool isAssignableTo(DartType type, [Set thisExpansions, Set typeExpansions]) { // A function type T may be assigned to a function type S, written T <=> S, // iff T <: S. return isSubtypeOf(type, thisExpansions, typeExpansions); } @override bool isMoreSpecificThan(DartType type, [Set thisExpansions, Set typeExpansions, bool withDynamic = false, Set visitedElements]) { // Note: visitedElements is only used for breaking recursion in the type // hierarchy; we don't use it when recursing into the function type. // trivial base cases if (type == null) { return false; } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) { return true; } else if (type is! FunctionType) { return false; } else if (this == type) { return true; } FunctionType t = this; FunctionType s = type as FunctionType; if (thisExpansions == null) { thisExpansions = new HashSet(); } else if (thisExpansions.contains(this.element)) { // [this] contains a reference to itself, which is illegal (and is // checked elsewhere). To avoid cascading errors, consider T to be a // subtype of S. return true; } if (typeExpansions == null) { typeExpansions = new HashSet(); } else if (typeExpansions.contains(type.element)) { // [type] contains a reference to itself, which is illegal (and is // checked elsewhere). To avoid cascading errors, consider T to be a // subtype of S. return true; } thisExpansions.add(this.element); typeExpansions.add(type.element); try { List tTypes = t.normalParameterTypes; List tOpTypes = t.optionalParameterTypes; List sTypes = s.normalParameterTypes; List sOpTypes = s.optionalParameterTypes; // If one function has positional and the other has named parameters, // return false. if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) || (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) { return false; } // named parameters case if (t.namedParameterTypes.length > 0) { // check that the number of required parameters are equal, and check that // every t_i is more specific than every s_i if (t.normalParameterTypes.length != s.normalParameterTypes.length) { return false; } else if (t.normalParameterTypes.length > 0) { for (int i = 0; i < tTypes.length; i++) { if (!(tTypes[i] as TypeImpl).isMoreSpecificThan( sTypes[i], thisExpansions, typeExpansions, withDynamic)) { return false; } } } Map namedTypesT = t.namedParameterTypes; Map namedTypesS = s.namedParameterTypes; // if k >= m is false, return false: the passed function type has more // named parameter types than this if (namedTypesT.length < namedTypesS.length) { return false; } // Loop through each element in S verifying that T has a matching // parameter name and that the corresponding type is more specific then // the type in S. for (String keyS in namedTypesS.keys) { DartType typeT = namedTypesT[keyS]; if (typeT == null) { return false; } if (!(typeT as TypeImpl).isMoreSpecificThan( namedTypesS[keyS], thisExpansions, typeExpansions, withDynamic)) { return false; } } } else if (s.namedParameterTypes.length > 0) { return false; } else { // positional parameter case int tArgLength = tTypes.length + tOpTypes.length; int sArgLength = sTypes.length + sOpTypes.length; // Check that the total number of parameters in t is greater than or equal // to the number of parameters in s and that the number of required // parameters in s is greater than or equal to the number of required // parameters in t. if (tArgLength < sArgLength || sTypes.length < tTypes.length) { return false; } if (tOpTypes.length == 0 && sOpTypes.length == 0) { // No positional arguments, don't copy contents to new array for (int i = 0; i < sTypes.length; i++) { if (!(tTypes[i] as TypeImpl).isMoreSpecificThan( sTypes[i], thisExpansions, typeExpansions, withDynamic)) { return false; } } } else { // Else, we do have positional parameters, copy required and positional // parameter types into arrays to do the compare (for loop below). List tAllTypes = new List(sArgLength); for (int i = 0; i < tTypes.length; i++) { tAllTypes[i] = tTypes[i]; } for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) { tAllTypes[i] = tOpTypes[j]; } List sAllTypes = new List(sArgLength); for (int i = 0; i < sTypes.length; i++) { sAllTypes[i] = sTypes[i]; } for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) { sAllTypes[i] = sOpTypes[j]; } for (int i = 0; i < sAllTypes.length; i++) { if (!(tAllTypes[i] as TypeImpl).isMoreSpecificThan( sAllTypes[i], thisExpansions, typeExpansions, withDynamic)) { return false; } } } } DartType tRetType = t.returnType; DartType sRetType = s.returnType; return sRetType.isVoid || (tRetType as TypeImpl).isMoreSpecificThan( sRetType, thisExpansions, typeExpansions, withDynamic); } finally { thisExpansions.remove(this.element); typeExpansions.remove(type.element); } } @override bool isSubtypeOf(DartType type, [Set thisExpansions, Set typeExpansions]) { // trivial base cases if (type == null) { return false; } else if (identical(this, type) || type.isDynamic || type.isDartCoreFunction || type.isObject) { return true; } else if (type is! FunctionType) { return false; } else if (this == type) { return true; } FunctionType t = this; FunctionType s = type as FunctionType; if (thisExpansions == null) { thisExpansions = new HashSet(); } else if (thisExpansions.contains(this.element)) { // [this] contains a reference to itself, which is illegal (and is // checked elsewhere). To avoid cascading errors, consider T to be a // subtype of S. return true; } if (typeExpansions == null) { typeExpansions = new HashSet(); } else if (typeExpansions.contains(type.element)) { // [type] contains a reference to itself, which is illegal (and is // checked elsewhere). To avoid cascading errors, consider T to be a // subtype of S. return true; } thisExpansions.add(this.element); typeExpansions.add(type.element); try { List tTypes = t.normalParameterTypes; List tOpTypes = t.optionalParameterTypes; List sTypes = s.normalParameterTypes; List sOpTypes = s.optionalParameterTypes; // If one function has positional and the other has named parameters, // return false. if ((sOpTypes.length > 0 && t.namedParameterTypes.length > 0) || (tOpTypes.length > 0 && s.namedParameterTypes.length > 0)) { return false; } // named parameters case if (t.namedParameterTypes.length > 0) { // check that the number of required parameters are equal, // and check that every t_i is assignable to every s_i if (t.normalParameterTypes.length != s.normalParameterTypes.length) { return false; } else if (t.normalParameterTypes.length > 0) { for (int i = 0; i < tTypes.length; i++) { if (!(tTypes[i] as TypeImpl).isAssignableTo( sTypes[i], thisExpansions, typeExpansions)) { return false; } } } Map namedTypesT = t.namedParameterTypes; Map namedTypesS = s.namedParameterTypes; // if k >= m is false, return false: the passed function type has more // named parameter types than this if (namedTypesT.length < namedTypesS.length) { return false; } // Loop through each element in S verifying that T has a matching // parameter name and that the corresponding type is assignable to the // type in S. for (String keyS in namedTypesS.keys) { DartType typeT = namedTypesT[keyS]; if (typeT == null) { return false; } if (!(typeT as TypeImpl).isAssignableTo( namedTypesS[keyS], thisExpansions, typeExpansions)) { return false; } } } else if (s.namedParameterTypes.length > 0) { return false; } else { // positional parameter case int tArgLength = tTypes.length + tOpTypes.length; int sArgLength = sTypes.length + sOpTypes.length; // Check that the total number of parameters in t is greater than or // equal to the number of parameters in s and that the number of // required parameters in s is greater than or equal to the number of // required parameters in t. if (tArgLength < sArgLength || sTypes.length < tTypes.length) { return false; } if (tOpTypes.length == 0 && sOpTypes.length == 0) { // No positional arguments, don't copy contents to new array for (int i = 0; i < sTypes.length; i++) { if (!(tTypes[i] as TypeImpl).isAssignableTo( sTypes[i], thisExpansions, typeExpansions)) { return false; } } } else { // Else, we do have positional parameters, copy required and // positional parameter types into arrays to do the compare (for loop // below). List tAllTypes = new List(sArgLength); for (int i = 0; i < tTypes.length; i++) { tAllTypes[i] = tTypes[i]; } for (int i = tTypes.length, j = 0; i < sArgLength; i++, j++) { tAllTypes[i] = tOpTypes[j]; } List sAllTypes = new List(sArgLength); for (int i = 0; i < sTypes.length; i++) { sAllTypes[i] = sTypes[i]; } for (int i = sTypes.length, j = 0; i < sArgLength; i++, j++) { sAllTypes[i] = sOpTypes[j]; } for (int i = 0; i < sAllTypes.length; i++) { if (!(tAllTypes[i] as TypeImpl).isAssignableTo( sAllTypes[i], thisExpansions, typeExpansions)) { return false; } } } } DartType tRetType = t.returnType; DartType sRetType = s.returnType; return sRetType.isVoid || (tRetType as TypeImpl).isAssignableTo( sRetType, thisExpansions, typeExpansions); } finally { thisExpansions.remove(this.element); typeExpansions.remove(type.element); } } @override FunctionTypeImpl substitute2( List argumentTypes, List parameterTypes) { if (argumentTypes.length != parameterTypes.length) { throw new IllegalArgumentException( "argumentTypes.length (${argumentTypes.length}) != parameterTypes.length (${parameterTypes.length})"); } if (argumentTypes.length == 0) { return this; } Element element = this.element; FunctionTypeImpl newType = (element is ExecutableElement) ? new FunctionTypeImpl.con1(element) : new FunctionTypeImpl.con2(element as FunctionTypeAliasElement); newType.typeArguments = TypeImpl.substitute(typeArguments, argumentTypes, parameterTypes); return newType; } @override FunctionTypeImpl substitute3(List