View | Details | Raw Unified | Return to bug 249134 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java (-9 / +87 lines)
Lines 771-777 Link Here
771
			"1. ERROR in X.java (at line 1)\r\n" +
771
			"1. ERROR in X.java (at line 1)\r\n" +
772
			"	abstract class X6 extends A implements I {}\r\n" +
772
			"	abstract class X6 extends A implements I {}\r\n" +
773
			"	               ^^\n" +
773
			"	               ^^\n" +
774
			"The return type is incompatible with I.foo(), A.foo()\n" +
774
			"The type X6 must implement the inherited abstract method I.foo() to override A.foo()\n" +
775
			"----------\n"
775
			"----------\n"
776
		);
776
		);
777
	}
777
	}
Lines 7858-7864 Link Here
7858
		"1. ERROR in X.java (at line 1)\n" +
7858
		"1. ERROR in X.java (at line 1)\n" +
7859
		"	public abstract class X implements J, K {}\n" +
7859
		"	public abstract class X implements J, K {}\n" +
7860
		"	                      ^\n" +
7860
		"	                      ^\n" +
7861
		"The return type is incompatible with K.foo(Number), J.foo(Number)\n" +
7861
		"The return type is incompatible with I.foo(Number), K.foo(Number), J.foo(Number)\n" +
7862
		"----------\n" +
7862
		"----------\n" +
7863
		"2. WARNING in X.java (at line 6)\n" +
7863
		"2. WARNING in X.java (at line 6)\n" +
7864
		"	XX foo(Number n);\n" +
7864
		"	XX foo(Number n);\n" +
Lines 7957-7967 Link Here
7957
		"	public List<Pet> getPets() { return null; }\n" +
7957
		"	public List<Pet> getPets() { return null; }\n" +
7958
		"	       ^^^^\n" +
7958
		"	       ^^^^\n" +
7959
		"Type safety: The return type List<Pet> for getPets() from the type CatShopImpl needs unchecked conversion to conform to List<? extends Cat> from the type CatShop\n" +
7959
		"Type safety: The return type List<Pet> for getPets() from the type CatShopImpl needs unchecked conversion to conform to List<? extends Cat> from the type CatShop\n" +
7960
		"----------\n" +
7961
		"2. WARNING in PurebredCatShopImpl.java (at line 12)\n" +
7962
		"	class PurebredCatShopImpl extends CatShopImpl implements PurebredCatShop {}\n" +
7963
		"	      ^^^^^^^^^^^^^^^^^^^\n" +
7964
		"Type safety: The return type List<Pet> for getPets() from the type CatShopImpl needs unchecked conversion to conform to List<? extends Cat> from the type CatShop\n" +
7965
		"----------\n"
7960
		"----------\n"
7966
	);
7961
	);
7967
}
7962
}
Lines 8658-8664 Link Here
8658
		"1. ERROR in Concrete.java (at line 12)\r\n" +
8653
		"1. ERROR in Concrete.java (at line 12)\r\n" +
8659
		"	class Concrete extends HalfConcrete implements I<Object, String> {}\r\n" +
8654
		"	class Concrete extends HalfConcrete implements I<Object, String> {}\r\n" +
8660
		"	      ^^^^^^^^\n" +
8655
		"	      ^^^^^^^^\n" +
8661
		"The return type is incompatible with I<Object,String>.foo(String), HalfGenericSuper.foo(String)\n" +
8656
		"The type Concrete must implement the inherited abstract method I<Object,String>.foo(String) to override HalfGenericSuper.foo(String)\n" +
8662
		"----------\n"
8657
		"----------\n"
8663
	);
8658
	);
8664
}
8659
}
Lines 8927-8933 Link Here
8927
		"1. ERROR in X.java (at line 1)\n" + 
8922
		"1. ERROR in X.java (at line 1)\n" + 
8928
		"	class X extends Y implements I { }\n" + 
8923
		"	class X extends Y implements I { }\n" + 
8929
		"	      ^\n" + 
8924
		"	      ^\n" + 
8930
		"The type X must implement the inherited abstract method Y.m()\n" + 
8925
		"The type X must implement the inherited abstract method I.m() to override Y.m()\n" + 
8931
		"----------\n"
8926
		"----------\n"
8932
	);
8927
	);
8933
}
8928
}
Lines 9089-9092 Link Here
9089
		"----------\n"
9084
		"----------\n"
9090
	);
9085
	);
9091
}
9086
}
9087
9088
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=249134
9089
public void test180() {
9090
	this.runNegativeTest(
9091
		new String[] {
9092
			"B.java",
9093
			"interface I {\n" +
9094
			"	String m();\n" +
9095
			"	Object n();\n" +
9096
			"}\n" +
9097
			"abstract class A {\n" +
9098
			"	abstract Object m();\n" +
9099
			"	abstract String n();\n" +
9100
			"}\n" +
9101
			"class B extends A implements I {}\n" +
9102
			"class A2 {\n" +
9103
			"	abstract Object m();\n" +
9104
			"	abstract String n();\n" +
9105
			"}\n" +
9106
			"class B2 extends A2 implements I {}"
9107
		},
9108
		"----------\n" + 
9109
		"1. ERROR in B.java (at line 9)\n" + 
9110
		"	class B extends A implements I {}\n" + 
9111
		"	      ^\n" + 
9112
		"The type B must implement the inherited abstract method A.n()\n" + 
9113
		"----------\n" + 
9114
		"2. ERROR in B.java (at line 9)\n" + 
9115
		"	class B extends A implements I {}\n" + 
9116
		"	      ^\n" + 
9117
		"The type B must implement the inherited abstract method I.m() to override A.m()\n" + 
9118
		"----------\n" + 
9119
		"3. ERROR in B.java (at line 11)\n" + 
9120
		"	abstract Object m();\n" + 
9121
		"	                ^^^\n" + 
9122
		"The abstract method m in type A2 can only be defined by an abstract class\n" + 
9123
		"----------\n" + 
9124
		"4. ERROR in B.java (at line 12)\n" + 
9125
		"	abstract String n();\n" + 
9126
		"	                ^^^\n" + 
9127
		"The abstract method n in type A2 can only be defined by an abstract class\n" + 
9128
		"----------\n" + 
9129
		"5. ERROR in B.java (at line 14)\n" + 
9130
		"	class B2 extends A2 implements I {}\n" + 
9131
		"	      ^^\n" + 
9132
		"The type B2 must implement the inherited abstract method I.m() to override A2.m()\n" + 
9133
		"----------\n"
9134
	);
9135
}
9136
9137
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=249134
9138
public void test181() {
9139
	this.runNegativeTest(
9140
		new String[] {
9141
			"B.java",
9142
			"interface I {\n" +
9143
			"	String m();\n" +
9144
			"	Object n();\n" +
9145
			"}\n" +
9146
			"class A {\n" +
9147
			"	public Object m() { return null; }\n" +
9148
			"	public String n() { return null; }\n" +
9149
			"}\n" +
9150
			"class B extends A implements I {}\n" +
9151
			"abstract class A2 {\n" +
9152
			"	public Object m() { return null; }\n" +
9153
			"	public String n() { return null; }\n" +
9154
			"}\n" +
9155
			"class B2 extends A2 implements I {}"
9156
		},
9157
		"----------\n" + 
9158
		"1. ERROR in B.java (at line 9)\n" + 
9159
		"	class B extends A implements I {}\n" + 
9160
		"	      ^\n" + 
9161
		"The type B must implement the inherited abstract method I.m() to override A.m()\n" + 
9162
		"----------\n" + 
9163
		"2. ERROR in B.java (at line 14)\n" + 
9164
		"	class B2 extends A2 implements I {}\n" + 
9165
		"	      ^^\n" + 
9166
		"The type B2 must implement the inherited abstract method I.m() to override A2.m()\n" + 
9167
		"----------\n"
9168
	);
9169
}
9092
}
9170
}
(-)src/org/eclipse/jdt/core/tests/compiler/regression/CompilerInvocationTests.java (+2 lines)
Lines 631-636 Link Here
631
		expectedProblemAttributes.put("IllegalVararg", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
631
		expectedProblemAttributes.put("IllegalVararg", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
632
		expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
632
		expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
633
		expectedProblemAttributes.put("MissingSynchronizedModifierInInheritedMethod", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
633
		expectedProblemAttributes.put("MissingSynchronizedModifierInInheritedMethod", new ProblemAttributes(CategorizedProblem.CAT_POTENTIAL_PROGRAMMING_PROBLEM));
634
		expectedProblemAttributes.put("AbstractMethodMustBeImplementedOverConcreteMethod", new ProblemAttributes(CategorizedProblem.CAT_MEMBER));
634
		expectedProblemAttributes.put("CodeSnippetMissingClass", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
635
		expectedProblemAttributes.put("CodeSnippetMissingClass", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
635
		expectedProblemAttributes.put("CodeSnippetMissingMethod", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
636
		expectedProblemAttributes.put("CodeSnippetMissingMethod", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
636
		expectedProblemAttributes.put("CannotUseSuperInCodeSnippet", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
637
		expectedProblemAttributes.put("CannotUseSuperInCodeSnippet", new ProblemAttributes(CategorizedProblem.CAT_INTERNAL));
Lines 1253-1258 Link Here
1253
		expectedProblemAttributes.put("IllegalVararg", SKIP);
1254
		expectedProblemAttributes.put("IllegalVararg", SKIP);
1254
		expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(JavaCore.COMPILER_PB_OVERRIDING_METHOD_WITHOUT_SUPER_INVOCATION));
1255
		expectedProblemAttributes.put("OverridingMethodWithoutSuperInvocation", new ProblemAttributes(JavaCore.COMPILER_PB_OVERRIDING_METHOD_WITHOUT_SUPER_INVOCATION));
1255
		expectedProblemAttributes.put("MissingSynchronizedModifierInInheritedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_MISSING_SYNCHRONIZED_ON_INHERITED_METHOD));
1256
		expectedProblemAttributes.put("MissingSynchronizedModifierInInheritedMethod", new ProblemAttributes(JavaCore.COMPILER_PB_MISSING_SYNCHRONIZED_ON_INHERITED_METHOD));
1257
		expectedProblemAttributes.put("AbstractMethodMustBeImplementedOverConcreteMethod", SKIP);
1256
		expectedProblemAttributes.put("CodeSnippetMissingClass", SKIP);
1258
		expectedProblemAttributes.put("CodeSnippetMissingClass", SKIP);
1257
		expectedProblemAttributes.put("CodeSnippetMissingMethod", SKIP);
1259
		expectedProblemAttributes.put("CodeSnippetMissingMethod", SKIP);
1258
		expectedProblemAttributes.put("CannotUseSuperInCodeSnippet", SKIP);
1260
		expectedProblemAttributes.put("CannotUseSuperInCodeSnippet", SKIP);
(-)src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java (-1 / +1 lines)
Lines 41814-41820 Link Here
41814
		"4. ERROR in X.java (at line 13)\n" +
41814
		"4. ERROR in X.java (at line 13)\n" +
41815
		"	public interface CombinedSubInterface extends SubInterface, OtherSubInterface {}\n" +
41815
		"	public interface CombinedSubInterface extends SubInterface, OtherSubInterface {}\n" +
41816
		"	                 ^^^^^^^^^^^^^^^^^^^^\n" +
41816
		"	                 ^^^^^^^^^^^^^^^^^^^^\n" +
41817
		"The return type is incompatible with X.OtherSubInterface.and(X.SuperInterface), X.SubInterface.and(X.SuperInterface)\n" +
41817
		"The return type is incompatible with X.SuperInterface.and(X.SuperInterface), X.OtherSubInterface.and(X.SuperInterface), X.SubInterface.and(X.SuperInterface)\n" +
41818
		"----------\n" +
41818
		"----------\n" +
41819
		"5. WARNING in X.java (at line 15)\n" +
41819
		"5. WARNING in X.java (at line 15)\n" +
41820
		"	public interface OtherSubInterface extends SuperInterface {\n" +
41820
		"	public interface OtherSubInterface extends SuperInterface {\n" +
(-)compiler/org/eclipse/jdt/core/compiler/IProblem.java (+1 lines)
Lines 778-783 Link Here
778
	int OverridingMethodWithoutSuperInvocation = MethodRelated + 416;
778
	int OverridingMethodWithoutSuperInvocation = MethodRelated + 416;
779
	/** @since 3.5 */
779
	/** @since 3.5 */
780
	int MissingSynchronizedModifierInInheritedMethod= MethodRelated + 417;
780
	int MissingSynchronizedModifierInInheritedMethod= MethodRelated + 417;
781
	int AbstractMethodMustBeImplementedOverConcreteMethod = MethodRelated + 418;
781
782
782
	// code snippet support
783
	// code snippet support
783
	int CodeSnippetMissingClass = Internal + 420;
784
	int CodeSnippetMissingClass = Internal + 420;
(-)compiler/org/eclipse/jdt/internal/compiler/problem/messages.properties (+1 lines)
Lines 352-357 Link Here
352
415 = The variable argument type {0} of the method {1} must be the last parameter
352
415 = The variable argument type {0} of the method {1} must be the last parameter
353
416 = The method {0} is overriding a method without making a super invocation
353
416 = The method {0} is overriding a method without making a super invocation
354
417 = The method {0}.{1}({2}) is overriding a synchronized method without being synchronized
354
417 = The method {0}.{1}({2}) is overriding a synchronized method without being synchronized
355
418 = The type {3} must implement the inherited abstract method {2}.{0}({1}) to override {6}.{4}({5})
355
356
356
420 = Code snippet support cannot find the class {0}
357
420 = Code snippet support cannot find the class {0}
357
421 = Code snippet support cannot find the method {0}.{1}({2}) 
358
421 = Code snippet support cannot find the method {0}.{1}({2}) 
(-)compiler/org/eclipse/jdt/internal/compiler/problem/ProblemReporter.java (+26 lines)
Lines 531-536 Link Here
531
			type.sourceEnd());
531
			type.sourceEnd());
532
	}
532
	}
533
}
533
}
534
public void abstractMethodMustBeImplemented(SourceTypeBinding type, MethodBinding abstractMethod, MethodBinding concreteMethod) {
535
	this.handle(
536
		// Must implement the inherited abstract method %1
537
		// 8.4.3 - Every non-abstract subclass of an abstract type, A, must provide a concrete implementation of all of A's methods.
538
		IProblem.AbstractMethodMustBeImplementedOverConcreteMethod,
539
		new String[] {
540
		        new String(abstractMethod.selector),
541
		        typesAsString(abstractMethod.isVarargs(), abstractMethod.parameters, false),
542
		        new String(abstractMethod.declaringClass.readableName()),
543
		        new String(type.readableName()),
544
		        new String(concreteMethod.selector),
545
		        typesAsString(concreteMethod.isVarargs(), concreteMethod.parameters, false),
546
		        new String(concreteMethod.declaringClass.readableName()),
547
		},
548
		new String[] {
549
		        new String(abstractMethod.selector),
550
		        typesAsString(abstractMethod.isVarargs(), abstractMethod.parameters, true),
551
		        new String(abstractMethod.declaringClass.shortReadableName()),
552
		        new String(type.shortReadableName()),
553
		        new String(concreteMethod.selector),
554
		        typesAsString(concreteMethod.isVarargs(), concreteMethod.parameters, true),
555
		        new String(concreteMethod.declaringClass.shortReadableName()),
556
		},
557
		type.sourceStart(),
558
		type.sourceEnd());
559
}
534
public void abstractMethodNeedingNoBody(AbstractMethodDeclaration method) {
560
public void abstractMethodNeedingNoBody(AbstractMethodDeclaration method) {
535
	this.handle(
561
	this.handle(
536
		IProblem.BodyForAbstractMethod,
562
		IProblem.BodyForAbstractMethod,
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java (-29 / +12 lines)
Lines 359-396 Link Here
359
359
360
	super.checkInheritedMethods(methods, length);
360
	super.checkInheritedMethods(methods, length);
361
}
361
}
362
boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) {
362
boolean checkInheritedReturnTypes(MethodBinding method, MethodBinding otherMethod) {
363
	// assumes length > 1
363
	if (areReturnTypesCompatible(method, otherMethod)) return true;
364
	// its possible in 1.5 that A is compatible with B & C, but B is not compatible with C
364
365
	// so find 1 method that is compatible with every other method
365
	if (!this.type.isInterface())
366
	// abstract classes must check every method against each other
366
		if (method.declaringClass.isClass() || !this.type.implementsInterface(method.declaringClass, false))
367
	// but if first method is concrete, then only check it against the rest
367
			if (otherMethod.declaringClass.isClass() || !this.type.implementsInterface(otherMethod.declaringClass, false))
368
	match : for (int i = 0, l = methods[0].isAbstract() ? length - 1 : 0; i <= l; i++) {
368
				return true; // do not complain since the superclass already got blamed
369
		MethodBinding method = methods[i];
369
370
		next : for (int j = 0; j < length; j++) {
370
	// check to see if this is just a warning, if so report it & skip to next method
371
			if (i == j) continue;
371
	if (isUnsafeReturnTypeOverride(method, otherMethod)) {
372
			if (!areReturnTypesCompatible(method, methods[j])) {
372
		if (!method.declaringClass.implementsInterface(otherMethod.declaringClass, false))
373
				if (this.type.isInterface()) {
373
			problemReporter(method).unsafeReturnTypeOverride(method, otherMethod, this.type);
374
					for (int m = length; --m >= 0;)
375
						if (methods[m].declaringClass.id == TypeIds.T_JavaLangObject)
376
							return true; // do not complain since the super interface already got blamed
377
				} else {
378
					if (method.declaringClass.isClass() || !this.type.implementsInterface(method.declaringClass, false))
379
						if (methods[j].declaringClass.isClass() || !this.type.implementsInterface(methods[j].declaringClass, false))
380
							continue next; // do not complain since the superclass already got blamed
381
				}
382
				// check to see if this is just a warning, if so report it & skip to next method
383
				if (isUnsafeReturnTypeOverride(method, methods[j])) {
384
					problemReporter(method).unsafeReturnTypeOverride(method, methods[j], this.type);
385
					continue next;
386
				}
387
				continue match;
388
			}
389
		}
390
		return true;
374
		return true;
391
	}
375
	}
392
376
393
	problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length);
394
	return false;
377
	return false;
395
}
378
}
396
void checkMethods() {
379
void checkMethods() {
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java (-79 / +83 lines)
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
	}

Return to bug 249134