| Index: sdk/lib/_internal/compiler/implementation/resolution/class_members.dart
|
| ===================================================================
|
| --- sdk/lib/_internal/compiler/implementation/resolution/class_members.dart (revision 32236)
|
| +++ sdk/lib/_internal/compiler/implementation/resolution/class_members.dart (working copy)
|
| @@ -32,13 +32,32 @@
|
| Map<Name, MemberSignature> interfaceMembers =
|
| new Map<Name, MemberSignature>();
|
|
|
| + Map<dynamic/* Member | Element */, Set<MessageKind>> reportedMessages =
|
| + new Map<dynamic, Set<MessageKind>>();
|
| +
|
| MembersCreator(Compiler this.compiler, ClassElement this.cls);
|
|
|
| + void reportMessage(var marker, MessageKind kind, report()) {
|
| + Set<MessageKind> messages =
|
| + reportedMessages.putIfAbsent(marker,
|
| + () => new Set<MessageKind>());
|
| + if (messages.add(kind)) {
|
| + report();
|
| + }
|
| + }
|
| +
|
| void computeMembers() {
|
| Map<Name, Set<Member>> inheritedInterfaceMembers =
|
| _computeSuperMembers();
|
| Map<Name, Member> declaredMembers = _computeClassMembers();
|
| _computeInterfaceMembers(inheritedInterfaceMembers, declaredMembers);
|
| +
|
| + if (!cls.modifiers.isAbstract() &&
|
| + !declaredMembers.containsKey(const PublicName('noSuchMethod'))) {
|
| + // Check for unimplemented members on concrete classes that neither have
|
| + // a `@proxy` annotation nor declare a `noSuchMethod` method.
|
| + checkInterfaceImplementation();
|
| + }
|
| }
|
|
|
| Map<Name, Set<Member>> _computeSuperMembers() {
|
| @@ -85,7 +104,9 @@
|
| Map<Name, Member> declaredMembers = new Map<Name, Member>();
|
|
|
| void overrideMember(DeclaredMember declared) {
|
| + DeclaredMember inherited = classMembers[declared.name];
|
| classMembers[declared.name] = declared;
|
| + checkValidOverride(declared, inherited);
|
| }
|
|
|
| if (cls.isMixinApplication) {
|
| @@ -170,6 +191,10 @@
|
| (Name name, Set<Member> inheritedMembers) {
|
| Member declared = declaredMembers[name];
|
| if (declared != null) {
|
| + // Check that [declaredMember] is a valid override
|
| + for (Member inherited in inheritedMembers) {
|
| + checkValidOverride(declared, inherited);
|
| + }
|
| if (!declared.isStatic) {
|
| interfaceMembers[name] = declared;
|
| }
|
| @@ -196,6 +221,26 @@
|
| () => new Set<Member>()).add(inherited);
|
| }
|
| if (someAreGetters && !allAreGetters) {
|
| + compiler.reportWarningCode(cls,
|
| + MessageKind.INHERIT_GETTER_AND_METHOD,
|
| + {'class': thisType, 'name': name.text });
|
| + for (Member inherited in inheritedMembers) {
|
| + MessageKind kind;
|
| + if (inherited.isMethod) {
|
| + kind = MessageKind.INHERITED_METHOD;
|
| + } else {
|
| + assert(invariant(cls, inherited.isGetter,
|
| + message: 'Conflicting member is neither a method nor a '
|
| + 'getter.'));
|
| + if (inherited.isDeclaredByField) {
|
| + kind = MessageKind.INHERITED_IMPLICIT_GETTER;
|
| + } else {
|
| + kind = MessageKind.INHERITED_EXPLICIT_GETTER;
|
| + }
|
| + }
|
| + compiler.reportInfo(inherited.element, kind,
|
| + {'class': inherited.declarer, 'name': name.text });
|
| + }
|
| interfaceMembers[name] = new ErroneousMember(inheritedMembers);
|
| } else if (subtypesOfAllInherited.length == 1) {
|
| // All signatures have the same type.
|
| @@ -293,6 +338,215 @@
|
| }
|
| }
|
|
|
| + /// Checks that a class member exists for every interface member.
|
| + void checkInterfaceImplementation() {
|
| + LibraryElement library = cls.getLibrary();
|
| +
|
| + interfaceMembers.forEach((Name name, MemberSignature interfaceMember) {
|
| + if (!name.isAccessibleFrom(library)) return;
|
| + Member classMember = classMembers[name];
|
| + if (classMember != null) return;
|
| + if (interfaceMember is DeclaredMember &&
|
| + interfaceMember.declarer.element == cls) {
|
| + // Abstract method declared in [cls].
|
| + MessageKind kind = MessageKind.ABSTRACT_METHOD;
|
| + if (interfaceMember.isSetter) {
|
| + kind = MessageKind.ABSTRACT_SETTER;
|
| + } else if (interfaceMember.isGetter) {
|
| + kind = MessageKind.ABSTRACT_GETTER;
|
| + }
|
| + reportMessage(
|
| + interfaceMember.element, MessageKind.ABSTRACT_METHOD, () {
|
| + compiler.reportWarningCode(
|
| + interfaceMember.element, kind,
|
| + {'class': cls.name, 'name': name.text});
|
| + });
|
| + } else {
|
| + reportWarning(MessageKind singleKind,
|
| + MessageKind multipleKind,
|
| + MessageKind explicitlyDeclaredKind,
|
| + [MessageKind implicitlyDeclaredKind]) {
|
| + Member inherited = interfaceMember.declarations.first;
|
| + reportMessage(
|
| + interfaceMember, MessageKind.UNIMPLEMENTED_METHOD, () {
|
| + compiler.reportWarningCode(cls,
|
| + interfaceMember.declarations.length == 1
|
| + ? singleKind : multipleKind,
|
| + {'class': cls.name,
|
| + 'name': name.text,
|
| + 'method': interfaceMember,
|
| + 'declarer': inherited.declarer});
|
| + for (Member inherited in interfaceMember.declarations) {
|
| + compiler.reportInfo(inherited.element,
|
| + inherited.isDeclaredByField ?
|
| + implicitlyDeclaredKind : explicitlyDeclaredKind,
|
| + {'class': inherited.declarer.name,
|
| + 'name': name.text});
|
| + }
|
| + });
|
| + }
|
| + if (interfaceMember.isSetter) {
|
| + reportWarning(MessageKind.UNIMPLEMENTED_SETTER_ONE,
|
| + MessageKind.UNIMPLEMENTED_SETTER,
|
| + MessageKind.UNIMPLEMENTED_EXPLICIT_SETTER,
|
| + MessageKind.UNIMPLEMENTED_IMPLICIT_SETTER);
|
| + } else if (interfaceMember.isGetter) {
|
| + reportWarning(MessageKind.UNIMPLEMENTED_GETTER_ONE,
|
| + MessageKind.UNIMPLEMENTED_GETTER,
|
| + MessageKind.UNIMPLEMENTED_EXPLICIT_GETTER,
|
| + MessageKind.UNIMPLEMENTED_IMPLICIT_GETTER);
|
| + } else if (interfaceMember.isMethod) {
|
| + reportWarning(MessageKind.UNIMPLEMENTED_METHOD_ONE,
|
| + MessageKind.UNIMPLEMENTED_METHOD,
|
| + MessageKind.UNIMPLEMENTED_METHOD_CONT);
|
| + }
|
| + }
|
| + // TODO(johnniwinther): If [cls] is not abstract, check that for all
|
| + // interface members, there is a class member whose type is a subtype of
|
| + // the interface member.
|
| + });
|
| + }
|
| +
|
| + void checkValidOverride(Member declared, MemberSignature superMember) {
|
| + if (superMember == null) {
|
| + // No override.
|
| + if (!declared.isStatic) {
|
| + ClassElement superclass = cls.superclass;
|
| + while (superclass != null) {
|
| + Member superMember =
|
| + superclass.lookupClassMember(declared.name);
|
| + if (superMember != null && superMember.isStatic) {
|
| + reportMessage(superMember, MessageKind.INSTANCE_STATIC_SAME_NAME,
|
| + () {
|
| + compiler.reportWarningCode(
|
| + declared.element,
|
| + MessageKind.INSTANCE_STATIC_SAME_NAME,
|
| + {'memberName': declared.name,
|
| + 'className': superclass.name});
|
| + compiler.reportInfo(superMember.element,
|
| + MessageKind.INSTANCE_STATIC_SAME_NAME_CONT);
|
| + });
|
| + break;
|
| + }
|
| + superclass = superclass.superclass;
|
| + }
|
| + }
|
| + } else {
|
| + assert(declared.name == superMember.name);
|
| + if (declared.isStatic) {
|
| + for (Member inherited in superMember.declarations) {
|
| + reportMessage(
|
| + inherited.element, MessageKind.NO_STATIC_OVERRIDE, () {
|
| + reportErrorWithContext(
|
| + declared.element, MessageKind.NO_STATIC_OVERRIDE,
|
| + inherited.element, MessageKind.NO_STATIC_OVERRIDE_CONT);
|
| + });
|
| + }
|
| + }
|
| +
|
| + DartType declaredType = declared.functionType;
|
| + for (Member inherited in superMember.declarations) {
|
| +
|
| + void reportError(MessageKind errorKind, MessageKind infoKind) {
|
| + reportMessage(
|
| + inherited.element, MessageKind.INVALID_OVERRIDE_METHOD, () {
|
| + compiler.reportError(declared.element, errorKind,
|
| + {'name': declared.name.text,
|
| + 'class': cls.thisType,
|
| + 'inheritedClass': inherited.declarer});
|
| + compiler.reportInfo(inherited.element, infoKind,
|
| + {'name': declared.name.text,
|
| + 'class': inherited.declarer});
|
| + });
|
| + }
|
| +
|
| + if (declared.isDeclaredByField && inherited.isMethod) {
|
| + reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD,
|
| + MessageKind.CANNOT_OVERRIDE_METHOD_WITH_FIELD_CONT);
|
| + } else if (declared.isMethod && inherited.isDeclaredByField) {
|
| + reportError(MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD,
|
| + MessageKind.CANNOT_OVERRIDE_FIELD_WITH_METHOD_CONT);
|
| + } else if (declared.isGetter && inherited.isMethod) {
|
| + reportError(MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER,
|
| + MessageKind.CANNOT_OVERRIDE_METHOD_WITH_GETTER_CONT);
|
| + } else if (declared.isMethod && inherited.isGetter) {
|
| + reportError(MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD,
|
| + MessageKind.CANNOT_OVERRIDE_GETTER_WITH_METHOD_CONT);
|
| + } else {
|
| + DartType inheritedType = inherited.functionType;
|
| + if (!compiler.types.isSubtype(declaredType, inheritedType)) {
|
| + void reportWarning(var marker,
|
| + MessageKind warningKind,
|
| + MessageKind infoKind) {
|
| + reportMessage(marker, MessageKind.INVALID_OVERRIDE_METHOD, () {
|
| + compiler.reportWarningCode(declared.element, warningKind,
|
| + {'declaredType': declared.type,
|
| + 'name': declared.name.text,
|
| + 'class': cls.thisType,
|
| + 'inheritedType': inherited.type,
|
| + 'inheritedClass': inherited.declarer});
|
| + compiler.reportInfo(inherited.element, infoKind,
|
| + {'name': declared.name.text,
|
| + 'class': inherited.declarer});
|
| + });
|
| + }
|
| + if (declared.isDeclaredByField) {
|
| + if (inherited.isDeclaredByField) {
|
| + reportWarning(inherited.element,
|
| + MessageKind.INVALID_OVERRIDE_FIELD,
|
| + MessageKind.INVALID_OVERRIDDEN_FIELD);
|
| + } else if (inherited.isGetter) {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_GETTER_WITH_FIELD,
|
| + MessageKind.INVALID_OVERRIDDEN_GETTER);
|
| + } else if (inherited.isSetter) {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_SETTER_WITH_FIELD,
|
| + MessageKind.INVALID_OVERRIDDEN_SETTER);
|
| + }
|
| + } else if (declared.isGetter) {
|
| + if (inherited.isDeclaredByField) {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_FIELD_WITH_GETTER,
|
| + MessageKind.INVALID_OVERRIDDEN_FIELD);
|
| + } else {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_GETTER,
|
| + MessageKind.INVALID_OVERRIDDEN_GETTER);
|
| + }
|
| + } else if (declared.isSetter) {
|
| + if (inherited.isDeclaredByField) {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_FIELD_WITH_SETTER,
|
| + MessageKind.INVALID_OVERRIDDEN_FIELD);
|
| + } else {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_SETTER,
|
| + MessageKind.INVALID_OVERRIDDEN_SETTER);
|
| + }
|
| + } else {
|
| + reportWarning(inherited,
|
| + MessageKind.INVALID_OVERRIDE_METHOD,
|
| + MessageKind.INVALID_OVERRIDDEN_METHOD);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + void reportErrorWithContext(Element errorneousElement,
|
| + MessageKind errorMessage,
|
| + Element contextElement,
|
| + MessageKind contextMessage) {
|
| + compiler.reportError(
|
| + errorneousElement,
|
| + errorMessage,
|
| + {'memberName': contextElement.name,
|
| + 'className': contextElement.getEnclosingClass().name});
|
| + compiler.reportInfo(contextElement, contextMessage);
|
| + }
|
| +
|
| static void computeClassMembers(Compiler compiler, BaseClassElementX cls) {
|
| if (cls.classMembers != null) return;
|
| MembersCreator creator = new MembersCreator(compiler, cls);
|
|
|