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

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier.java (-27 / +29 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 550-557 Link Here
550
*/
550
*/
551
void computeInheritedMethods(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) {
551
void computeInheritedMethods(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) {
552
	// only want to remember inheritedMethods that can have an impact on the current type
552
	// only want to remember inheritedMethods that can have an impact on the current type
553
	// if an inheritedMethod has been 'replaced' by a supertype's method then skip it
553
	// if an inheritedMethod has been 'replaced' by a supertype's method then skip it, however
554
554
    // see usage of canOverridingMethodDifferInErasure below.
555
	this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
555
	this.inheritedMethods = new HashtableOfObject(51); // maps method selectors to an array of methods... must search to match paramaters & return type
556
	ReferenceBinding[] interfacesToVisit = null;
556
	ReferenceBinding[] interfacesToVisit = null;
557
	int nextPosition = 0;
557
	int nextPosition = 0;
Lines 563-592 Link Here
563
563
564
	ReferenceBinding superType = superclass;
564
	ReferenceBinding superType = superclass;
565
	HashtableOfObject nonVisibleDefaultMethods = new HashtableOfObject(3); // maps method selectors to an array of methods
565
	HashtableOfObject nonVisibleDefaultMethods = new HashtableOfObject(3); // maps method selectors to an array of methods
566
	boolean allSuperclassesAreAbstract = true;
567
566
568
	while (superType != null && superType.isValidBinding()) {
567
	while (superType != null && superType.isValidBinding()) {
569
	    if (allSuperclassesAreAbstract) {
568
		// We used to only include superinterfaces if immediate superclasses are abstract
570
		    if (superType.isAbstract()) {
569
		// but that is problematic. See https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358
571
				// only need to include superinterfaces if immediate superclasses are abstract
570
		if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
572
				if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
571
			if (interfacesToVisit == null) {
573
					if (interfacesToVisit == null) {
572
				interfacesToVisit = itsInterfaces;
574
						interfacesToVisit = itsInterfaces;
573
				nextPosition = interfacesToVisit.length;
575
						nextPosition = interfacesToVisit.length;
576
					} else {
577
						int itsLength = itsInterfaces.length;
578
						if (nextPosition + itsLength >= interfacesToVisit.length)
579
							System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
580
						nextInterface : for (int a = 0; a < itsLength; a++) {
581
							ReferenceBinding next = itsInterfaces[a];
582
							for (int b = 0; b < nextPosition; b++)
583
								if (next == interfacesToVisit[b]) continue nextInterface;
584
							interfacesToVisit[nextPosition++] = next;
585
						}
586
					}
587
				}
588
			} else {
574
			} else {
589
			    allSuperclassesAreAbstract = false;
575
				int itsLength = itsInterfaces.length;
576
				if (nextPosition + itsLength >= interfacesToVisit.length)
577
					System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
578
				nextInterface : for (int a = 0; a < itsLength; a++) {
579
					ReferenceBinding next = itsInterfaces[a];
580
					for (int b = 0; b < nextPosition; b++)
581
						if (next == interfacesToVisit[b]) continue nextInterface;
582
					interfacesToVisit[nextPosition++] = next;
583
				}
590
			}
584
			}
591
		}
585
		}
592
586
Lines 599-605 Link Here
599
			if (existingMethods != null) {
593
			if (existingMethods != null) {
600
				existing : for (int i = 0, length = existingMethods.length; i < length; i++) {
594
				existing : for (int i = 0, length = existingMethods.length; i < length; i++) {
601
					MethodBinding existingMethod = existingMethods[i];
595
					MethodBinding existingMethod = existingMethods[i];
602
					if (existingMethod.declaringClass != inheritedMethod.declaringClass && areMethodsCompatible(existingMethod, inheritedMethod)) {
596
					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358, skip inherited method only if any overriding version
597
					// in a subclass is guaranteed to have the same erasure as an existing method.
598
					if (existingMethod.declaringClass != inheritedMethod.declaringClass && areMethodsCompatible(existingMethod, inheritedMethod) && !canOverridingMethodDifferInErasure(existingMethod, inheritedMethod)) {
603
						if (inheritedMethod.isDefault()) {
599
						if (inheritedMethod.isDefault()) {
604
							if (inheritedMethod.isAbstract()) {
600
							if (inheritedMethod.isAbstract()) {
605
								checkPackagePrivateAbstractMethod(inheritedMethod);
601
								checkPackagePrivateAbstractMethod(inheritedMethod);
Lines 681-688 Link Here
681
				} else {
677
				} else {
682
					int length = existingMethods.length;
678
					int length = existingMethods.length;
683
					// look to see if any of the existingMethods implement this inheritedMethod
679
					// look to see if any of the existingMethods implement this inheritedMethod
680
					// https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358, skip inherited method only if any overriding version
681
					// in a subclass is guaranteed to have the same erasure as an existing method.
684
					for (int e = 0; e < length; e++)
682
					for (int e = 0; e < length; e++)
685
						if (isInterfaceMethodImplemented(inheritedMethod, existingMethods[e], superType))
683
						if (isInterfaceMethodImplemented(inheritedMethod, existingMethods[e], superType) && !canOverridingMethodDifferInErasure(existingMethods[e], inheritedMethod))
686
							continue nextMethod; // skip interface method with the same signature if visible to its declaringClass
684
							continue nextMethod; // skip interface method with the same signature if visible to its declaringClass
687
					System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
685
					System.arraycopy(existingMethods, 0, existingMethods = new MethodBinding[length + 1], 0, length);
688
					existingMethods[length] = inheritedMethod;
686
					existingMethods[length] = inheritedMethod;
Lines 692-698 Link Here
692
		}
690
		}
693
	}
691
	}
694
}
692
}
695
693
// Given `overridingMethod' which overrides `inheritedMethod' answer whether some subclass method that
694
// differs in erasure from overridingMethod could override `inheritedMethod'
695
protected boolean canOverridingMethodDifferInErasure(MethodBinding overridingMethod, MethodBinding inheritedMethod) {
696
	return false;   // the case for <= 1.4  (cannot differ)
697
}
696
void computeMethods() {
698
void computeMethods() {
697
	MethodBinding[] methods = this.type.methods();
699
	MethodBinding[] methods = this.type.methods();
698
	int size = methods.length;
700
	int size = methods.length;
(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java (-3 / +16 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
 * Copyright (c) 2000, 2009 IBM Corporation and others.
2
 * Copyright (c) 2000, 2010 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 96-101 Link Here
96
	//		return ((UnresolvedReferenceBinding) two).resolvedType == one;
96
	//		return ((UnresolvedReferenceBinding) two).resolvedType == one;
97
	return false; // all other type bindings are identical
97
	return false; // all other type bindings are identical
98
}
98
}
99
// Given `overridingMethod' which overrides `inheritedMethod' answer whether some subclass method that
100
// differs in erasure from overridingMethod could override `inheritedMethod'
101
protected boolean canOverridingMethodDifferInErasure(MethodBinding overridingMethod, MethodBinding inheritedMethod) {
102
	if (overridingMethod.areParameterErasuresEqual(inheritedMethod))
103
		return false;  // no further change in signature is possible due to parameterization.
104
	if (overridingMethod.declaringClass.isRawType())
105
		return false;  // no parameterization is happening anyways.
106
	return true;
107
}
99
boolean canSkipInheritedMethods() {
108
boolean canSkipInheritedMethods() {
100
	if (this.type.superclass() != null)
109
	if (this.type.superclass() != null)
101
		if (this.type.superclass().isAbstract() || this.type.superclass().isParameterizedType())
110
		if (this.type.superclass().isAbstract() || this.type.superclass().isParameterizedType())
Lines 577-586 Link Here
577
boolean detectInheritedNameClash(MethodBinding inherited, MethodBinding otherInherited) {
586
boolean detectInheritedNameClash(MethodBinding inherited, MethodBinding otherInherited) {
578
	if (!inherited.areParameterErasuresEqual(otherInherited))
587
	if (!inherited.areParameterErasuresEqual(otherInherited))
579
		return false;
588
		return false;
580
	// skip it if otherInherited is defined by a subtype of inherited's declaringClass
589
	// skip it if otherInherited is defined by a subtype of inherited's declaringClass or vice versa.
581
	if (inherited.declaringClass.erasure() != otherInherited.declaringClass.erasure())
590
	// avoid being order sensitive and check with the roles reversed also.
591
	if (inherited.declaringClass.erasure() != otherInherited.declaringClass.erasure()) {
582
		if (inherited.declaringClass.findSuperTypeOriginatingFrom(otherInherited.declaringClass) != null)
592
		if (inherited.declaringClass.findSuperTypeOriginatingFrom(otherInherited.declaringClass) != null)
583
			return false;
593
			return false;
594
		if (otherInherited.declaringClass.findSuperTypeOriginatingFrom(inherited.declaringClass) != null)
595
			return false;
596
	}
584
597
585
	problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited);
598
	problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited);
586
	return true;
599
	return true;
(-)src/org/eclipse/jdt/core/tests/compiler/regression/AmbiguousMethodTest.java (+162 lines)
Lines 3528-3531 Link Here
3528
		},
3528
		},
3529
		"SUCCESS");
3529
		"SUCCESS");
3530
}
3530
}
3531
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358
3532
public void test081() {
3533
	this.runConformTest(
3534
		new String[] {
3535
			"C.java",
3536
			"class A<ModelType extends D, ValueType> implements I<ModelType, ValueType> {\n" +
3537
			"    public void doSet(ModelType valueGetter) {\n" +
3538
			"        this.set((ValueType) valueGetter.getObject());\n" +
3539
			"    }\n" +
3540
			"    public void set(Object object) {\n" +
3541
			"        System.out.println(\"In A.set(Object)\");\n" +
3542
			"    }\n" +
3543
			"}\n" +
3544
			"class B extends A<E, CharSequence> {\n" +
3545
			"	public void set(CharSequence string) {\n" +
3546
			"        System.out.println(\"In B.set(CharSequence)\");\n" +
3547
			"    }\n" +
3548
			"}\n" +
3549
			"public class C extends B {\n" +
3550
			"    static public void main(String[] args) {\n" +
3551
			"        C c = new C();\n" +
3552
			"        c.run();\n" +
3553
			"    }\n" +
3554
			"    public void run() {\n" +
3555
			"        E e = new E<String>(String.class);\n" +
3556
			"        this.doSet(e);\n" +
3557
			"    }\n" +
3558
			"}\n" +
3559
			"class D {\n" +
3560
			"    public Object getObject() {\n" +
3561
			"        return null;\n" +
3562
			"    }\n" +
3563
			"}\n" +
3564
			"class E<Type extends CharSequence> extends D {\n" +
3565
			"    private Class<Type> typeClass;\n" +
3566
			"    public E(Class<Type> typeClass) {\n" +
3567
			"        this.typeClass = typeClass;\n" +
3568
			"    }\n" +
3569
			"    public Type getObject() {\n" +
3570
			"        try {\n" +
3571
			"            return (Type) typeClass.newInstance();\n" +
3572
			"        } catch (Exception e) {\n" +
3573
			"            throw new RuntimeException(e);\n" +
3574
			"        }\n" +
3575
			"    }\n" +
3576
			"}\n" +
3577
			"interface I<ModelType, ValueType> {\n" +
3578
			"    public void doSet(ModelType model);\n" +
3579
			"    public void set(ValueType value);\n" +
3580
			"}\n"
3581
3582
		},
3583
		"In B.set(CharSequence)");
3584
}
3585
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358
3586
public void test082() {
3587
	this.runConformTest(
3588
		new String[] {
3589
			"C.java",
3590
			"class A<ModelType extends D, ValueType> extends I<ModelType, ValueType> {\n" +
3591
			"    public void doSet(ModelType valueGetter) {\n" +
3592
			"        this.set((ValueType) valueGetter.getObject());\n" +
3593
			"    }\n" +
3594
			"    public void set(Object object) {\n" +
3595
			"        System.out.println(\"In A.set(Object)\");\n" +
3596
			"    }\n" +
3597
			"}\n" +
3598
			"class B extends A<E, CharSequence> {\n" +
3599
			"	public void set(CharSequence string) {\n" +
3600
			"        System.out.println(\"In B.set(CharSequence)\");\n" +
3601
			"    }\n" +
3602
			"}\n" +
3603
			"public class C extends B {\n" +
3604
			"    static public void main(String[] args) {\n" +
3605
			"        C c = new C();\n" +
3606
			"        c.run();\n" +
3607
			"    }\n" +
3608
			"    public void run() {\n" +
3609
			"        E e = new E<String>(String.class);\n" +
3610
			"        this.doSet(e);\n" +
3611
			"    }\n" +
3612
			"}\n" +
3613
			"class D {\n" +
3614
			"    public Object getObject() {\n" +
3615
			"        return null;\n" +
3616
			"    }\n" +
3617
			"}\n" +
3618
			"class E<Type extends CharSequence> extends D {\n" +
3619
			"    private Class<Type> typeClass;\n" +
3620
			"    public E(Class<Type> typeClass) {\n" +
3621
			"        this.typeClass = typeClass;\n" +
3622
			"    }\n" +
3623
			"    public Type getObject() {\n" +
3624
			"        try {\n" +
3625
			"            return (Type) typeClass.newInstance();\n" +
3626
			"        } catch (Exception e) {\n" +
3627
			"            throw new RuntimeException(e);\n" +
3628
			"        }\n" +
3629
			"    }\n" +
3630
			"}\n" +
3631
			"abstract class I<ModelType, ValueType> {\n" +
3632
			"    public abstract void doSet(ModelType model);\n" +
3633
			"    public abstract void set(ValueType value);\n" +
3634
			"}\n"
3635
3636
		},
3637
		"In B.set(CharSequence)");
3638
}
3639
// https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358
3640
public void test083() {
3641
	this.runConformTest(
3642
		new String[] {
3643
			"C.java",
3644
			"class A<ModelType extends D, ValueType> implements I<ModelType, ValueType> {\n" +
3645
			"    public void doSet(ModelType valueGetter) {\n" +
3646
			"        this.set((ValueType) valueGetter.getObject());\n" +
3647
			"    }\n" +
3648
			"    public void set(Object object) {\n" +
3649
			"        System.out.println(\"In A.set(Object)\");\n" +
3650
			"    }\n" +
3651
			"}\n" +
3652
			"class B extends A<E, CharSequence> implements I<E, CharSequence> {\n" +
3653
			"	public void set(CharSequence string) {\n" +
3654
			"        System.out.println(\"In B.set(CharSequence)\");\n" +
3655
			"    }\n" +
3656
			"}\n" +
3657
			"public class C extends B {\n" +
3658
			"    static public void main(String[] args) {\n" +
3659
			"        C c = new C();\n" +
3660
			"        c.run();\n" +
3661
			"    }\n" +
3662
			"    public void run() {\n" +
3663
			"        E e = new E<String>(String.class);\n" +
3664
			"        this.doSet(e);\n" +
3665
			"    }\n" +
3666
			"}\n" +
3667
			"class D {\n" +
3668
			"    public Object getObject() {\n" +
3669
			"        return null;\n" +
3670
			"    }\n" +
3671
			"}\n" +
3672
			"class E<Type extends CharSequence> extends D {\n" +
3673
			"    private Class<Type> typeClass;\n" +
3674
			"    public E(Class<Type> typeClass) {\n" +
3675
			"        this.typeClass = typeClass;\n" +
3676
			"    }\n" +
3677
			"    public Type getObject() {\n" +
3678
			"        try {\n" +
3679
			"            return (Type) typeClass.newInstance();\n" +
3680
			"        } catch (Exception e) {\n" +
3681
			"            throw new RuntimeException(e);\n" +
3682
			"        }\n" +
3683
			"    }\n" +
3684
			"}\n" +
3685
			"interface I<ModelType, ValueType> {\n" +
3686
			"    public void doSet(ModelType model);\n" +
3687
			"    public void set(ValueType value);\n" +
3688
			"}\n"
3689
3690
		},
3691
		"In B.set(CharSequence)");
3692
}
3531
}
3693
}

Return to bug 302358