| Index: pkg/analyzer/lib/src/generated/resolver.dart
|
| diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
|
| index 78878046c12c64ba238d0f794ea58d803031848e..33c08635e4442761fbc8aff5d4bcf044c34e8b84 100644
|
| --- a/pkg/analyzer/lib/src/generated/resolver.dart
|
| +++ b/pkg/analyzer/lib/src/generated/resolver.dart
|
| @@ -3613,6 +3613,7 @@ class ElementBuilder extends RecursiveAstVisitor<Object> {
|
| Object visitEnumDeclaration(EnumDeclaration node) {
|
| SimpleIdentifier enumName = node.name;
|
| ClassElementImpl enumElement = new ClassElementImpl.forNode(enumName);
|
| + enumElement.enum2 = true;
|
| InterfaceTypeImpl enumType = new InterfaceTypeImpl.con1(enumElement);
|
| enumElement.type = enumType;
|
| _currentHolder.addEnum(enumElement);
|
| @@ -4043,13 +4044,11 @@ class ElementBuilder extends RecursiveAstVisitor<Object> {
|
| }
|
| PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.forVariable(variable);
|
| getter.getter = true;
|
| - getter.static = variable.isStatic;
|
| _currentHolder.addAccessor(getter);
|
| variable.getter = getter;
|
| if (!isFinal) {
|
| PropertyAccessorElementImpl setter = new PropertyAccessorElementImpl.forVariable(variable);
|
| setter.setter = true;
|
| - setter.static = variable.isStatic;
|
| ParameterElementImpl parameter = new ParameterElementImpl("_${variable.name}", variable.nameOffset);
|
| parameter.synthetic = true;
|
| parameter.parameterKind = ParameterKind.REQUIRED;
|
| @@ -6832,11 +6831,15 @@ class ElementResolver extends SimpleAstVisitor<Object> {
|
| }
|
| } else {
|
| if (staticOrPropagatedEnclosingElt is ClassElement) {
|
| - InterfaceType targetType = staticOrPropagatedEnclosingElt.type;
|
| + ClassElement classElement = staticOrPropagatedEnclosingElt;
|
| + InterfaceType targetType = classElement.type;
|
| if (targetType != null && targetType.isDartCoreFunction && propertyName.name == FunctionElement.CALL_METHOD_NAME) {
|
| // TODO(brianwilkerson) Can we ever resolve the function being invoked?
|
| //resolveArgumentsToParameters(node.getArgumentList(), invokedFunction);
|
| return;
|
| + } else if (classElement.isEnum && propertyName.name == "_name") {
|
| + _resolver.reportErrorForNode(CompileTimeErrorCode.ACCESS_PRIVATE_ENUM_FIELD, propertyName, [propertyName.name]);
|
| + return;
|
| }
|
| }
|
| ErrorCode errorCode = (shouldReportMissingMember_static ? StaticTypeWarningCode.UNDEFINED_GETTER : HintCode.UNDEFINED_GETTER);
|
| @@ -7128,23 +7131,22 @@ class EnumMemberBuilder extends RecursiveAstVisitor<Object> {
|
| // Populate the fields.
|
| //
|
| List<FieldElement> fields = new List<FieldElement>();
|
| + List<PropertyAccessorElement> getters = new List<PropertyAccessorElement>();
|
| InterfaceType intType = _typeProvider.intType;
|
| - InterfaceType stringType = _typeProvider.stringType;
|
| String indexFieldName = "index";
|
| FieldElementImpl indexField = new FieldElementImpl(indexFieldName, -1);
|
| indexField.final2 = true;
|
| + indexField.synthetic = true;
|
| indexField.type = intType;
|
| fields.add(indexField);
|
| - String nameFieldName = "_name";
|
| - FieldElementImpl nameField = new FieldElementImpl(nameFieldName, -1);
|
| - nameField.final2 = true;
|
| - nameField.type = stringType;
|
| - fields.add(nameField);
|
| + getters.add(_createGetter(indexField));
|
| FieldElementImpl valuesField = new FieldElementImpl("values", -1);
|
| valuesField.static = true;
|
| valuesField.const3 = true;
|
| + valuesField.synthetic = true;
|
| valuesField.type = _typeProvider.listType.substitute4(<DartType> [enumType]);
|
| fields.add(valuesField);
|
| + getters.add(_createGetter(valuesField));
|
| //
|
| // Build the enum constants.
|
| //
|
| @@ -7152,25 +7154,43 @@ class EnumMemberBuilder extends RecursiveAstVisitor<Object> {
|
| int constantCount = constants.length;
|
| for (int i = 0; i < constantCount; i++) {
|
| SimpleIdentifier constantName = constants[i].name;
|
| - FieldElementImpl constantElement = new ConstFieldElementImpl.con1(constantName);
|
| - constantElement.static = true;
|
| - constantElement.const3 = true;
|
| - constantElement.type = enumType;
|
| + FieldElementImpl constantField = new ConstFieldElementImpl.con1(constantName);
|
| + constantField.static = true;
|
| + constantField.const3 = true;
|
| + constantField.type = enumType;
|
| + //
|
| + // Create a value for the constant.
|
| + //
|
| HashMap<String, DartObjectImpl> fieldMap = new HashMap<String, DartObjectImpl>();
|
| fieldMap[indexFieldName] = new DartObjectImpl(intType, new IntState(i));
|
| - fieldMap[nameFieldName] = new DartObjectImpl(stringType, new StringState(constantName.name));
|
| DartObjectImpl value = new DartObjectImpl(enumType, new GenericState(fieldMap));
|
| - constantElement.evaluationResult = new ValidResult(value);
|
| - fields.add(constantElement);
|
| - constantName.staticElement = constantElement;
|
| + constantField.evaluationResult = new ValidResult(value);
|
| + fields.add(constantField);
|
| + getters.add(_createGetter(constantField));
|
| + constantName.staticElement = constantField;
|
| }
|
| //
|
| // Finish building the enum.
|
| //
|
| enumElement.fields = new List.from(fields);
|
| + enumElement.accessors = new List.from(getters);
|
| // Client code isn't allowed to invoke the constructor, so we do not model it.
|
| return super.visitEnumDeclaration(node);
|
| }
|
| +
|
| + /**
|
| + * Create a getter that corresponds to the given field.
|
| + *
|
| + * @param field the field for which a getter is to be created
|
| + * @return the getter that was created
|
| + */
|
| + PropertyAccessorElement _createGetter(FieldElementImpl field) {
|
| + PropertyAccessorElementImpl getter = new PropertyAccessorElementImpl.forVariable(field);
|
| + getter.getter = true;
|
| + getter.returnType = field.type;
|
| + field.getter = getter;
|
| + return getter;
|
| + }
|
| }
|
|
|
| /**
|
| @@ -7857,6 +7877,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| if (type is InterfaceType) {
|
| InterfaceType interfaceType = type;
|
| _checkForConstOrNewWithAbstractClass(node, typeName, interfaceType);
|
| + _checkForConstOrNewWithEnum(node, typeName, interfaceType);
|
| if (_isInConstInstanceCreation) {
|
| _checkForConstWithNonConst(node);
|
| _checkForConstWithUndefinedConstructor(node, constructorName, typeName);
|
| @@ -8075,6 +8096,7 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| Object visitSwitchStatement(SwitchStatement node) {
|
| _checkForSwitchExpressionNotAssignable(node);
|
| _checkForCaseBlocksNotTerminated(node);
|
| + _checkForMissingEnumConstantInSwitch(node);
|
| return super.visitSwitchStatement(node);
|
| }
|
|
|
| @@ -9544,12 +9566,30 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * This verifies that the passed instance creation expression is not being invoked on an enum.
|
| + *
|
| + * @param node the instance creation expression to verify
|
| + * @param typeName the [TypeName] of the [ConstructorName] from the
|
| + * [InstanceCreationExpression], this is the AST node that the error is attached to
|
| + * @param type the type being constructed with this [InstanceCreationExpression]
|
| + * @return `true` if and only if an error code is generated on the passed node
|
| + * @see CompileTimeErrorCode#INSTANTIATE_ENUM
|
| + */
|
| + bool _checkForConstOrNewWithEnum(InstanceCreationExpression node, TypeName typeName, InterfaceType type) {
|
| + if (type.element.isEnum) {
|
| + _errorReporter.reportErrorForNode(CompileTimeErrorCode.INSTANTIATE_ENUM, typeName, []);
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| * This verifies that the passed 'const' instance creation expression is not being invoked on a
|
| * constructor that is not 'const'.
|
| *
|
| * This method assumes that the instance creation was tested to be 'const' before being called.
|
| *
|
| - * @param node the instance creation expression to evaluate
|
| + * @param node the instance creation expression to verify
|
| * @return `true` if and only if an error code is generated on the passed node
|
| * @see CompileTimeErrorCode#CONST_WITH_NON_CONST
|
| */
|
| @@ -9613,6 +9653,14 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| if (node.staticElement != null) {
|
| return false;
|
| }
|
| + DartType type = typeName.type;
|
| + if (type is InterfaceType) {
|
| + ClassElement element = type.element;
|
| + if (element != null && element.isEnum) {
|
| + // We have already reported the error.
|
| + return false;
|
| + }
|
| + }
|
| Identifier className = typeName.name;
|
| // report as named or default constructor absence
|
| SimpleIdentifier name = constructorName.name;
|
| @@ -10724,6 +10772,59 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * Check to make sure that switch statements whose static type is an enum type either have a
|
| + * default case or include all of the enum constants.
|
| + *
|
| + * @param statement the switch statement to check
|
| + * @return `true` if and only if an error code is generated on the passed node
|
| + */
|
| + bool _checkForMissingEnumConstantInSwitch(SwitchStatement statement) {
|
| + // TODO(brianwilkerson) This needs to be checked after constant values have been computed.
|
| + Expression expression = statement.expression;
|
| + DartType expressionType = getStaticType(expression);
|
| + if (expressionType == null) {
|
| + return false;
|
| + }
|
| + Element expressionElement = expressionType.element;
|
| + if (expressionElement is! ClassElement) {
|
| + return false;
|
| + }
|
| + ClassElement classElement = expressionElement as ClassElement;
|
| + if (!classElement.isEnum) {
|
| + return false;
|
| + }
|
| + List<String> constantNames = new List<String>();
|
| + List<FieldElement> fields = classElement.fields;
|
| + int fieldCount = fields.length;
|
| + for (int i = 0; i < fieldCount; i++) {
|
| + FieldElement field = fields[i];
|
| + if (field.isStatic && !field.isSynthetic) {
|
| + constantNames.add(field.name);
|
| + }
|
| + }
|
| + NodeList<SwitchMember> members = statement.members;
|
| + int memberCount = members.length;
|
| + for (int i = 0; i < memberCount; i++) {
|
| + SwitchMember member = members[i];
|
| + if (member is SwitchDefault) {
|
| + return false;
|
| + }
|
| + String constantName = _getConstantName((member as SwitchCase).expression);
|
| + if (constantName != null) {
|
| + constantNames.remove(constantName);
|
| + }
|
| + }
|
| + int nameCount = constantNames.length;
|
| + if (nameCount == 0) {
|
| + return false;
|
| + }
|
| + for (int i = 0; i < nameCount; i++) {
|
| + _errorReporter.reportErrorForNode(CompileTimeErrorCode.MISSING_ENUM_CONSTANT_IN_SWITCH, statement, [constantNames[i]]);
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| * This verifies that the given function body does not contain return statements that both have
|
| * and do not have return values.
|
| *
|
| @@ -10852,6 +10953,14 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| if (node.staticElement != null) {
|
| return false;
|
| }
|
| + DartType type = typeName.type;
|
| + if (type is InterfaceType) {
|
| + ClassElement element = type.element;
|
| + if (element != null && element.isEnum) {
|
| + // We have already reported the error.
|
| + return false;
|
| + }
|
| + }
|
| // prepare class name
|
| Identifier className = typeName.name;
|
| // report as named or default constructor absence
|
| @@ -11950,6 +12059,25 @@ class ErrorVerifier extends RecursiveAstVisitor<Object> {
|
| }
|
|
|
| /**
|
| + * Given an expression in a switch case whose value is expected to be an enum constant, return the
|
| + * name of the constant.
|
| + *
|
| + * @param expression the expression from the switch case
|
| + * @return the name of the constant referenced by the expression
|
| + */
|
| + String _getConstantName(Expression expression) {
|
| + // TODO(brianwilkerson) Convert this to return the element representing the constant.
|
| + if (expression is SimpleIdentifier) {
|
| + return expression.name;
|
| + } else if (expression is PrefixedIdentifier) {
|
| + return expression.identifier.name;
|
| + } else if (expression is PropertyAccess) {
|
| + return expression.propertyName.name;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| * Returns the Type (return type) for a given getter.
|
| *
|
| * @param propertyAccessorElement
|
| @@ -22990,7 +23118,7 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| InterfaceType superclassType = null;
|
| if (extendsClause != null) {
|
| ErrorCode errorCode = (withClause == null ? CompileTimeErrorCode.EXTENDS_NON_CLASS : CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS);
|
| - superclassType = _resolveType(extendsClause.superclass, errorCode, errorCode);
|
| + superclassType = _resolveType(extendsClause.superclass, errorCode, CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
|
| if (!identical(superclassType, typeProvider.objectType)) {
|
| classElement.validMixin = false;
|
| }
|
| @@ -23014,7 +23142,7 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| super.visitClassTypeAlias(node);
|
| ClassElementImpl classElement = _getClassElement(node.name);
|
| ErrorCode errorCode = CompileTimeErrorCode.MIXIN_WITH_NON_CLASS_SUPERCLASS;
|
| - InterfaceType superclassType = _resolveType(node.superclass, errorCode, errorCode);
|
| + InterfaceType superclassType = _resolveType(node.superclass, errorCode, CompileTimeErrorCode.EXTENDS_ENUM, errorCode);
|
| if (superclassType == null) {
|
| superclassType = typeProvider.objectType;
|
| }
|
| @@ -23841,14 +23969,14 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| */
|
| void _resolve(ClassElementImpl classElement, WithClause withClause, ImplementsClause implementsClause) {
|
| if (withClause != null) {
|
| - List<InterfaceType> mixinTypes = _resolveTypes(withClause.mixinTypes, CompileTimeErrorCode.MIXIN_OF_NON_CLASS, CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
|
| + List<InterfaceType> mixinTypes = _resolveTypes(withClause.mixinTypes, CompileTimeErrorCode.MIXIN_OF_NON_CLASS, CompileTimeErrorCode.MIXIN_OF_ENUM, CompileTimeErrorCode.MIXIN_OF_NON_CLASS);
|
| if (classElement != null) {
|
| classElement.mixins = mixinTypes;
|
| }
|
| }
|
| if (implementsClause != null) {
|
| NodeList<TypeName> interfaces = implementsClause.interfaces;
|
| - List<InterfaceType> interfaceTypes = _resolveTypes(interfaces, CompileTimeErrorCode.IMPLEMENTS_NON_CLASS, CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
|
| + List<InterfaceType> interfaceTypes = _resolveTypes(interfaces, CompileTimeErrorCode.IMPLEMENTS_NON_CLASS, CompileTimeErrorCode.IMPLEMENTS_ENUM, CompileTimeErrorCode.IMPLEMENTS_DYNAMIC);
|
| if (classElement != null) {
|
| classElement.interfaces = interfaceTypes;
|
| }
|
| @@ -23883,12 +24011,18 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| * @param typeName the type name specifying the type to be returned
|
| * @param nonTypeError the error to produce if the type name is defined to be something other than
|
| * a type
|
| + * @param enumTypeError the error to produce if the type name is defined to be an enum
|
| * @param dynamicTypeError the error to produce if the type name is "dynamic"
|
| * @return the type specified by the type name
|
| */
|
| - InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError, ErrorCode dynamicTypeError) {
|
| + InterfaceType _resolveType(TypeName typeName, ErrorCode nonTypeError, ErrorCode enumTypeError, ErrorCode dynamicTypeError) {
|
| DartType type = typeName.type;
|
| if (type is InterfaceType) {
|
| + ClassElement element = type.element;
|
| + if (element != null && element.isEnum) {
|
| + reportErrorForNode(enumTypeError, typeName, []);
|
| + return null;
|
| + }
|
| return type;
|
| }
|
| // If the type is not an InterfaceType, then visitTypeName() sets the type to be a DynamicTypeImpl
|
| @@ -23907,13 +24041,14 @@ class TypeResolverVisitor extends ScopedVisitor {
|
| * @param typeNames the type names to be resolved
|
| * @param nonTypeError the error to produce if the type name is defined to be something other than
|
| * a type
|
| + * @param enumTypeError the error to produce if the type name is defined to be an enum
|
| * @param dynamicTypeError the error to produce if the type name is "dynamic"
|
| * @return an array containing all of the types that were resolved.
|
| */
|
| - List<InterfaceType> _resolveTypes(NodeList<TypeName> typeNames, ErrorCode nonTypeError, ErrorCode dynamicTypeError) {
|
| + List<InterfaceType> _resolveTypes(NodeList<TypeName> typeNames, ErrorCode nonTypeError, ErrorCode enumTypeError, ErrorCode dynamicTypeError) {
|
| List<InterfaceType> types = new List<InterfaceType>();
|
| for (TypeName typeName in typeNames) {
|
| - InterfaceType type = _resolveType(typeName, nonTypeError, dynamicTypeError);
|
| + InterfaceType type = _resolveType(typeName, nonTypeError, enumTypeError, dynamicTypeError);
|
| if (type != null) {
|
| types.add(type);
|
| }
|
|
|