Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2221)

Unified Diff: pkg/analyzer/lib/src/dart/element/element.dart

Issue 2029303002: Start pulling apart ClassElementImpl and EnumElementImpl. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/analyzer/lib/src/dart/element/builder.dart ('k') | pkg/analyzer/lib/src/generated/error_verifier.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/analyzer/lib/src/dart/element/element.dart
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 6ce99401ebb2bfe458052ae9b0d6260aaff4bfa6..cfd009f1ff4921dc698c68cce95b7a789d4ac490 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -44,38 +44,11 @@ abstract class AbstractClassElementImpl extends ElementImpl
List<PropertyAccessorElement> _accessors = PropertyAccessorElement.EMPTY_LIST;
/**
- * For classes which are not mixin applications, a list containing all of the
- * constructors contained in this class, or `null` if the list of
- * constructors has not yet been built.
- *
- * For classes which are mixin applications, the list of constructors is
- * computed on the fly by the [constructors] getter, and this field is
- * `null`.
- */
- List<ConstructorElement> _constructors;
-
- /**
* A list containing all of the fields contained in this class.
*/
List<FieldElement> _fields = FieldElement.EMPTY_LIST;
/**
- * A list containing all of the mixins that are applied to the class being
- * extended in order to derive the superclass of this class.
- */
- List<InterfaceType> _mixins;
-
- /**
- * A list containing all of the interfaces that are implemented by this class.
- */
- List<InterfaceType> _interfaces;
-
- /**
- * A list containing all of the methods contained in this class.
- */
- List<MethodElement> _methods = MethodElement.EMPTY_LIST;
-
- /**
* The superclass of the class, or `null` if the class does not have an
* explicit superclass.
*/
@@ -89,17 +62,6 @@ abstract class AbstractClassElementImpl extends ElementImpl
InterfaceType type;
/**
- * A list containing all of the type parameters defined for this class.
- */
- List<TypeParameterElement> _typeParameters = TypeParameterElement.EMPTY_LIST;
-
- /**
- * A flag indicating whether the types associated with the instance members of
- * this class have been inferred.
- */
- bool hasBeenInferred = false;
-
- /**
* 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.
*/
@@ -117,13 +79,6 @@ abstract class AbstractClassElementImpl extends ElementImpl
CompilationUnitElementImpl enclosingUnit)
: super.forSerialized(enclosingUnit);
- /**
- * Set whether this class is abstract.
- */
- void set abstract(bool isAbstract) {
- setModifier(Modifier.ABSTRACT, isAbstract);
- }
-
@override
List<PropertyAccessorElement> get accessors => _accessors;
@@ -138,81 +93,8 @@ abstract class AbstractClassElementImpl extends ElementImpl
}
@override
- List<InterfaceType> get allSupertypes {
- List<InterfaceType> list = new List<InterfaceType>();
- _collectAllSupertypes(list);
- return list;
- }
-
- @override
- List<ConstructorElement> get constructors {
- if (!isMixinApplication) {
- assert(_constructors != null);
- return _constructors ?? ConstructorElement.EMPTY_LIST;
- }
- return _computeMixinAppConstructors();
- }
-
- /**
- * Set the constructors contained in this class to the given [constructors].
- *
- * Should only be used for class elements that are not mixin applications.
- */
- void set constructors(List<ConstructorElement> constructors) {
- assert(!isMixinApplication);
- for (ConstructorElement constructor in constructors) {
- (constructor as ConstructorElementImpl).enclosingElement = this;
- }
- this._constructors = constructors;
- }
-
- @override
String get displayName => name;
- /**
- * Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
- * be reported for this class.
- */
- bool get doesMixinLackConstructors {
- if (!isMixinApplication && mixins.isEmpty) {
- // This class is not a mixin application and it doesn't have a "with"
- // clause, so CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS is
- // inapplicable.
- return false;
- }
- if (supertype == null) {
- // Should never happen, since Object is the only class that has no
- // supertype, and it should have been caught by the test above.
- assert(false);
- return false;
- }
- // Find the nearest class in the supertype chain that is not a mixin
- // application.
- ClassElement nearestNonMixinClass = supertype.element;
- if (nearestNonMixinClass.isMixinApplication) {
- // Use a list to keep track of the classes we've seen, so that we won't
- // go into an infinite loop in the event of a non-trivial loop in the
- // class hierarchy.
- List<ClassElement> classesSeen = <ClassElement>[this];
- while (nearestNonMixinClass.isMixinApplication) {
- if (classesSeen.contains(nearestNonMixinClass)) {
- // Loop in the class hierarchy (which is reported elsewhere). Don't
- // confuse the user with further errors.
- return false;
- }
- classesSeen.add(nearestNonMixinClass);
- if (nearestNonMixinClass.supertype == null) {
- // Should never happen, since Object is the only class that has no
- // supertype, and it is not a mixin application.
- assert(false);
- return false;
- }
- nearestNonMixinClass = nearestNonMixinClass.supertype.element;
- }
- }
- return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
- }
-
@override
TypeParameterizedElementMixin get enclosingTypeParameterContext => null;
@@ -230,330 +112,80 @@ abstract class AbstractClassElementImpl extends ElementImpl
}
@override
- bool get hasNonFinalField {
- List<ClassElement> classesToVisit = new List<ClassElement>();
- HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
- classesToVisit.add(this);
- while (!classesToVisit.isEmpty) {
- ClassElement currentElement = classesToVisit.removeAt(0);
- if (visitedClasses.add(currentElement)) {
- // check fields
- for (FieldElement field in currentElement.fields) {
- if (!field.isFinal &&
- !field.isConst &&
- !field.isStatic &&
- !field.isSynthetic) {
- return true;
- }
- }
- // check mixins
- for (InterfaceType mixinType in currentElement.mixins) {
- ClassElement mixinElement = mixinType.element;
- classesToVisit.add(mixinElement);
- }
- // check super
- InterfaceType supertype = currentElement.supertype;
- if (supertype != null) {
- ClassElement superElement = supertype.element;
- if (superElement != null) {
- classesToVisit.add(superElement);
- }
- }
- }
- }
- // not found
- return false;
- }
+ bool get isEnum;
@override
- bool get hasReferenceToSuper => hasModifier(Modifier.REFERENCES_SUPER);
+ ElementKind get kind => ElementKind.CLASS;
/**
- * Set whether this class references 'super'.
+ * Return resynthesized type parameter elements.
*/
- 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;
+ List<TypeParameterElement> get resynthesizedTypeParameters {
+ return super.typeParameters;
}
@override
- List<InterfaceType> get interfaces {
- return _interfaces ?? const <InterfaceType>[];
- }
-
- void set interfaces(List<InterfaceType> interfaces) {
- _interfaces = interfaces;
- }
+ TypeParameterizedElementMixin get typeParameterContext => this;
@override
- bool get isAbstract {
- return hasModifier(Modifier.ABSTRACT);
- }
+ List<UnlinkedTypeParam> get unlinkedTypeParams => const <UnlinkedTypeParam>[];
@override
- bool get isEnum;
+ accept(ElementVisitor visitor) => visitor.visitClassElement(this);
@override
- bool get isMixinApplication {
- return hasModifier(Modifier.MIXIN_APPLICATION);
+ NamedCompilationUnitMember computeNode() {
+ if (isEnum) {
+ return getNodeMatching((node) => node is EnumDeclaration);
+ } else {
+ return getNodeMatching(
+ (node) => node is ClassDeclaration || node is ClassTypeAlias);
+ }
}
@override
- bool get isOrInheritsProxy =>
- _safeIsOrInheritsProxy(this, new HashSet<ClassElement>());
-
- @override
- bool get isProxy {
- for (ElementAnnotation annotation in metadata) {
- if (annotation.isProxy) {
- return true;
+ ElementImpl getChild(String identifier) {
+ //
+ // The casts in this method are safe because the set methods would have
+ // thrown a CCE if any of the elements in the arrays were not of the
+ // expected types.
+ //
+ for (PropertyAccessorElement accessor in _accessors) {
+ PropertyAccessorElementImpl accessorImpl = accessor;
+ if (accessorImpl.identifier == identifier) {
+ return accessorImpl;
}
}
- return false;
+ for (FieldElement field in _fields) {
+ FieldElementImpl fieldImpl = field;
+ if (fieldImpl.identifier == identifier) {
+ return fieldImpl;
+ }
+ }
+ return null;
}
@override
- bool get isValidMixin {
- if (!context.analysisOptions.enableSuperMixins) {
- if (hasReferenceToSuper) {
- return false;
- }
- if (!supertype.isObject) {
- return false;
- }
- }
- for (ConstructorElement constructor in constructors) {
- if (!constructor.isSynthetic && !constructor.isFactory) {
- return false;
+ FieldElement getField(String name) {
+ for (FieldElement fieldElement in _fields) {
+ if (name == fieldElement.name) {
+ return fieldElement;
}
}
- return true;
+ return null;
}
@override
- ElementKind get kind => ElementKind.CLASS;
-
- @override
- List<MethodElement> get methods => _methods;
-
- /**
- * Set the methods contained in this class to the given [methods].
- */
- void set methods(List<MethodElement> methods) {
- for (MethodElement method in methods) {
- (method as MethodElementImpl).enclosingElement = this;
- }
- this._methods = methods;
- }
-
- /**
- * Set whether this class is a mixin application.
- */
- void set mixinApplication(bool isMixinApplication) {
- setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
- }
-
- @override
- List<InterfaceType> get mixins {
- return _mixins ?? const <InterfaceType>[];
- }
-
- void set mixins(List<InterfaceType> mixins) {
- _mixins = mixins;
- }
-
- /**
- * Return resynthesized type parameter elements.
- */
- List<TypeParameterElement> get resynthesizedTypeParameters {
- return super.typeParameters;
- }
-
- @override
- TypeParameterizedElementMixin get typeParameterContext => this;
-
- @override
- List<TypeParameterElement> get typeParameters {
- return _typeParameters;
- }
-
- /**
- * Set the type parameters defined for this class to the given
- * [typeParameters].
- */
- void set typeParameters(List<TypeParameterElement> typeParameters) {
- for (TypeParameterElement typeParameter in typeParameters) {
- (typeParameter as TypeParameterElementImpl).enclosingElement = this;
- }
- this._typeParameters = typeParameters;
- }
-
- @override
- List<UnlinkedTypeParam> get unlinkedTypeParams => const <UnlinkedTypeParam>[];
-
- @override
- ConstructorElement get unnamedConstructor {
- for (ConstructorElement element in constructors) {
- String name = element.displayName;
- if (name == null || name.isEmpty) {
- return element;
- }
- }
- return null;
- }
-
- @override
- accept(ElementVisitor visitor) => visitor.visitClassElement(this);
-
- @override
- void appendTo(StringBuffer buffer) {
- if (isAbstract) {
- buffer.write('abstract ');
- }
- if (isEnum) {
- buffer.write('enum ');
- } else {
- buffer.write('class ');
- }
- String name = displayName;
- if (name == null) {
- buffer.write("{unnamed class}");
- } else {
- buffer.write(name);
- }
- int variableCount = typeParameters.length;
- if (variableCount > 0) {
- buffer.write("<");
- for (int i = 0; i < variableCount; i++) {
- if (i > 0) {
- buffer.write(", ");
- }
- (typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
- }
- buffer.write(">");
- }
- if (supertype != null && !supertype.isObject) {
- buffer.write(' extends ');
- buffer.write(supertype.displayName);
- }
- if (mixins.isNotEmpty) {
- buffer.write(' with ');
- buffer.write(mixins.map((t) => t.displayName).join(', '));
- }
- if (interfaces.isNotEmpty) {
- buffer.write(' implements ');
- buffer.write(interfaces.map((t) => t.displayName).join(', '));
- }
- }
-
- @override
- NamedCompilationUnitMember computeNode() {
- if (isEnum) {
- return getNodeMatching((node) => node is EnumDeclaration);
- } else {
- return getNodeMatching(
- (node) => node is ClassDeclaration || node is ClassTypeAlias);
- }
- }
-
- @override
- ElementImpl getChild(String identifier) {
- //
- // The casts in this method are safe because the set methods would have
- // thrown a CCE if any of the elements in the arrays were not of the
- // expected types.
- //
- for (PropertyAccessorElement accessor in _accessors) {
- PropertyAccessorElementImpl accessorImpl = accessor;
- if (accessorImpl.identifier == identifier) {
- return accessorImpl;
- }
- }
- for (ConstructorElement constructor in _constructors) {
- ConstructorElementImpl constructorImpl = constructor;
- if (constructorImpl.identifier == identifier) {
- return constructorImpl;
- }
- }
- for (FieldElement field in _fields) {
- FieldElementImpl fieldImpl = field;
- if (fieldImpl.identifier == identifier) {
- return fieldImpl;
- }
- }
- for (MethodElement method in _methods) {
- MethodElementImpl methodImpl = method;
- if (methodImpl.identifier == identifier) {
- return methodImpl;
- }
- }
- for (TypeParameterElement typeParameter in typeParameters) {
- TypeParameterElementImpl typeParameterImpl = typeParameter;
- if (typeParameterImpl.identifier == identifier) {
- return typeParameterImpl;
- }
- }
- return null;
- }
-
- @override
- FieldElement getField(String name) {
- for (FieldElement fieldElement in _fields) {
- if (name == fieldElement.name) {
- return fieldElement;
- }
- }
- return null;
- }
-
- @override
- PropertyAccessorElement getGetter(String getterName) {
- int length = _accessors.length;
- for (int i = 0; i < length; i++) {
- PropertyAccessorElement accessor = _accessors[i];
- if (accessor.isGetter && accessor.name == getterName) {
- return accessor;
- }
- }
- return null;
- }
-
- @override
- MethodElement getMethod(String methodName) {
- int length = _methods.length;
- for (int i = 0; i < length; i++) {
- MethodElement method = _methods[i];
- if (method.name == methodName) {
- return method;
- }
- }
- return null;
- }
-
- @override
- ConstructorElement getNamedConstructor(String name) {
- for (ConstructorElement element in constructors) {
- String elementName = element.name;
- if (elementName != null && elementName == name) {
- return element;
- }
- }
- return null;
- }
+ PropertyAccessorElement getGetter(String getterName) {
+ int length = _accessors.length;
+ for (int i = 0; i < length; i++) {
+ PropertyAccessorElement accessor = _accessors[i];
+ if (accessor.isGetter && accessor.name == getterName) {
+ return accessor;
+ }
+ }
+ return null;
+ }
@override
PropertyAccessorElement getSetter(String setterName) {
@@ -572,23 +204,6 @@ abstract class AbstractClassElementImpl extends ElementImpl
}
@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(
@@ -635,131 +250,7 @@ abstract class AbstractClassElementImpl extends ElementImpl
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<InterfaceType> supertypes) {
- List<InterfaceType> typesToVisit = new List<InterfaceType>();
- List<ClassElement> visitedClasses = new List<ClassElement>();
- 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);
- }
- }
- }
- }
- }
-
- /**
- * Compute a list of constructors for this class, which is a mixin
- * application. If specified, [visitedClasses] is a list of the other mixin
- * application classes which have been visited on the way to reaching this
- * one (this is used to detect circularities).
- */
- List<ConstructorElement> _computeMixinAppConstructors(
- [List<ClassElementImpl> visitedClasses = null]) {
- // First get the list of constructors of the superclass which need to be
- // forwarded to this class.
- Iterable<ConstructorElement> constructorsToForward;
- if (supertype == null) {
- // Shouldn't ever happen, since the only class with no supertype is
- // Object, and it isn't a mixin application. But for safety's sake just
- // assume an empty list.
- assert(false);
- constructorsToForward = <ConstructorElement>[];
- } else if (!supertype.element.isMixinApplication) {
- List<ConstructorElement> superclassConstructors =
- supertype.element.constructors;
- // Filter out any constructors with optional parameters (see
- // dartbug.com/15101).
- constructorsToForward =
- superclassConstructors.where(isSuperConstructorAccessible);
- } else {
- if (visitedClasses == null) {
- visitedClasses = <ClassElementImpl>[this];
- } else {
- if (visitedClasses.contains(this)) {
- // Loop in the class hierarchy. Don't try to forward any
- // constructors.
- return <ConstructorElement>[];
- }
- visitedClasses.add(this);
- }
- try {
- constructorsToForward = getImpl(supertype.element)
- ._computeMixinAppConstructors(visitedClasses);
- } finally {
- visitedClasses.removeLast();
- }
- }
-
- // Figure out the type parameter substitution we need to perform in order
- // to produce constructors for this class. We want to be robust in the
- // face of errors, so drop any extra type arguments and fill in any missing
- // ones with `dynamic`.
- List<DartType> parameterTypes =
- TypeParameterTypeImpl.getTypes(supertype.typeParameters);
- List<DartType> argumentTypes = new List<DartType>.filled(
- parameterTypes.length, DynamicTypeImpl.instance);
- for (int i = 0; i < supertype.typeArguments.length; i++) {
- if (i >= argumentTypes.length) {
- break;
- }
- argumentTypes[i] = supertype.typeArguments[i];
- }
-
- // Now create an implicit constructor for every constructor found above,
- // substituting type parameters as appropriate.
- return constructorsToForward
- .map((ConstructorElement superclassConstructor) {
- ConstructorElementImpl implicitConstructor =
- new ConstructorElementImpl(superclassConstructor.name, -1);
- implicitConstructor.synthetic = true;
- implicitConstructor.redirectedConstructor = superclassConstructor;
- implicitConstructor.returnType = type;
- List<ParameterElement> superParameters = superclassConstructor.parameters;
- int count = superParameters.length;
- if (count > 0) {
- List<ParameterElement> implicitParameters =
- new List<ParameterElement>(count);
- for (int i = 0; i < count; i++) {
- ParameterElement superParameter = superParameters[i];
- ParameterElementImpl implicitParameter =
- new ParameterElementImpl(superParameter.name, -1);
- implicitParameter.const3 = superParameter.isConst;
- implicitParameter.final2 = superParameter.isFinal;
- implicitParameter.parameterKind = superParameter.parameterKind;
- implicitParameter.synthetic = true;
- implicitParameter.type =
- superParameter.type.substitute2(argumentTypes, parameterTypes);
- implicitParameters[i] = implicitParameter;
- }
- implicitConstructor.parameters = implicitParameters;
- }
- implicitConstructor.enclosingElement = this;
- implicitConstructor.type = new FunctionTypeImpl(implicitConstructor);
- return implicitConstructor;
- }).toList(growable: false);
}
PropertyAccessorElement _internalLookUpConcreteGetter(
@@ -909,33 +400,6 @@ abstract class AbstractClassElementImpl extends ElementImpl
return null;
}
- bool _safeIsOrInheritsProxy(
- ClassElement classElt, HashSet<ClassElement> 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<InterfaceType> 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;
- }
-
/**
* Return the [AbstractClassElementImpl] of the given [classElement]. May
* throw an exception if the [AbstractClassElementImpl] cannot be provided
@@ -988,6 +452,44 @@ class ClassElementImpl extends AbstractClassElementImpl {
final UnlinkedClass _unlinkedClass;
/**
+ * A list containing all of the type parameters defined for this class.
+ */
+ List<TypeParameterElement> _typeParameters = TypeParameterElement.EMPTY_LIST;
+
+ /**
+ * A list containing all of the mixins that are applied to the class being
+ * extended in order to derive the superclass of this class.
+ */
+ List<InterfaceType> _mixins;
+
+ /**
+ * A list containing all of the interfaces that are implemented by this class.
+ */
+ List<InterfaceType> _interfaces;
+
+ /**
+ * For classes which are not mixin applications, a list containing all of the
+ * constructors contained in this class, or `null` if the list of
+ * constructors has not yet been built.
+ *
+ * For classes which are mixin applications, the list of constructors is
+ * computed on the fly by the [constructors] getter, and this field is
+ * `null`.
+ */
+ List<ConstructorElement> _constructors;
+
+ /**
+ * A list containing all of the methods contained in this class.
+ */
+ List<MethodElement> _methods = MethodElement.EMPTY_LIST;
+
+ /**
+ * A flag indicating whether the types associated with the instance members of
+ * this class have been inferred.
+ */
+ bool hasBeenInferred = false;
+
+ /**
* 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.
*/
@@ -1014,7 +516,14 @@ class ClassElementImpl extends AbstractClassElementImpl {
*/
void set abstract(bool isAbstract) {
assert(_unlinkedClass == null);
- super.abstract = isAbstract;
+ setModifier(Modifier.ABSTRACT, isAbstract);
+ }
+
+ @override
+ List<InterfaceType> get allSupertypes {
+ List<InterfaceType> list = new List<InterfaceType>();
+ _collectAllSupertypes(list);
+ return list;
}
@override
@@ -1034,6 +543,28 @@ class ClassElementImpl extends AbstractClassElementImpl {
}
@override
+ List<ConstructorElement> get constructors {
+ if (!isMixinApplication) {
+ assert(_constructors != null);
+ return _constructors ?? ConstructorElement.EMPTY_LIST;
+ }
+ return _computeMixinAppConstructors();
+ }
+
+ /**
+ * Set the constructors contained in this class to the given [constructors].
+ *
+ * Should only be used for class elements that are not mixin applications.
+ */
+ void set constructors(List<ConstructorElement> constructors) {
+ assert(!isMixinApplication);
+ for (ConstructorElement constructor in constructors) {
+ (constructor as ConstructorElementImpl).enclosingElement = this;
+ }
+ this._constructors = constructors;
+ }
+
+ @override
SourceRange get docRange {
if (_unlinkedClass != null) {
UnlinkedDocumentationComment comment =
@@ -1053,6 +584,111 @@ class ClassElementImpl extends AbstractClassElementImpl {
return super.documentationComment;
}
+ /**
+ * Return `true` if [CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS] should
+ * be reported for this class.
+ */
+ bool get doesMixinLackConstructors {
+ if (!isMixinApplication && mixins.isEmpty) {
+ // This class is not a mixin application and it doesn't have a "with"
+ // clause, so CompileTimeErrorCode.MIXIN_HAS_NO_CONSTRUCTORS is
+ // inapplicable.
+ return false;
+ }
+ if (supertype == null) {
+ // Should never happen, since Object is the only class that has no
+ // supertype, and it should have been caught by the test above.
+ assert(false);
+ return false;
+ }
+ // Find the nearest class in the supertype chain that is not a mixin
+ // application.
+ ClassElement nearestNonMixinClass = supertype.element;
+ if (nearestNonMixinClass.isMixinApplication) {
+ // Use a list to keep track of the classes we've seen, so that we won't
+ // go into an infinite loop in the event of a non-trivial loop in the
+ // class hierarchy.
+ List<ClassElement> classesSeen = <ClassElement>[this];
+ while (nearestNonMixinClass.isMixinApplication) {
+ if (classesSeen.contains(nearestNonMixinClass)) {
+ // Loop in the class hierarchy (which is reported elsewhere). Don't
+ // confuse the user with further errors.
+ return false;
+ }
+ classesSeen.add(nearestNonMixinClass);
+ if (nearestNonMixinClass.supertype == null) {
+ // Should never happen, since Object is the only class that has no
+ // supertype, and it is not a mixin application.
+ assert(false);
+ return false;
+ }
+ nearestNonMixinClass = nearestNonMixinClass.supertype.element;
+ }
+ }
+ return !nearestNonMixinClass.constructors.any(isSuperConstructorAccessible);
+ }
+
+ @override
+ bool get hasNonFinalField {
+ List<ClassElement> classesToVisit = new List<ClassElement>();
+ HashSet<ClassElement> visitedClasses = new HashSet<ClassElement>();
+ classesToVisit.add(this);
+ while (!classesToVisit.isEmpty) {
+ ClassElement currentElement = classesToVisit.removeAt(0);
+ if (visitedClasses.add(currentElement)) {
+ // check fields
+ for (FieldElement field in currentElement.fields) {
+ if (!field.isFinal &&
+ !field.isConst &&
+ !field.isStatic &&
+ !field.isSynthetic) {
+ return true;
+ }
+ }
+ // check mixins
+ for (InterfaceType mixinType in currentElement.mixins) {
+ ClassElement mixinElement = mixinType.element;
+ classesToVisit.add(mixinElement);
+ }
+ // check super
+ InterfaceType supertype = currentElement.supertype;
+ if (supertype != null) {
+ ClassElement superElement = supertype.element;
+ if (superElement != null) {
+ classesToVisit.add(superElement);
+ }
+ }
+ }
+ }
+ // not found
+ return false;
+ }
+
+ @override
+ bool get hasReferenceToSuper => hasModifier(Modifier.REFERENCES_SUPER);
+
+ /**
+ * Set whether this class references 'super'.
+ */
+ void set hasReferenceToSuper(bool isReferencedSuper) {
+ setModifier(Modifier.REFERENCES_SUPER, isReferencedSuper);
+ }
+
+ @override
+ bool get hasStaticMember {
+ for (MethodElement method in _methods) {
+ if (method.isStatic) {
+ return true;
+ }
+ }
+ for (PropertyAccessorElement accessor in _accessors) {
+ if (accessor.isStatic) {
+ return true;
+ }
+ }
+ return false;
+ }
+
@override
List<InterfaceType> get interfaces {
if (_unlinkedClass != null && _interfaces == null) {
@@ -1061,12 +697,12 @@ class ClassElementImpl extends AbstractClassElementImpl {
.map((EntityRef t) => context.resolveTypeRef(t, this))
.toList(growable: false);
}
- return super.interfaces;
+ return _interfaces ?? const <InterfaceType>[];
}
void set interfaces(List<InterfaceType> interfaces) {
assert(_unlinkedClass == null);
- super.interfaces = interfaces;
+ _interfaces = interfaces;
}
@override
@@ -1074,7 +710,7 @@ class ClassElementImpl extends AbstractClassElementImpl {
if (_unlinkedClass != null) {
return _unlinkedClass.isAbstract;
}
- return super.isAbstract;
+ return hasModifier(Modifier.ABSTRACT);
}
@override
@@ -1085,7 +721,39 @@ class ClassElementImpl extends AbstractClassElementImpl {
if (_unlinkedClass != null) {
return _unlinkedClass.isMixinApplication;
}
- return super.isMixinApplication;
+ return hasModifier(Modifier.MIXIN_APPLICATION);
+ }
+
+ @override
+ bool get isOrInheritsProxy =>
+ _safeIsOrInheritsProxy(this, new HashSet<ClassElement>());
+
+ @override
+ bool get isProxy {
+ for (ElementAnnotation annotation in metadata) {
+ if (annotation.isProxy) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
+ bool get isValidMixin {
+ if (!context.analysisOptions.enableSuperMixins) {
+ if (hasReferenceToSuper) {
+ return false;
+ }
+ if (!supertype.isObject) {
+ return false;
+ }
+ }
+ for (ConstructorElement constructor in constructors) {
+ if (!constructor.isSynthetic && !constructor.isFactory) {
+ return false;
+ }
+ }
+ return true;
}
@override
@@ -1097,66 +765,360 @@ class ClassElementImpl extends AbstractClassElementImpl {
return super.metadata;
}
+ @override
+ List<MethodElement> get methods => _methods;
+
+ /**
+ * Set the methods contained in this class to the given [methods].
+ */
+ void set methods(List<MethodElement> methods) {
+ for (MethodElement method in methods) {
+ (method as MethodElementImpl).enclosingElement = this;
+ }
+ this._methods = methods;
+ }
+
/**
* Set whether this class is a mixin application.
*/
void set mixinApplication(bool isMixinApplication) {
assert(_unlinkedClass == null);
- super.mixinApplication = isMixinApplication;
+ setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
+ }
+
+ @override
+ List<InterfaceType> get mixins {
+ if (_unlinkedClass != null && _mixins == null) {
+ ResynthesizerContext context = enclosingUnit.resynthesizerContext;
+ _mixins = _unlinkedClass.mixins
+ .map((EntityRef t) => context.resolveTypeRef(t, this))
+ .toList(growable: false);
+ }
+ return _mixins ?? const <InterfaceType>[];
+ }
+
+ void set mixins(List<InterfaceType> mixins) {
+ assert(_unlinkedClass == null);
+ _mixins = mixins;
+ }
+
+ @override
+ String get name {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.name;
+ }
+ return super.name;
+ }
+
+ @override
+ int get nameOffset {
+ if (_unlinkedClass != null) {
+ return _unlinkedClass.nameOffset;
+ }
+ return super.nameOffset;
+ }
+
+ @override
+ List<TypeParameterElement> get typeParameters {
+ if (_unlinkedClass != null) {
+ return resynthesizedTypeParameters;
+ }
+ return _typeParameters;
+ }
+
+ /**
+ * Set the type parameters defined for this class to the given
+ * [typeParameters].
+ */
+ void set typeParameters(List<TypeParameterElement> typeParameters) {
+ assert(_unlinkedClass == null);
+ for (TypeParameterElement typeParameter in typeParameters) {
+ (typeParameter as TypeParameterElementImpl).enclosingElement = this;
+ }
+ this._typeParameters = typeParameters;
+ }
+
+ @override
+ List<UnlinkedTypeParam> get unlinkedTypeParams =>
+ _unlinkedClass.typeParameters;
+
+ @override
+ ConstructorElement get unnamedConstructor {
+ for (ConstructorElement element in constructors) {
+ String name = element.displayName;
+ if (name == null || name.isEmpty) {
+ return element;
+ }
+ }
+ return null;
+ }
+
+ @override
+ void appendTo(StringBuffer buffer) {
+ if (isAbstract) {
+ buffer.write('abstract ');
+ }
+ buffer.write('class ');
+ String name = displayName;
+ if (name == null) {
+ buffer.write("{unnamed class}");
+ } else {
+ buffer.write(name);
+ }
+ int variableCount = typeParameters.length;
+ if (variableCount > 0) {
+ buffer.write("<");
+ for (int i = 0; i < variableCount; i++) {
+ if (i > 0) {
+ buffer.write(", ");
+ }
+ (typeParameters[i] as TypeParameterElementImpl).appendTo(buffer);
+ }
+ buffer.write(">");
+ }
+ if (supertype != null && !supertype.isObject) {
+ buffer.write(' extends ');
+ buffer.write(supertype.displayName);
+ }
+ if (mixins.isNotEmpty) {
+ buffer.write(' with ');
+ buffer.write(mixins.map((t) => t.displayName).join(', '));
+ }
+ if (interfaces.isNotEmpty) {
+ buffer.write(' implements ');
+ buffer.write(interfaces.map((t) => t.displayName).join(', '));
+ }
+ }
+
+ @override
+ ElementImpl getChild(String identifier) {
+ ElementImpl child = super.getChild(identifier);
+ if (child != null) {
+ return child;
+ }
+ //
+ // The casts in this method are safe because the set methods would have
+ // thrown a CCE if any of the elements in the arrays were not of the
+ // expected types.
+ //
+ for (ConstructorElement constructor in _constructors) {
+ ConstructorElementImpl constructorImpl = constructor;
+ if (constructorImpl.identifier == identifier) {
+ return constructorImpl;
+ }
+ }
+ for (MethodElement method in _methods) {
+ MethodElementImpl methodImpl = method;
+ if (methodImpl.identifier == identifier) {
+ return methodImpl;
+ }
+ }
+ for (TypeParameterElement typeParameter in typeParameters) {
+ TypeParameterElementImpl typeParameterImpl = typeParameter;
+ if (typeParameterImpl.identifier == identifier) {
+ return typeParameterImpl;
+ }
+ }
+ return null;
}
@override
- List<InterfaceType> get mixins {
- if (_unlinkedClass != null && _mixins == null) {
- ResynthesizerContext context = enclosingUnit.resynthesizerContext;
- _mixins = _unlinkedClass.mixins
- .map((EntityRef t) => context.resolveTypeRef(t, this))
- .toList(growable: false);
+ MethodElement getMethod(String methodName) {
+ int length = _methods.length;
+ for (int i = 0; i < length; i++) {
+ MethodElement method = _methods[i];
+ if (method.name == methodName) {
+ return method;
+ }
}
- return super.mixins;
- }
-
- void set mixins(List<InterfaceType> mixins) {
- assert(_unlinkedClass == null);
- super.mixins = mixins;
+ return null;
}
@override
- String get name {
- if (_unlinkedClass != null) {
- return _unlinkedClass.name;
+ ConstructorElement getNamedConstructor(String name) {
+ for (ConstructorElement element in constructors) {
+ String elementName = element.name;
+ if (elementName != null && elementName == name) {
+ return element;
+ }
}
- return super.name;
+ return null;
}
@override
- int get nameOffset {
- if (_unlinkedClass != null) {
- return _unlinkedClass.nameOffset;
+ bool isSuperConstructorAccessible(ConstructorElement constructor) {
+ // If this class has no mixins, then all superclass constructors are
+ // accessible.
+ if (mixins.isEmpty) {
+ return true;
}
- return super.nameOffset;
+ // 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
- List<TypeParameterElement> get typeParameters {
- if (_unlinkedClass != null) {
- return resynthesizedTypeParameters;
+ void visitChildren(ElementVisitor visitor) {
+ super.visitChildren(visitor);
+ safelyVisitChildren(_constructors, visitor);
+ safelyVisitChildren(_methods, visitor);
+ safelyVisitChildren(_typeParameters, visitor);
+ }
+
+ void _collectAllSupertypes(List<InterfaceType> supertypes) {
+ List<InterfaceType> typesToVisit = new List<InterfaceType>();
+ List<ClassElement> visitedClasses = new List<ClassElement>();
+ 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);
+ }
+ }
+ }
}
- return super.typeParameters;
}
/**
- * Set the type parameters defined for this class to the given
- * [typeParameters].
+ * Compute a list of constructors for this class, which is a mixin
+ * application. If specified, [visitedClasses] is a list of the other mixin
+ * application classes which have been visited on the way to reaching this
+ * one (this is used to detect circularities).
*/
- void set typeParameters(List<TypeParameterElement> typeParameters) {
- assert(_unlinkedClass == null);
- super.typeParameters = typeParameters;
+ List<ConstructorElement> _computeMixinAppConstructors(
+ [List<ClassElementImpl> visitedClasses = null]) {
+ // First get the list of constructors of the superclass which need to be
+ // forwarded to this class.
+ Iterable<ConstructorElement> constructorsToForward;
+ if (supertype == null) {
+ // Shouldn't ever happen, since the only class with no supertype is
+ // Object, and it isn't a mixin application. But for safety's sake just
+ // assume an empty list.
+ assert(false);
+ constructorsToForward = <ConstructorElement>[];
+ } else if (!supertype.element.isMixinApplication) {
+ List<ConstructorElement> superclassConstructors =
+ supertype.element.constructors;
+ // Filter out any constructors with optional parameters (see
+ // dartbug.com/15101).
+ constructorsToForward =
+ superclassConstructors.where(isSuperConstructorAccessible);
+ } else {
+ if (visitedClasses == null) {
+ visitedClasses = <ClassElementImpl>[this];
+ } else {
+ if (visitedClasses.contains(this)) {
+ // Loop in the class hierarchy. Don't try to forward any
+ // constructors.
+ return <ConstructorElement>[];
+ }
+ visitedClasses.add(this);
+ }
+ try {
+ ClassElementImpl superElement = AbstractClassElementImpl
+ .getImpl(supertype.element) as ClassElementImpl;
+ constructorsToForward =
+ superElement._computeMixinAppConstructors(visitedClasses);
+ } finally {
+ visitedClasses.removeLast();
+ }
+ }
+
+ // Figure out the type parameter substitution we need to perform in order
+ // to produce constructors for this class. We want to be robust in the
+ // face of errors, so drop any extra type arguments and fill in any missing
+ // ones with `dynamic`.
+ List<DartType> parameterTypes =
+ TypeParameterTypeImpl.getTypes(supertype.typeParameters);
+ List<DartType> argumentTypes = new List<DartType>.filled(
+ parameterTypes.length, DynamicTypeImpl.instance);
+ for (int i = 0; i < supertype.typeArguments.length; i++) {
+ if (i >= argumentTypes.length) {
+ break;
+ }
+ argumentTypes[i] = supertype.typeArguments[i];
+ }
+
+ // Now create an implicit constructor for every constructor found above,
+ // substituting type parameters as appropriate.
+ return constructorsToForward
+ .map((ConstructorElement superclassConstructor) {
+ ConstructorElementImpl implicitConstructor =
+ new ConstructorElementImpl(superclassConstructor.name, -1);
+ implicitConstructor.synthetic = true;
+ implicitConstructor.redirectedConstructor = superclassConstructor;
+ implicitConstructor.returnType = type;
+ List<ParameterElement> superParameters = superclassConstructor.parameters;
+ int count = superParameters.length;
+ if (count > 0) {
+ List<ParameterElement> implicitParameters =
+ new List<ParameterElement>(count);
+ for (int i = 0; i < count; i++) {
+ ParameterElement superParameter = superParameters[i];
+ ParameterElementImpl implicitParameter =
+ new ParameterElementImpl(superParameter.name, -1);
+ implicitParameter.const3 = superParameter.isConst;
+ implicitParameter.final2 = superParameter.isFinal;
+ implicitParameter.parameterKind = superParameter.parameterKind;
+ implicitParameter.synthetic = true;
+ implicitParameter.type =
+ superParameter.type.substitute2(argumentTypes, parameterTypes);
+ implicitParameters[i] = implicitParameter;
+ }
+ implicitConstructor.parameters = implicitParameters;
+ }
+ implicitConstructor.enclosingElement = this;
+ implicitConstructor.type = new FunctionTypeImpl(implicitConstructor);
+ return implicitConstructor;
+ }).toList(growable: false);
}
- @override
- List<UnlinkedTypeParam> get unlinkedTypeParams =>
- _unlinkedClass.typeParameters;
+ bool _safeIsOrInheritsProxy(
+ ClassElement classElt, HashSet<ClassElement> 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<InterfaceType> 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;
+ }
}
/**
@@ -3022,6 +2984,9 @@ class EnumElementImpl extends AbstractClassElementImpl {
}
@override
+ List<InterfaceType> get allSupertypes => <InterfaceType>[supertype];
+
+ @override
int get codeLength {
if (_unlinkedEnum != null) {
return _unlinkedEnum.codeRange?.length;
@@ -3038,6 +3003,9 @@ class EnumElementImpl extends AbstractClassElementImpl {
}
@override
+ List<ConstructorElement> get constructors => const <ConstructorElement>[];
Paul Berry 2016/06/01 21:47:02 Can we replicate the comment you've removed from p
scheglov 2016/06/02 00:13:24 Done.
+
+ @override
SourceRange get docRange {
if (_unlinkedEnum != null) {
UnlinkedDocumentationComment comment = _unlinkedEnum.documentationComment;
@@ -3057,11 +3025,16 @@ class EnumElementImpl extends AbstractClassElementImpl {
}
@override
- List<InterfaceType> get interfaces => const <InterfaceType>[];
+ bool get hasNonFinalField => false;
- void set interfaces(List<InterfaceType> interfaces) {
- assert(false);
- }
+ @override
+ bool get hasReferenceToSuper => false;
+
+ @override
+ bool get hasStaticMember => true;
+
+ @override
+ List<InterfaceType> get interfaces => const <InterfaceType>[];
@override
bool get isAbstract => false;
@@ -3073,6 +3046,15 @@ class EnumElementImpl extends AbstractClassElementImpl {
bool get isMixinApplication => false;
@override
+ bool get isOrInheritsProxy => false;
+
+ @override
+ bool get isProxy => false;
+
+ @override
+ bool get isValidMixin => false;
+
+ @override
List<ElementAnnotation> get metadata {
if (_unlinkedEnum != null) {
return _metadata ??=
@@ -3081,20 +3063,12 @@ class EnumElementImpl extends AbstractClassElementImpl {
return super.metadata;
}
- /**
- * Set whether this class is a mixin application.
- */
- void set mixinApplication(bool isMixinApplication) {
- assert(false);
- }
+ @override
+ List<MethodElement> get methods => const <MethodElement>[];
@override
List<InterfaceType> get mixins => const <InterfaceType>[];
- void set mixins(List<InterfaceType> mixins) {
- assert(false);
- }
-
@override
String get name {
if (_unlinkedEnum != null) {
@@ -3115,13 +3089,28 @@ class EnumElementImpl extends AbstractClassElementImpl {
List<TypeParameterElement> get typeParameters =>
const <TypeParameterElement>[];
- /**
- * Set the type parameters defined for this class to the given
- * [typeParameters].
- */
- void set typeParameters(List<TypeParameterElement> typeParameters) {
- assert(false);
+ @override
+ ConstructorElement get unnamedConstructor => null;
+
+ @override
+ void appendTo(StringBuffer buffer) {
+ buffer.write('enum ');
+ String name = displayName;
+ if (name == null) {
+ buffer.write("{unnamed enum}");
+ } else {
+ buffer.write(name);
+ }
}
+
+ @override
+ MethodElement getMethod(String name) => null;
+
+ @override
+ ConstructorElement getNamedConstructor(String name) => null;
+
+ @override
+ bool isSuperConstructorAccessible(ConstructorElement constructor) => false;
}
/**
« no previous file with comments | « pkg/analyzer/lib/src/dart/element/builder.dart ('k') | pkg/analyzer/lib/src/generated/error_verifier.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698