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

Unified Diff: sdk/lib/_internal/compiler/implementation/resolution/class_members.dart

Issue 152593002: Version 1.2.0-dev.3.1 (Closed) Base URL: http://dart.googlecode.com/svn/trunk/dart/
Patch Set: Created 6 years, 11 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
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);

Powered by Google App Engine
This is Rietveld 408576698