for (int i = 0, length = this.methods.length; i < length; i++) {
MethodBinding method = resolvedMethods[i];
if (method == null)
continue;
char[] selector = method.selector;
AbstractMethodDeclaration methodDecl = null;
nextSibling: for (int j = i + 1; j < length; j++) {
MethodBinding method2 = resolvedMethods[j];
if (method2 == null)
continue nextSibling;
if (!CharOperation.equals(selector, method2.selector))
break nextSibling; // methods with same selector are contiguous
if (complyTo15 && method.returnType != null && method2.returnType != null) {
// 8.4.2, for collision to be detected between m1 and m2:
// signature(m1) == signature(m2) i.e. same arity, same type parameter count, can be substituted
// signature(m1) == erasure(signature(m2)) or erasure(signature(m1)) == signature(m2)
TypeBinding[] params1 = method.parameters;
TypeBinding[] params2 = method2.parameters;
int pLength = params1.length;
if (pLength != params2.length)
continue nextSibling;
TypeVariableBinding[] vars = method.typeVariables;
TypeVariableBinding[] vars2 = method2.typeVariables;
boolean equalTypeVars = vars == vars2;
MethodBinding subMethod = method2;
if (!equalTypeVars) {
MethodBinding temp = method.computeSubstitutedMethod(method2, this.scope.environment());
if (temp != null) {
equalTypeVars = true;
subMethod = temp;
}
}
boolean equalParams = method.areParametersEqual(subMethod);
if (equalParams && equalTypeVars) {
// duplicates regardless of return types
} else if (method.returnType.erasure() == subMethod.returnType.erasure() && (equalParams || method.areParameterErasuresEqual(method2))) {
// name clash for sure if not duplicates, report as duplicates
} else if (!equalTypeVars && vars != Binding.NO_TYPE_VARIABLES && vars2 != Binding.NO_TYPE_VARIABLES) {
// type variables are different so we can distinguish between methods
continue nextSibling;
} else if (pLength > 0) {
// check to see if the erasure of either method is equal to the other
int index = pLength;
for (; --index >= 0;) {
if (params1[index] != params2[index].erasure())
break;
if (params1[index] == params2[index]) {
TypeBinding type = params1[index].leafComponentType();
if (type instanceof SourceTypeBinding && type.typeVariables() != Binding.NO_TYPE_VARIABLES) {
index = pLength; // handle comparing identical source types like X<T>... its erasure is itself BUT we need to answer false
break;
}
}
}
if (index >= 0 && index < pLength) {
for (index = pLength; --index >= 0;)
if (params1[index].erasure() != params2[index])
break;
}
if (index >= 0)
continue nextSibling;
}
} else if (!method.areParametersEqual(method2)) { // prior to 1.5, parameter identity meant a collision case
continue nextSibling;
}
boolean isEnumSpecialMethod = isEnum() && (CharOperation.equals(selector,TypeConstants.VALUEOF) || CharOperation.equals(selector,TypeConstants.VALUES));
// report duplicate
if (methodDecl == null) {
methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost & may still be null if method is special
if (methodDecl != null && methodDecl.binding != null) { // ensure its a valid user defined method
if (isEnumSpecialMethod) {
this.scope.problemReporter().duplicateEnumSpecialMethod(this, methodDecl);
} else {
this.scope.problemReporter().duplicateMethodInType(this, methodDecl, method.areParametersEqual(method2));
}
methodDecl.binding = null;
// do not alter original method array until resolution is over, due to reentrance (143259)
if (resolvedMethods == this.methods) {
System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);
}
resolvedMethods[i] = null;
failed++;
}
}
AbstractMethodDeclaration method2Decl = method2.sourceMethod();
if (method2Decl != null && method2Decl.binding != null) { // ensure its a valid user defined method
if (isEnumSpecialMethod) {
this.scope.problemReporter().duplicateEnumSpecialMethod(this, method2Decl);
} else {
this.scope.problemReporter().duplicateMethodInType(this, method2Decl, method.areParametersEqual(method2));