Lines 82-106
Link Here
|
82 |
// short is compatible with int, but as far as covariance is concerned, its not |
82 |
// short is compatible with int, but as far as covariance is concerned, its not |
83 |
if (one.returnType.isBaseType()) return false; |
83 |
if (one.returnType.isBaseType()) return false; |
84 |
|
84 |
|
85 |
if (!one.declaringClass.isInterface()) { |
85 |
if (!one.declaringClass.isInterface() && one.declaringClass.id == TypeIds.T_JavaLangObject) |
86 |
if (one.declaringClass.id == TypeIds.T_JavaLangObject) |
86 |
return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object |
87 |
return two.returnType.isCompatibleWith(one.returnType); // interface methods inherit from Object |
87 |
|
88 |
return one.returnType.isCompatibleWith(two.returnType); |
88 |
return one.returnType.isCompatibleWith(two.returnType); |
89 |
} |
|
|
90 |
|
91 |
// check for methods from Object, every interface inherits from Object |
92 |
if (two.declaringClass.id == TypeIds.T_JavaLangObject) |
93 |
return one.returnType.isCompatibleWith(two.returnType); |
94 |
|
95 |
// both are interfaces, see if they're related |
96 |
if (one.declaringClass.implementsInterface(two.declaringClass, true)) |
97 |
return one.returnType.isCompatibleWith(two.returnType); |
98 |
if (two.declaringClass.implementsInterface(one.declaringClass, true)) |
99 |
return two.returnType.isCompatibleWith(one.returnType); |
100 |
|
101 |
// unrelated interfaces... one must be a subtype of the other |
102 |
return one.returnType.isCompatibleWith(two.returnType) |
103 |
|| two.returnType.isCompatibleWith(one.returnType); |
104 |
} |
89 |
} |
105 |
boolean areTypesEqual(TypeBinding one, TypeBinding two) { |
90 |
boolean areTypesEqual(TypeBinding one, TypeBinding two) { |
106 |
if (one == two) return true; |
91 |
if (one == two) return true; |
Lines 322-396
Link Here
|
322 |
} |
307 |
} |
323 |
|
308 |
|
324 |
void checkInheritedMethods(MethodBinding[] methods, int length) { |
309 |
void checkInheritedMethods(MethodBinding[] methods, int length) { |
325 |
if (length > 1) { |
310 |
/* |
326 |
int[] overriddenInheritedMethods = findOverriddenInheritedMethods(methods, length); |
311 |
1. find concrete method |
327 |
if (overriddenInheritedMethods != null) { |
312 |
2. if it doesn't exist then find first inherited abstract method whose return type is compatible with all others |
328 |
// detected some overridden methods that can be ignored when checking return types |
313 |
if no such method exists then report incompatible return type error |
329 |
// but cannot ignore an overridden inherited method completely when it comes to checking for bridge methods |
314 |
otherwise report abstract method must be implemented |
330 |
int index = 0; |
315 |
3. if concrete method exists, check to see if its return type is compatible with all others |
331 |
MethodBinding[] closestMethods = new MethodBinding[length]; |
316 |
if it is then check concrete method against abstract methods |
332 |
for (int i = 0; i < length; i++) |
317 |
if its not, then find most specific abstract method & report abstract method must be implemented since concrete method is insufficient |
333 |
if (overriddenInheritedMethods[i] == 0) |
318 |
if no most specific return type abstract method exists, then report incompatible return type with all inherited methods |
334 |
closestMethods[index++] = methods[i]; |
319 |
*/ |
335 |
if (index > 1 && !checkInheritedReturnTypes(closestMethods, index)) |
|
|
336 |
return; |
337 |
} else if (!checkInheritedReturnTypes(methods, length)) { |
338 |
return; |
339 |
} |
340 |
} |
341 |
|
320 |
|
342 |
MethodBinding concreteMethod = null; |
321 |
MethodBinding concreteMethod = this.type.isInterface() || methods[0].isAbstract() ? null : methods[0]; |
343 |
if (!this.type.isInterface()) { // ignore concrete methods for interfaces |
|
|
344 |
for (int i = length; --i >= 0;) { // Remember that only one of the methods can be non-abstract |
345 |
if (!methods[i].isAbstract()) { |
346 |
concreteMethod = methods[i]; |
347 |
break; |
348 |
} |
349 |
} |
350 |
} |
351 |
if (concreteMethod == null) { |
322 |
if (concreteMethod == null) { |
352 |
if (!this.type.isAbstract()) { |
323 |
MethodBinding bestAbstractMethod = length == 1 ? methods[0] : findBestInheritedAbstractMethod(methods, length); |
353 |
for (int i = length; --i >= 0;) { |
324 |
if (bestAbstractMethod == null) { |
354 |
if (mustImplementAbstractMethod(methods[i].declaringClass)) { |
325 |
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); |
355 |
TypeDeclaration typeDeclaration = this.type.scope.referenceContext; |
326 |
} else if (mustImplementAbstractMethod(bestAbstractMethod.declaringClass)) { |
356 |
if (typeDeclaration != null) { |
327 |
TypeDeclaration typeDeclaration = this.type.scope.referenceContext; |
357 |
MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(methods[0]); |
328 |
MethodBinding superclassAbstractMethod = methods[0]; |
358 |
missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); |
329 |
if (superclassAbstractMethod == bestAbstractMethod || superclassAbstractMethod.declaringClass.isInterface()) { |
359 |
} else { |
330 |
if (typeDeclaration != null) { |
360 |
problemReporter().abstractMethodMustBeImplemented(this.type, methods[0]); |
331 |
MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(bestAbstractMethod); |
361 |
} |
332 |
missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod); |
362 |
return; |
333 |
} else { |
|
|
334 |
problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod); |
335 |
} |
336 |
} else { |
337 |
if (typeDeclaration != null) { |
338 |
MethodDeclaration missingAbstractMethod = typeDeclaration.addMissingAbstractMethodFor(bestAbstractMethod); |
339 |
missingAbstractMethod.scope.problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod, superclassAbstractMethod); |
340 |
} else { |
341 |
problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod, superclassAbstractMethod); |
363 |
} |
342 |
} |
364 |
} |
343 |
} |
365 |
} |
344 |
} |
366 |
return; |
345 |
return; |
367 |
} |
346 |
} |
|
|
347 |
if (length < 2) return; // nothing else to check |
368 |
|
348 |
|
369 |
if (length > 1) { |
349 |
int index = length; |
370 |
MethodBinding[] abstractMethods = new MethodBinding[length - 1]; |
350 |
while (--index > 0 && checkInheritedReturnTypes(concreteMethod, methods[index])) {/*empty*/} |
371 |
int index = 0; |
351 |
if (index > 0) { |
372 |
for (int i = length; --i >= 0;) |
352 |
// concreteMethod is not the best match |
373 |
if (methods[i] != concreteMethod) |
353 |
MethodBinding bestAbstractMethod = findBestInheritedAbstractMethod(methods, length); |
374 |
abstractMethods[index++] = methods[i]; |
354 |
if (bestAbstractMethod == null) |
375 |
checkConcreteInheritedMethod(concreteMethod, abstractMethods); |
355 |
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); |
|
|
356 |
else // can only happen in >= 1.5 since return types must be equal prior to 1.5 |
357 |
problemReporter().abstractMethodMustBeImplemented(this.type, bestAbstractMethod, concreteMethod); |
358 |
return; |
376 |
} |
359 |
} |
377 |
} |
|
|
378 |
|
360 |
|
379 |
boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) { |
361 |
MethodBinding[] abstractMethods = new MethodBinding[length - 1]; |
380 |
MethodBinding first = methods[0]; |
362 |
index = 0; |
381 |
int index = length; |
363 |
for (int i = 0; i < length; i++) |
382 |
while (--index > 0 && areReturnTypesCompatible(first, methods[index])){/*empty*/} |
364 |
if (methods[i].isAbstract()) |
383 |
if (index == 0) |
365 |
abstractMethods[index++] = methods[i]; |
384 |
return true; |
366 |
if (index < abstractMethods.length) |
385 |
|
367 |
System.arraycopy(abstractMethods, 0, abstractMethods = new MethodBinding[index], 0, index); |
386 |
// All inherited methods do NOT have the same vmSignature |
368 |
checkConcreteInheritedMethod(concreteMethod, abstractMethods); |
387 |
if (this.type.isInterface()) |
369 |
} |
388 |
for (int i = length; --i >= 0;) |
370 |
|
389 |
if (methods[i].declaringClass.id == TypeIds.T_JavaLangObject) |
371 |
boolean checkInheritedReturnTypes(MethodBinding method, MethodBinding otherMethod) { |
390 |
return false; // do not complain since the super interface already got blamed |
372 |
if (areReturnTypesCompatible(method, otherMethod)) return true; |
391 |
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); |
373 |
|
|
|
374 |
if (!this.type.isInterface()) |
375 |
if (method.declaringClass.isClass() || !this.type.implementsInterface(method.declaringClass, false)) |
376 |
if (otherMethod.declaringClass.isClass() || !this.type.implementsInterface(otherMethod.declaringClass, false)) |
377 |
return true; // do not complain since the superclass already got blamed |
378 |
|
392 |
return false; |
379 |
return false; |
393 |
} |
380 |
} |
|
|
381 |
|
394 |
/* |
382 |
/* |
395 |
For each inherited method identifier (message pattern - vm signature minus the return type) |
383 |
For each inherited method identifier (message pattern - vm signature minus the return type) |
396 |
if current method exists |
384 |
if current method exists |
Lines 722-727
Link Here
|
722 |
return null; // noop in 1.4 |
710 |
return null; // noop in 1.4 |
723 |
} |
711 |
} |
724 |
|
712 |
|
|
|
713 |
MethodBinding findBestInheritedAbstractMethod(MethodBinding[] methods, int length) { |
714 |
findMethod : for (int i = 0; i < length; i++) { |
715 |
MethodBinding method = methods[i]; |
716 |
if (!method.isAbstract()) continue findMethod; |
717 |
for (int j = 0; j < length; j++) { |
718 |
if (i == j) continue; |
719 |
if (!checkInheritedReturnTypes(method, methods[j])) { |
720 |
if (this.type.isInterface() && methods[j].declaringClass.id == TypeIds.T_JavaLangObject) |
721 |
return method; // do not complain since the super interface already got blamed |
722 |
continue findMethod; |
723 |
} |
724 |
} |
725 |
return method; |
726 |
} |
727 |
return null; |
728 |
} |
729 |
|
725 |
int[] findOverriddenInheritedMethods(MethodBinding[] methods, int length) { |
730 |
int[] findOverriddenInheritedMethods(MethodBinding[] methods, int length) { |
726 |
// NOTE assumes length > 1 |
731 |
// NOTE assumes length > 1 |
727 |
// inherited methods are added as we walk up the superclass hierarchy, then each superinterface |
732 |
// inherited methods are added as we walk up the superclass hierarchy, then each superinterface |
Lines 809-824
Link Here
|
809 |
boolean mustImplementAbstractMethod(ReferenceBinding declaringClass) { |
814 |
boolean mustImplementAbstractMethod(ReferenceBinding declaringClass) { |
810 |
// if the type's superclass is an abstract class, then all abstract methods must be implemented |
815 |
// if the type's superclass is an abstract class, then all abstract methods must be implemented |
811 |
// otherwise, skip it if the type's superclass must implement any of the inherited methods |
816 |
// otherwise, skip it if the type's superclass must implement any of the inherited methods |
|
|
817 |
if (!mustImplementAbstractMethods()) return false; |
812 |
ReferenceBinding superclass = this.type.superclass(); |
818 |
ReferenceBinding superclass = this.type.superclass(); |
813 |
if (declaringClass.isClass()) { |
819 |
if (declaringClass.isClass()) { |
814 |
while (superclass.isAbstract() && superclass != declaringClass) |
820 |
while (superclass.isAbstract() && superclass != declaringClass) |
815 |
superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass |
821 |
superclass = superclass.superclass(); // find the first concrete superclass or the abstract declaringClass |
816 |
} else { |
822 |
} else { |
817 |
if (this.type.implementsInterface(declaringClass, false)) { |
823 |
if (this.type.implementsInterface(declaringClass, false)) |
818 |
if (this.type.isAbstract()) return false; // leave it for the subclasses |
|
|
819 |
if (!superclass.implementsInterface(declaringClass, true)) // only if a superclass does not also implement the interface |
824 |
if (!superclass.implementsInterface(declaringClass, true)) // only if a superclass does not also implement the interface |
820 |
return true; |
825 |
return true; |
821 |
} |
|
|
822 |
while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false)) |
826 |
while (superclass.isAbstract() && !superclass.implementsInterface(declaringClass, false)) |
823 |
superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface |
827 |
superclass = superclass.superclass(); // find the first concrete superclass or the superclass which implements the interface |
824 |
} |
828 |
} |