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

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java (-7 / +37 lines)
Lines 138-148 Link Here
138
		if (!isAcceptableReturnTypeOverride(currentMethod, inheritedMethod))
138
		if (!isAcceptableReturnTypeOverride(currentMethod, inheritedMethod))
139
			problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
139
			problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
140
140
141
	if (this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original()) != null) {
141
	MethodBinding bridge = this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original());
142
	if (bridge != null) {
142
		for (int i = 0, l = allInheritedMethods == null ? 0 : allInheritedMethods.length; i < l; i++) {
143
		for (int i = 0, l = allInheritedMethods == null ? 0 : allInheritedMethods.length; i < l; i++) {
143
			if (allInheritedMethods[i] != null && detectInheritedNameClash(originalInherited, allInheritedMethods[i].original()))
144
			if (allInheritedMethods[i] != null && detectInheritedNameClash(originalInherited, allInheritedMethods[i].original()))
144
				return;
145
				return;
145
		}
146
		}
147
		// See if the new bridge clashes with any of the user methods of the class. For this check
148
		// we should check for "method descriptor clash" and not just "method signature clash". Really
149
		// what we are checking is whether there is a contention for the method dispatch table slot.
150
		// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=293615.
151
		MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(bridge.selector);
152
		for (int i = current.length - 1; i >= 0; --i) {
153
			final MethodBinding thisMethod = current[i];
154
			if (thisMethod.areParameterErasuresEqual(bridge) && thisMethod.returnType.erasure() == bridge.returnType.erasure()) {
155
				// use inherited method for problem reporting.
156
				problemReporter(thisMethod).methodNameClash(thisMethod, inheritedMethod.declaringClass.isRawType() ? inheritedMethod : inheritedMethod.original());
157
				return;	
158
			}
159
		}
146
	}
160
	}
147
}
161
}
148
void checkForNameClash(MethodBinding currentMethod, MethodBinding inheritedMethod) {
162
void checkForNameClash(MethodBinding currentMethod, MethodBinding inheritedMethod) {
Lines 180-186 Link Here
180
194
181
	if (currentMethod.declaringClass.isInterface() || inheritedMethod.isStatic()) return;
195
	if (currentMethod.declaringClass.isInterface() || inheritedMethod.isStatic()) return;
182
196
183
	if (!detectNameClash(currentMethod, inheritedMethod)) { // check up the hierarchy for skipped inherited methods
197
	if (!detectNameClash(currentMethod, inheritedMethod, false)) { // check up the hierarchy for skipped inherited methods
184
		TypeBinding[] currentParams = currentMethod.parameters;
198
		TypeBinding[] currentParams = currentMethod.parameters;
185
		TypeBinding[] inheritedParams = inheritedMethod.parameters;
199
		TypeBinding[] inheritedParams = inheritedMethod.parameters;
186
		int length = currentParams.length;
200
		int length = currentParams.length;
Lines 204-210 Link Here
204
			MethodBinding[] methods = superType.getMethods(currentMethod.selector);
218
			MethodBinding[] methods = superType.getMethods(currentMethod.selector);
205
			for (int m = 0, n = methods.length; m < n; m++) {
219
			for (int m = 0, n = methods.length; m < n; m++) {
206
				MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
220
				MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
207
				if (substitute != null && !isSubstituteParameterSubsignature(currentMethod, substitute) && detectNameClash(currentMethod, substitute))
221
				if (substitute != null && !isSubstituteParameterSubsignature(currentMethod, substitute) && detectNameClash(currentMethod, substitute, true))
208
					return;
222
					return;
209
			}
223
			}
210
			if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
224
			if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
Lines 232-238 Link Here
232
				MethodBinding[] methods = superType.getMethods(currentMethod.selector);
246
				MethodBinding[] methods = superType.getMethods(currentMethod.selector);
233
				for (int m = 0, n = methods.length; m < n; m++){
247
				for (int m = 0, n = methods.length; m < n; m++){
234
					MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
248
					MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
235
					if (substitute != null && !isSubstituteParameterSubsignature(currentMethod, substitute) && detectNameClash(currentMethod, substitute))
249
					if (substitute != null && !isSubstituteParameterSubsignature(currentMethod, substitute) && detectNameClash(currentMethod, substitute, true))
236
						return;
250
						return;
237
				}
251
				}
238
				if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
252
				if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
Lines 555-565 Link Here
555
	problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited);
569
	problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited);
556
	return true;
570
	return true;
557
}
571
}
558
boolean detectNameClash(MethodBinding current, MethodBinding inherited) {
572
boolean detectNameClash(MethodBinding current, MethodBinding inherited, boolean treatAsSynthetic) {
559
	MethodBinding original = inherited.original(); // can be the same as inherited
573
	MethodBinding methodToCheck = inherited;
574
	if (!treatAsSynthetic) {
575
		// For a user method, see if current class overrides the inherited method. If it does,
576
		// then any grievance we may have ought to be against the current class's method and
577
		// NOT against any super implementations. https://bugs.eclipse.org/bugs/show_bug.cgi?id=293615
578
		MethodBinding[] currentNamesakes = (MethodBinding[]) this.currentMethods.get(inherited.selector);
579
		if (currentNamesakes.length > 1) { // we know it ought to at least one and that current is NOT the override
580
			for (int i = 0, length = currentNamesakes.length; i < length; i++) {
581
				MethodBinding currentMethod = currentNamesakes[i];
582
				if (currentMethod != current && doesMethodOverride(currentMethod, inherited)) {
583
					methodToCheck = currentMethod;
584
					break;
585
				}
586
			}
587
		}
588
	}
589
	MethodBinding original = methodToCheck.original(); // can be the same as inherited
560
	if (!current.areParameterErasuresEqual(original))
590
	if (!current.areParameterErasuresEqual(original))
561
		return false;
591
		return false;
562
592
	original = inherited.original();  // For error reporting use, inherited.original()
563
	problemReporter(current).methodNameClash(current, inherited.declaringClass.isRawType() ? inherited : original);
593
	problemReporter(current).methodNameClash(current, inherited.declaringClass.isRawType() ? inherited : original);
564
	return true;
594
	return true;
565
}
595
}
(-)src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java (+47 lines)
Lines 10684-10687 Link Here
10684
		""
10684
		""
10685
	);
10685
	);
10686
}
10686
}
10687
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=293615 (bad name clash error)
10688
// No user vs user clash or user vs synthetic clash in this test
10689
public void test204() {
10690
	this.runConformTest(
10691
		new String[] {
10692
			"OverrideBug.java",
10693
			"import java.util.List;\n" +
10694
			"interface Map<K, V> {\n" + 
10695
			"	public V put(K key, V value);\n" +
10696
			"}\n" +
10697
			"public class OverrideBug<K, V> implements Map<K, List<V>> {\n" +
10698
			"public List<V> put(final K arg0, final List<V> arg1) {\n" +
10699
			"    return null;\n" +
10700
			"}\n" +
10701
			"public List<V> put(final K arg0, final V arg1) {\n" +
10702
			"    return null;\n" +
10703
			"}\n" +
10704
			"}"
10705
		},
10706
		"");
10707
}
10708
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=293615 (bad name clash error)
10709
// verify that we report user vs bridge clash properly.
10710
public void test204a() {
10711
	this.runNegativeTest(
10712
		new String[] {
10713
			"OverrideBug.java",
10714
			"import java.util.List;\n" +
10715
			"interface Map<K, V> {\n" + 
10716
			"	public V put(K key, V value);\n" +
10717
			"}\n" +
10718
			"public class OverrideBug<K, V> implements Map<K, List<V>> {\n" +
10719
			"public List<V> put(final K arg0, final List<V> arg1) {\n" +
10720
			"    return null;\n" +
10721
			"}\n" +
10722
			"public V put(final K arg0, final V arg1) {\n" +
10723
			"    return null;\n" +
10724
			"}\n" +
10725
			"}"
10726
		},
10727
		"----------\n" + 
10728
		"1. ERROR in OverrideBug.java (at line 9)\n" + 
10729
		"	public V put(final K arg0, final V arg1) {\n" + 
10730
		"	         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" + 
10731
		"Name clash: The method put(K, V) of type OverrideBug<K,V> has the same erasure as put(K, V) of type Map<K,V> but does not override it\n" + 
10732
		"----------\n");
10733
}
10687
}
10734
}

Return to bug 293615