Bug 388795 - [compiler] detection of name clash depends on order of
super interfaces
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
index 7275093..f1d2111 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/GenericTypeTest.java
@@ -7,7 +7,9 @@
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- *     Stephan Herrmann - Contribution for bug 383690 - [compiler] location of error re uninitialized final field should be aligned
+ *     Stephan Herrmann - Contributions for
+ *								bug 383690 - [compiler] location of error re uninitialized final field should be aligned
+ *								bug 388795 - [compiler] detection of name clash depends on order of super interfaces
  *******************************************************************************/
 package org.eclipse.jdt.core.tests.compiler.regression;
 
@@ -42809,7 +42811,7 @@
 		"4. ERROR in X.java (at line 13)\n" +
 		"	public interface CombinedSubInterface extends SubInterface, OtherSubInterface {}\n" +
 		"	                 ^^^^^^^^^^^^^^^^^^^^\n" +
-		"The return types are incompatible for the inherited methods X.SuperInterface.and(X.SuperInterface), X.OtherSubInterface.and(X.SuperInterface), X.SubInterface.and(X.SuperInterface)\n" +
+		"The return types are incompatible for the inherited methods X.OtherSubInterface.and(X.SuperInterface), X.SubInterface.and(X.SuperInterface)\n" +
 		"----------\n" +
 		"5. WARNING in X.java (at line 15)\n" +
 		"	public interface OtherSubInterface extends SuperInterface {\n" +
diff --git a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
index 53f8c5b..079991d 100644
--- a/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
+++ b/org.eclipse.jdt.core.tests.compiler/src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java
@@ -7,6 +7,8 @@
  *
  * Contributors:
  *     IBM Corporation - initial API and implementation
+ *     Stephan Herrmann - Contribution for
+ *								bug 388795 - [compiler] detection of name clash depends on order of super interfaces
  *******************************************************************************/
 package org.eclipse.jdt.core.tests.compiler.regression;
 
@@ -2491,32 +2493,27 @@
 			"Name clash: The method foo(A<String>) of type K has the same erasure as foo(A) of type I but does not override it\n" + 
 			"----------\n" : 
 				"----------\n" + 
-				"1. ERROR in X.java (at line 2)\n" + 
-				"	abstract class Y implements J, I { }\n" + 
-				"	               ^\n" + 
-				"Name clash: The method foo(A<String>) of type J has the same erasure as foo(A) of type I but does not override it\n" + 
-				"----------\n" + 
-				"2. WARNING in X.java (at line 4)\n" + 
+				"1. WARNING in X.java (at line 4)\n" + 
 				"	class YYY implements J, I { public void foo(A a) {} }\n" + 
 				"	                                            ^\n" + 
 				"A is a raw type. References to generic type A<T> should be parameterized\n" + 
 				"----------\n" + 
-				"3. WARNING in X.java (at line 5)\n" + 
+				"2. WARNING in X.java (at line 5)\n" + 
 				"	class XXX implements I, J { public void foo(A a) {} }\n" + 
 				"	                                            ^\n" + 
 				"A is a raw type. References to generic type A<T> should be parameterized\n" + 
 				"----------\n" + 
-				"4. WARNING in X.java (at line 6)\n" + 
+				"3. WARNING in X.java (at line 6)\n" + 
 				"	class ZZZ implements K { public void foo(A a) {} }\n" + 
 				"	                                         ^\n" + 
 				"A is a raw type. References to generic type A<T> should be parameterized\n" + 
 				"----------\n" + 
-				"5. WARNING in X.java (at line 7)\n" + 
+				"4. WARNING in X.java (at line 7)\n" + 
 				"	interface I { void foo(A a); }\n" + 
 				"	                       ^\n" + 
 				"A is a raw type. References to generic type A<T> should be parameterized\n" + 
 				"----------\n" + 
-				"6. ERROR in X.java (at line 9)\n" + 
+				"5. ERROR in X.java (at line 9)\n" + 
 				"	interface K extends I { void foo(A<String> a); }\n" + 
 				"	                             ^^^^^^^^^^^^^^^^\n" + 
 				"Name clash: The method foo(A<String>) of type K has the same erasure as foo(A) of type I but does not override it\n" + 
@@ -9087,7 +9084,7 @@
 		"1. ERROR in X.java (at line 1)\n" +
 		"	public abstract class X implements J, K {}\n" +
 		"	                      ^\n" +
-		"The return types are incompatible for the inherited methods I.foo(Number), K.foo(Number), J.foo(Number)\n" +
+		"The return types are incompatible for the inherited methods K.foo(Number), J.foo(Number)\n" +
 		"----------\n" +
 		"2. WARNING in X.java (at line 6)\n" +
 		"	XX foo(Number n);\n" +
@@ -13378,6 +13375,11 @@
 			"	Zork z;\n" + 
 			"	^^^^\n" + 
 			"Zork cannot be resolved to a type\n" + 
+			"----------\n" + 
+			"5. ERROR in X.java (at line 7)\n" + 
+			"	class ChildX<Z> extends X<Z>{}\n" + 
+			"	      ^^^^^^\n" + 
+			"Duplicate methods named forAccountSet with the parameters (List<R>) and (List) are defined by the type X<Z>\n" + 
 			"----------\n":
 				"----------\n" + 
 				"1. ERROR in X.java (at line 3)\n" + 
diff --git a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
index fee31e9..ccb933b 100644
--- a/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
+++ b/org.eclipse.jdt.core/compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
@@ -11,6 +11,7 @@
  *								bug 186342 - [compiler][null] Using annotations for null checking
  *								bug 365519 - editorial cleanup after bug 186342 and bug 365387
  *								bug 388281 - [compiler][null] inheritance of null annotations as an option
+ *								bug 388795 - [compiler] detection of name clash depends on order of super interfaces
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
@@ -33,6 +34,9 @@
 	super(environment);
 }
 boolean areMethodsCompatible(MethodBinding one, MethodBinding two) {
+	return areMethodsCompatible(one, two, false);
+}
+boolean areMethodsCompatible(MethodBinding one, MethodBinding two, boolean allowReverse) {
 	// use the original methods to test compatibility, but do not check visibility, etc
 	one = one.original();
 	two = one.findOriginalInheritedMethod(two);
@@ -40,7 +44,7 @@
 	if (two == null)
 		return false; // method's declaringClass does not inherit from inheritedMethod's
 
-	return isParameterSubsignature(one, two);
+	return isParameterSubsignature(one, two) || (allowReverse && isParameterSubsignature(two, one));
 }
 boolean areReturnTypesCompatible(MethodBinding one, MethodBinding two) {
 	if (one.returnType == two.returnType) return true;
@@ -461,6 +465,12 @@
 		int inheritedLength = inherited.length;
 		MethodBinding[] matchingInherited = new MethodBinding[inheritedLength];
 		MethodBinding[] foundMatch = new MethodBinding[inheritedLength]; // null is no match, otherwise value is matching currentMethod
+
+		// skip tracks inherited methods which can be safely ignored for one of these reasons:
+		// - methods that have matched other inherited methods
+		// 		either because they match the same currentMethod or match each other
+		// - methods that are overridden by a current method
+		boolean[] skip = new boolean[inheritedLength];
 		if (current != null) {
 			for (int i = 0, length1 = current.length; i < length1; i++) {
 				MethodBinding currentMethod = current[i];
@@ -469,6 +479,8 @@
 					MethodBinding inheritedMethod = computeSubstituteMethod(inherited[j], currentMethod);
 					if (inheritedMethod != null) {
 						if (foundMatch[j] == null && isSubstituteParameterSubsignature(currentMethod, inheritedMethod)) {
+							// already checked compatibility, do visibility etc. also indicate overriding? If so ignore inheritedMethod further downstream
+							skip[j] = couldMethodOverride(currentMethod, inheritedMethod);
 							matchingInherited[++index] = inheritedMethod;
 							foundMatch[j] = currentMethod;
 						} else {
@@ -492,9 +504,6 @@
 			}
 		}
 
-		// skip tracks which inherited methods have matched other inherited methods
-		// either because they match the same currentMethod or match each other
-		boolean[] skip = new boolean[inheritedLength];
 		for (int i = 0; i < inheritedLength; i++) {
 			MethodBinding matchMethod = foundMatch[i];
 			if (matchMethod == null && current != null && this.type.isPublic()) { // current == null case handled already.
@@ -522,24 +531,28 @@
 				// This elimination used to happen rather eagerly in computeInheritedMethods step
 				// itself earlier. (https://bugs.eclipse.org/bugs/show_bug.cgi?id=302358)
 				if (inheritedMethod.declaringClass != otherInheritedMethod.declaringClass) {
-					if (otherInheritedMethod.declaringClass.isInterface()) {
+					if (otherInheritedMethod.declaringClass.isInterface() && !inheritedMethod.declaringClass.isInterface()) {
 						if (isInterfaceMethodImplemented(otherInheritedMethod, inheritedMethod, otherInheritedMethod.declaringClass)) {
 							skip[j] = true;
 							continue;
 						}
-					} else if (areMethodsCompatible(inheritedMethod, otherInheritedMethod)) {
+					} else if (areMethodsCompatible(inheritedMethod, otherInheritedMethod, true)) {
 						skip[j] = true;
 						continue;
 					}
 				}
 				otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
 				if (otherInheritedMethod != null) {
-					if (isSubstituteParameterSubsignature(inheritedMethod, otherInheritedMethod)) {
-							if (index == -1)
-								matchingInherited[++index] = inheritedMethod;
-							if (foundMatch[j] == null)
-								matchingInherited[++index] = otherInheritedMethod;
-							skip[j] = true;
+					if (((!inheritedMethod.isAbstract() || otherInheritedMethod.isAbstract()) 		// if (abstract(inherited) => abstract(other)) check if inherited overrides other 
+								&& isSubstituteParameterSubsignature(inheritedMethod, otherInheritedMethod))
+						|| ((!otherInheritedMethod.isAbstract() || inheritedMethod.isAbstract())	// if (abstract(other) => abstract(inherited)) check if other overrides inherited 
+								&& isSubstituteParameterSubsignature(otherInheritedMethod, inheritedMethod))) 
+					{
+						if (index == -1)
+							matchingInherited[++index] = inheritedMethod;
+						if (foundMatch[j] == null)
+							matchingInherited[++index] = otherInheritedMethod;
+						skip[j] = true;
 					} else if (matchMethod == null && foundMatch[j] == null) {
 						checkInheritedMethods(inheritedMethod, otherInheritedMethod);
 					}
@@ -659,7 +672,6 @@
 			ReferenceBinding[] interfaces = typeVariable.superInterfaces;
 			if (interfaceLength != interfaces.length)
 				return inheritedMethod; // not a match
-			// TODO (kent) another place where we expect the superinterfaces to be in the exact same order
 			next : for (int j = 0; j < interfaceLength; j++) {
 				TypeBinding superType = Scope.substitute(substitute, inheritedTypeVariable.superInterfaces[j]);
 				for (int k = 0; k < interfaceLength; k++)