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

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

Issue 140803002: Perform override and inheritance checks. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/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
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/class_members.dart b/sdk/lib/_internal/compiler/implementation/resolution/class_members.dart
index a34160b5f151b2c1886aaa7c8b5de7f6c03bae1e..1964bd5f2ede692b8c98c027a9becaf18f498cf4 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/class_members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/class_members.dart
@@ -39,13 +39,33 @@ class MembersCreator {
Map<Name, Member> classMembers = new Map<Name, Member>();
Map<Name, Signature> interfaceMembers = new Map<Name, Signature>();
+ Map<Object, Set<MessageKind>> reportedMessages =
karlklose 2014/01/28 12:27:45 Please add a comment about the possible types of k
Johnni Winther 2014/01/31 12:29:30 Done.
+ new Map<Object, 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() &&
+ !cls.isProxy &&
+ !declaredMembers.containsKey(const PublicName('noSuchMethod'))) {
+ // Check for unimplemented member on concrete classes that neither have
karlklose 2014/01/28 12:27:45 'member' -> 'members'?
Johnni Winther 2014/01/31 12:29:30 Done.
+ // a @proxy annotation nor declare a `noSuchMethod` method.
karlklose 2014/01/28 12:27:45 '@proxy' -> '`@proxy`'.
Johnni Winther 2014/01/31 12:29:30 Done.
+ checkInterfaceImplementation();
+ }
}
Map<Name, Set<Member>> _computeSuperMembers() {
@@ -94,6 +114,7 @@ class MembersCreator {
void overrideMember(DeclaredMember declared) {
DeclaredMember inherited = classMembers[declared.name];
classMembers[declared.name] = declared;
+ checkValidOverride(declared, inherited);
}
if (cls.isMixinApplication) {
@@ -175,6 +196,10 @@ class MembersCreator {
(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;
}
@@ -201,6 +226,26 @@ class MembersCreator {
() => 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.
@@ -290,4 +335,214 @@ class MembersCreator {
}
});
}
+
+ void checkInterfaceImplementation() {
karlklose 2014/01/28 12:27:45 Please add a comment on what this method checks.
Johnni Winther 2014/01/31 12:29:30 Done.
+ LibraryElement library = cls.getLibrary();
+
+ interfaceMembers.forEach((Name name, Signature interfaceMember) {
+ if (!name.isAccessibleFrom(library)) return;
+ Member classMember = classMembers[name];
+ /*if (compiler.inUserCode(cls)) {
karlklose 2014/01/28 12:27:45 Remove debug code.
Johnni Winther 2014/01/31 12:29:30 Done.
+ print('cls:$cls, sig:$interfaceMember, member=$classMember (${classMember == null || classMember.isAbstract})');
+ }*/
+ 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, Signature superMember) {
+ if (superMember != null) {
karlklose 2014/01/28 12:27:45 Perhaps 'assert(declared.name == superMember.name)
Johnni Winther 2014/01/31 12:29:30 Done.
+ 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);
+ }
+ }
+ }
+ }
+ } else {
karlklose 2014/01/28 12:27:45 Consider changing the else-branch to be the then-b
Johnni Winther 2014/01/31 12:29:30 Done.
+ if (!declared.isStatic) {
+ ClassElement superclass = cls.superclass;
+ while (superclass != null) {
+ //print('checkValidOverride($declared,$superclass');
karlklose 2014/01/28 12:27:45 Remove debug code.
Johnni Winther 2014/01/31 12:29:30 Done.
+ 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;
+ }
+ }
+ }
+ }
+
+ 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);
+ }
}

Powered by Google App Engine
This is Rietveld 408576698