package org.eclipse.jdt.internal.compiler.lookup;
import java.util.Arrays;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.Argument;
import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
import org.eclipse.jdt.internal.compiler.ast.TypeReference;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.jdt.internal.compiler.util.SimpleSet;
import org.eclipse.jdt.internal.compiler.util.Sorting;
class MethodVerifier15 extends MethodVerifier {
MethodVerifier15(LookupEnvironment environment) {
super(environment);
}
@Override
protected boolean canOverridingMethodDifferInErasure(MethodBinding overridingMethod, MethodBinding inheritedMethod) {
if (overridingMethod.areParameterErasuresEqual(inheritedMethod))
return false;
if (overridingMethod.declaringClass.isRawType())
return false;
return true;
}
@Override
boolean canSkipInheritedMethods() {
if (this.type.superclass() != null)
if (this.type.superclass().isAbstract() || this.type.superclass().isParameterizedType())
return false;
return this.type.superInterfaces() == Binding.NO_SUPERINTERFACES;
}
@Override
boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
return two == null
|| (TypeBinding.equalsEquals(one.declaringClass, two.declaringClass) && !one.declaringClass.isParameterizedType());
}
@Override
void checkConcreteInheritedMethod(MethodBinding concreteMethod, MethodBinding[] abstractMethods) {
super.checkConcreteInheritedMethod(concreteMethod, abstractMethods);
boolean analyseNullAnnotations = this.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled;
AbstractMethodDeclaration srcMethod = null;
if (analyseNullAnnotations && this.type.equals(concreteMethod.declaringClass))
srcMethod = concreteMethod.sourceMethod();
boolean hasReturnNonNullDefault = analyseNullAnnotations && concreteMethod.hasNonNullDefaultForReturnType(srcMethod);
ParameterNonNullDefaultProvider hasParameterNonNullDefault = analyseNullAnnotations ? concreteMethod.hasNonNullDefaultForParameter(srcMethod): ParameterNonNullDefaultProvider.FALSE_PROVIDER;
for (int i = 0, l = abstractMethods.length; i < l; i++) {
MethodBinding abstractMethod = abstractMethods[i];
if (concreteMethod.isVarargs() != abstractMethod.isVarargs())
problemReporter().varargsConflict(concreteMethod, abstractMethod, this.type);
MethodBinding originalInherited = abstractMethod.original();
if (TypeBinding.notEquals(originalInherited.returnType, concreteMethod.returnType))
if (!isAcceptableReturnTypeOverride(concreteMethod, abstractMethod))
problemReporter().unsafeReturnTypeOverride(concreteMethod, originalInherited, this.type);
if (originalInherited.declaringClass.isInterface()) {
if ((TypeBinding.equalsEquals(concreteMethod.declaringClass, this.type.superclass) && this.type.superclass.isParameterizedType() && !areMethodsCompatible(concreteMethod, originalInherited))
|| this.type.superclass.erasure().findSuperTypeOriginatingFrom(originalInherited.declaringClass) == null)
this.type.addSyntheticBridgeMethod(originalInherited, concreteMethod.original());
}
if (analyseNullAnnotations && !concreteMethod.isStatic() && !abstractMethod.isStatic()) {
checkNullSpecInheritance(concreteMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, true, abstractMethod, abstractMethods, this.type.scope, null);
}
}
}
@Override
void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod, MethodBinding[] allInheritedMethods) {
if (currentMethod.isVarargs() != inheritedMethod.isVarargs())
problemReporter(currentMethod).varargsConflict(currentMethod, inheritedMethod, this.type);
MethodBinding originalInherited = inheritedMethod.original();
if (TypeBinding.notEquals(originalInherited.returnType, currentMethod.returnType))
if (!isAcceptableReturnTypeOverride(currentMethod, inheritedMethod))
problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
MethodBinding bridge = this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original());
if (bridge != null) {
for (int i = 0, l = allInheritedMethods == null ? 0 : allInheritedMethods.length; i < l; i++) {
if (allInheritedMethods[i] != null && detectInheritedNameClash(originalInherited, allInheritedMethods[i].original()))
return;
}
MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(bridge.selector);
for (int i = current.length - 1; i >= 0; --i) {
final MethodBinding thisMethod = current[i];
if (thisMethod.areParameterErasuresEqual(bridge) && TypeBinding.equalsEquals(thisMethod.returnType.erasure(), bridge.returnType.erasure())) {
problemReporter(thisMethod).methodNameClash(thisMethod, inheritedMethod.declaringClass.isRawType() ? inheritedMethod : inheritedMethod.original(), ProblemSeverities.Error);
return;
}
}
}
}
void checkForNameClash(MethodBinding currentMethod, MethodBinding inheritedMethod) {
if (inheritedMethod.isStatic() || currentMethod.isStatic()) {
MethodBinding original = inheritedMethod.original();
if (this.type.scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_7 && currentMethod.areParameterErasuresEqual(original)) {
problemReporter(currentMethod).methodNameClashHidden(currentMethod, inheritedMethod.declaringClass.isRawType() ? inheritedMethod : original);
}
return;
}
if (!detectNameClash(currentMethod, inheritedMethod, false)) {
TypeBinding[] currentParams = currentMethod.parameters;
TypeBinding[] inheritedParams = inheritedMethod.parameters;
int length = currentParams.length;
if (length != inheritedParams.length) return;
for (int i = 0; i < length; i++)
if (TypeBinding.notEquals(currentParams[i], inheritedParams[i]))
if (currentParams[i].isBaseType() != inheritedParams[i].isBaseType() || !inheritedParams[i].isCompatibleWith(currentParams[i]))
return;
ReferenceBinding[] interfacesToVisit = null;
int nextPosition = 0;
ReferenceBinding superType = inheritedMethod.declaringClass;
ReferenceBinding[] itsInterfaces = superType.superInterfaces();
if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
nextPosition = itsInterfaces.length;
interfacesToVisit = itsInterfaces;
}
superType = superType.superclass();
while (superType != null && superType.isValidBinding()) {
MethodBinding[] methods = superType.getMethods(currentMethod.selector);
for (int m = 0, n = methods.length; m < n; m++) {
MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
if (substitute != null && !isSubstituteParameterSubsignature(currentMethod, substitute) && detectNameClash(currentMethod, substitute, true))
return;
}
if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
if (interfacesToVisit == null) {
interfacesToVisit = itsInterfaces;
nextPosition = interfacesToVisit.length;
} else {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
superType = superType.superclass();
}
for (int i = 0; i < nextPosition; i++) {
superType = interfacesToVisit[i];
if (superType.isValidBinding()) {
MethodBinding[] methods = superType.getMethods(currentMethod.selector);
for (int m = 0, n = methods.length; m < n; m++){
MethodBinding substitute = computeSubstituteMethod(methods[m], currentMethod);
if (substitute != null && !isSubstituteParameterSubsignature(currentMethod, substitute) && detectNameClash(currentMethod, substitute, true))
return;
}
if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
}
}
}
void checkInheritedMethods(MethodBinding inheritedMethod, MethodBinding otherInheritedMethod) {
if (inheritedMethod.isStatic()) return;
if (this.environment.globalOptions.complianceLevel < ClassFileConstants.JDK1_7 && inheritedMethod.declaringClass.isInterface())
return;
detectInheritedNameClash(inheritedMethod.original(), otherInheritedMethod.original());
}
@Override
void checkInheritedMethods(MethodBinding[] methods, int length, boolean[] isOverridden, boolean[] isInherited) {
boolean continueInvestigation = true;
MethodBinding concreteMethod = null;
MethodBinding abstractSuperClassMethod = null;
boolean playingTrump = false;
for (int i = 0; i < length; i++) {
if (!methods[i].declaringClass.isInterface()
&& TypeBinding.notEquals(methods[i].declaringClass, this.type)
&& methods[i].isAbstract())
{
abstractSuperClassMethod = methods[i];
break;
}
}
for (int i = 0; i < length; i++) {
if (isInherited[i] && !methods[i].isAbstract()) {
if (methods[i].isDefaultMethod()
&& abstractSuperClassMethod != null
&& areParametersEqual(abstractSuperClassMethod, methods[i])
&& concreteMethod == null) {
playingTrump = true;
} else {
playingTrump = false;
if (concreteMethod != null) {
if (isOverridden[i] && areMethodsCompatible(concreteMethod, methods[i])) {
continue;
}
if (TypeBinding.equalsEquals(concreteMethod.declaringClass, methods[i].declaringClass)
&& concreteMethod.typeVariables.length != methods[i].typeVariables.length)
{
if (concreteMethod.typeVariables == Binding.NO_TYPE_VARIABLES
&& concreteMethod.original() == methods[i])
continue;
if (methods[i].typeVariables == Binding.NO_TYPE_VARIABLES
&& methods[i].original() == concreteMethod)
continue;
}
problemReporter().duplicateInheritedMethods(this.type, concreteMethod, methods[i],
this.environment.globalOptions.sourceLevel >= ClassFileConstants.JDK1_8);
continueInvestigation = false;
}
concreteMethod = methods[i];
}
}
}
if (continueInvestigation) {
if (playingTrump) {
if (!this.type.isAbstract()) {
problemReporter().abstractMethodMustBeImplemented(this.type, abstractSuperClassMethod);
return;
}
} else {
if (concreteMethod != null && concreteMethod.isDefaultMethod()) {
if (this.environment.globalOptions.complianceLevel >= ClassFileConstants.JDK1_8) {
if (!checkInheritedDefaultMethods(methods, isOverridden, length))
return;
}
}
}
super.checkInheritedMethods(methods, length, isOverridden, isInherited);
}
}
boolean checkInheritedDefaultMethods(MethodBinding[] methods, boolean[] isOverridden, int length) {
if (length < 2) return true;
boolean ok = true;
findDefaultMethod: for (int i=0; i<length; i++) {
if (methods[i].isDefaultMethod() && !isOverridden[i]) {
findEquivalent: for (int j=0; j<length; j++) {
if (j == i || isOverridden[j]) continue findEquivalent;
if (isMethodSubsignature(methods[i], methods[j])) {
if (!doesMethodOverride(methods[i], methods[j]) && !doesMethodOverride(methods[j], methods[i])) {
problemReporter().inheritedDefaultMethodConflictsWithOtherInherited(this.type, methods[i], methods[j]);
ok = false;
continue findDefaultMethod;
}
}
}
}
}
return ok;
}
@Override
boolean checkInheritedReturnTypes(MethodBinding method, MethodBinding otherMethod) {
if (areReturnTypesCompatible(method, otherMethod)) return true;
if (isUnsafeReturnTypeOverride(method, otherMethod)) {
if (!method.declaringClass.implementsInterface(otherMethod.declaringClass, false))
problemReporter(method).unsafeReturnTypeOverride(method, otherMethod, this.type);
return true;
}
return false;
}
@Override
void checkAgainstInheritedMethods(MethodBinding currentMethod, MethodBinding[] methods, int length, MethodBinding[] allInheritedMethods)
{
super.checkAgainstInheritedMethods(currentMethod, methods, length, allInheritedMethods);
CompilerOptions options = this.environment.globalOptions;
if (options.isAnnotationBasedNullAnalysisEnabled
&& (currentMethod.tagBits & TagBits.IsNullnessKnown) == 0)
{
AbstractMethodDeclaration srcMethod = null;
if (this.type.equals(currentMethod.declaringClass))
srcMethod = currentMethod.sourceMethod();
boolean hasReturnNonNullDefault = currentMethod.hasNonNullDefaultForReturnType(srcMethod);
ParameterNonNullDefaultProvider hasParameterNonNullDefault = currentMethod.hasNonNullDefaultForParameter(srcMethod);
for (int i = length; --i >= 0;)
if (!currentMethod.isStatic() && !methods[i].isStatic())
checkNullSpecInheritance(currentMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, true, methods[i], methods, this.type.scope, null);
}
}
@Override
void checkNullSpecInheritance(MethodBinding currentMethod, AbstractMethodDeclaration srcMethod,
boolean hasReturnNonNullDefault, ParameterNonNullDefaultProvider hasParameterNonNullDefault, boolean complain, MethodBinding inheritedMethod, MethodBinding[] allInherited, Scope scope, InheritedNonNullnessInfo[] inheritedNonNullnessInfos)
{
complain &= !currentMethod.isConstructor();
if (!hasReturnNonNullDefault && !hasParameterNonNullDefault.hasAnyNonNullDefault() && !complain && !this.environment.globalOptions.inheritNullAnnotations) {
currentMethod.tagBits |= TagBits.IsNullnessKnown;
return;
}
if (TypeBinding.notEquals(currentMethod.declaringClass, this.type)
&& (currentMethod.tagBits & TagBits.IsNullnessKnown) == 0)
{
this.buddyImplicitNullAnnotationsVerifier.checkImplicitNullAnnotations(currentMethod, srcMethod, complain, scope);
}
super.checkNullSpecInheritance(currentMethod, srcMethod, hasReturnNonNullDefault, hasParameterNonNullDefault, complain, inheritedMethod, allInherited, scope, inheritedNonNullnessInfos);
}
void reportRawReferences() {
CompilerOptions compilerOptions = this.type.scope.compilerOptions();
if (compilerOptions.sourceLevel < ClassFileConstants.JDK1_5
|| compilerOptions.reportUnavoidableGenericTypeProblems) {
return;
}
Object [] methodArray = this.currentMethods.valueTable;
for (int s = methodArray.length; --s >= 0;) {
if (methodArray[s] == null) continue;
MethodBinding[] current = (MethodBinding[]) methodArray[s];
for (int i = 0, length = current.length; i < length; i++) {
MethodBinding currentMethod = current[i];
if ((currentMethod.modifiers & (ExtraCompilerModifiers.AccImplementing | ExtraCompilerModifiers.AccOverriding)) == 0) {
AbstractMethodDeclaration methodDecl = currentMethod.sourceMethod();
if (methodDecl == null) return;
TypeBinding [] parameterTypes = currentMethod.parameters;
Argument[] arguments = methodDecl.arguments;
for (int j = 0, size = currentMethod.parameters.length; j < size; j++) {
TypeBinding parameterType = parameterTypes[j];
Argument arg = arguments[j];
if (parameterType.leafComponentType().isRawType()
&& compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore
&& (arg.type.bits & ASTNode.IgnoreRawTypeCheck) == 0) {
methodDecl.scope.problemReporter().rawTypeReference(arg.type, parameterType);
}
}
if (!methodDecl.isConstructor() && methodDecl instanceof MethodDeclaration) {
TypeReference returnType = ((MethodDeclaration) methodDecl).returnType;
TypeBinding methodType = currentMethod.returnType;
if (returnType != null) {
if (methodType.leafComponentType().isRawType()
&& compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore
&& (returnType.bits & ASTNode.IgnoreRawTypeCheck) == 0) {
methodDecl.scope.problemReporter().rawTypeReference(returnType, methodType);
}
}
}
}
}
}
}
@Override
public void reportRawReferences(MethodBinding currentMethod, MethodBinding inheritedMethod) {
CompilerOptions compilerOptions = this.type.scope.compilerOptions();
if (compilerOptions.sourceLevel < ClassFileConstants.JDK1_5
|| compilerOptions.reportUnavoidableGenericTypeProblems) {
return;
}
AbstractMethodDeclaration methodDecl = currentMethod.sourceMethod();
if (methodDecl == null) return;
TypeBinding [] parameterTypes = currentMethod.parameters;
TypeBinding [] inheritedParameterTypes = inheritedMethod.parameters;
Argument[] arguments = methodDecl.arguments;
for (int j = 0, size = currentMethod.parameters.length; j < size; j++) {
TypeBinding parameterType = parameterTypes[j];
TypeBinding inheritedParameterType = inheritedParameterTypes[j];
Argument arg = arguments[j];
if (parameterType.leafComponentType().isRawType()) {
if (inheritedParameterType.leafComponentType().isRawType()) {
arg.binding.tagBits |= TagBits.ForcedToBeRawType;
} else {
if (compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore
&& (arg.type.bits & ASTNode.IgnoreRawTypeCheck) == 0) {
methodDecl.scope.problemReporter().rawTypeReference(arg.type, parameterType);
}
}
}
}
TypeReference returnType = null;
if (!methodDecl.isConstructor() && methodDecl instanceof MethodDeclaration && (returnType = ((MethodDeclaration) methodDecl).returnType) != null) {
final TypeBinding inheritedMethodType = inheritedMethod.returnType;
final TypeBinding methodType = currentMethod.returnType;
if (methodType.leafComponentType().isRawType()) {
if (inheritedMethodType.leafComponentType().isRawType()) {
} else {
if ((returnType.bits & ASTNode.IgnoreRawTypeCheck) == 0
&& compilerOptions.getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) {
methodDecl.scope.problemReporter().rawTypeReference(returnType, methodType);
}
}
}
}
}
@Override
void checkMethods() {
boolean mustImplementAbstractMethods = mustImplementAbstractMethods();
boolean skipInheritedMethods = mustImplementAbstractMethods && canSkipInheritedMethods();
boolean isOrEnclosedByPrivateType = this.type.isOrEnclosedByPrivateType();
char[][] methodSelectors = this.inheritedMethods.keyTable;
nextSelector : for (int s = methodSelectors.length; --s >= 0;) {
if (methodSelectors[s] == null) continue nextSelector;
MethodBinding[] current = (MethodBinding[]) this.currentMethods.get(methodSelectors[s]);
MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
inherited = Sorting.concreteFirst(inherited, inherited.length);
if (current == null && !isOrEnclosedByPrivateType) {
int length = inherited.length;
for (int i = 0; i < length; i++){
inherited[i].original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
}
}
if (current == null && this.type.isPublic()) {
int length = inherited.length;
for (int i = 0; i < length; i++) {
MethodBinding inheritedMethod = inherited[i];
if (inheritedMethod.isPublic() && (!inheritedMethod.declaringClass.isInterface() && !inheritedMethod.declaringClass.isPublic()))
this.type.addSyntheticBridgeMethod(inheritedMethod.original());
}
}
if (current == null && skipInheritedMethods)
continue nextSelector;
if (inherited.length == 1 && current == null) {
if (mustImplementAbstractMethods && inherited[0].isAbstract())
checkAbstractMethod(inherited[0]);
continue nextSelector;
}
int index = -1;
int inheritedLength = inherited.length;
MethodBinding[] matchingInherited = new MethodBinding[inheritedLength];
MethodBinding[] foundMatch = new MethodBinding[inheritedLength];
boolean[] skip = new boolean[inheritedLength];
boolean[] isOverridden = new boolean[inheritedLength];
boolean[] isInherited = new boolean[inheritedLength];
Arrays.fill(isInherited, true);
if (current != null) {
for (int i = 0, length1 = current.length; i < length1; i++) {
MethodBinding currentMethod = current[i];
MethodBinding[] nonMatchingInherited = null;
for (int j = 0; j < inheritedLength; j++) {
MethodBinding inheritedMethod = computeSubstituteMethod(inherited[j], currentMethod);
if (inheritedMethod != null) {
if (foundMatch[j] == null && isSubstituteParameterSubsignature(currentMethod, inheritedMethod)) {
isOverridden[j] = skip[j] = couldMethodOverride(currentMethod, inheritedMethod);
matchingInherited[++index] = inheritedMethod;
foundMatch[j] = currentMethod;
} else {
checkForNameClash(currentMethod, inheritedMethod);
if (inheritedLength > 1) {
if (nonMatchingInherited == null)
nonMatchingInherited = new MethodBinding[inheritedLength];
nonMatchingInherited[j] = inheritedMethod;
}
}
}
}
if (index >= 0) {
checkAgainstInheritedMethods(currentMethod, matchingInherited, index + 1, nonMatchingInherited);
while (index >= 0) matchingInherited[index--] = null;
}
}
}
for (int i = 0; i < inheritedLength; i++) {
MethodBinding matchMethod = foundMatch[i];
if (matchMethod == null && current != null && this.type.isPublic()) {
MethodBinding inheritedMethod = inherited[i];
if (inheritedMethod.isPublic() && (!inheritedMethod.declaringClass.isInterface() && !inheritedMethod.declaringClass.isPublic())) {
this.type.addSyntheticBridgeMethod(inheritedMethod.original());
}
}
if (!isOrEnclosedByPrivateType && matchMethod == null && current != null) {
inherited[i].original().modifiers |= ExtraCompilerModifiers.AccLocallyUsed;
}
MethodBinding inheritedMethod = inherited[i];
for (int j = i + 1; j < inheritedLength; j++) {
MethodBinding otherInheritedMethod = inherited[j];
if (matchMethod == foundMatch[j] && matchMethod != null)
continue;
if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
continue;
if (TypeBinding.notEquals(inheritedMethod.declaringClass, otherInheritedMethod.declaringClass)) {
if (isSkippableOrOverridden(inheritedMethod, otherInheritedMethod, skip, isOverridden, isInherited, j))
continue;
if (isSkippableOrOverridden(otherInheritedMethod, inheritedMethod, skip, isOverridden, isInherited, i))
continue;
}
}
}
for (int i = 0; i < inheritedLength; i++) {
MethodBinding matchMethod = foundMatch[i];
if (skip[i]) continue;
MethodBinding inheritedMethod = inherited[i];
if (matchMethod == null)
matchingInherited[++index] = inheritedMethod;
for (int j = i + 1; j < inheritedLength; j++) {
if (foundMatch[j] == null) {
MethodBinding otherInheritedMethod = inherited[j];
if (matchMethod == foundMatch[j] && matchMethod != null)
continue;
if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
continue;
MethodBinding replaceMatch;
if ((replaceMatch = findReplacedMethod(inheritedMethod, otherInheritedMethod)) != null) {
matchingInherited[++index] = replaceMatch;
skip[j] = true;
} else if ((replaceMatch = findReplacedMethod(otherInheritedMethod, inheritedMethod)) != null) {
matchingInherited[++index] = replaceMatch;
skip[j] = true;
} else if (matchMethod == null) {
checkInheritedMethods(inheritedMethod, otherInheritedMethod);
}
}
}
if (index == -1) continue;
if (index > 0) {
int length = index + 1;
boolean[] matchingIsOverridden;
boolean[] matchingIsInherited;
if (length != inheritedLength) {
matchingIsOverridden = new boolean[length];
matchingIsInherited = new boolean[length];
for (int j = 0; j < length; j++) {
for (int k = 0; k < inheritedLength; k++) {
if (matchingInherited[j] == inherited[k]) {
matchingIsOverridden[j] = isOverridden[k];
matchingIsInherited[j] = isInherited[k];
break;
}
}
}
} else {
matchingIsOverridden = isOverridden;
matchingIsInherited = isInherited;
}
checkInheritedMethods(matchingInherited, length, matchingIsOverridden, matchingIsInherited);
}
else if (mustImplementAbstractMethods && matchingInherited[0].isAbstract() && matchMethod == null)
checkAbstractMethod(matchingInherited[0]);
while (index >= 0) matchingInherited[index--] = null;
}
}
}
boolean isSkippableOrOverridden(MethodBinding specific, MethodBinding general, boolean[] skip, boolean[] isOverridden, boolean[] isInherited, int idx) {
boolean specificIsInterface = specific.declaringClass.isInterface();
boolean generalIsInterface = general.declaringClass.isInterface();
if (!specificIsInterface && generalIsInterface) {
if (!specific.isAbstract() && isParameterSubsignature(specific, general)) {
isInherited[idx] = false;
return true;
} else if (isInterfaceMethodImplemented(general, specific, general.declaringClass)) {
skip[idx] = true;
isOverridden[idx] = true;
return true;
}
} else if (specificIsInterface == generalIsInterface) {
if (specific.declaringClass.isCompatibleWith(general.declaringClass) && isMethodSubsignature(specific, general)) {
skip[idx] = true;
isOverridden[idx] = true;
return true;
}
}
return false;
}
MethodBinding findReplacedMethod(MethodBinding specific, MethodBinding general) {
MethodBinding generalSubstitute = computeSubstituteMethod(general, specific);
if (generalSubstitute != null
&& (!specific.isAbstract() || general.isAbstract() || (general.isDefaultMethod() && specific.declaringClass.isClass()))
&& isSubstituteParameterSubsignature(specific, generalSubstitute))
{
return generalSubstitute;
}
return null;
}
void checkTypeVariableMethods(TypeParameter typeParameter) {
char[][] methodSelectors = this.inheritedMethods.keyTable;
nextSelector : for (int s = methodSelectors.length; --s >= 0;) {
if (methodSelectors[s] == null) continue nextSelector;
MethodBinding[] inherited = (MethodBinding[]) this.inheritedMethods.valueTable[s];
if (inherited.length == 1) continue nextSelector;
int index = -1;
MethodBinding[] matchingInherited = new MethodBinding[inherited.length];
for (int i = 0, length = inherited.length; i < length; i++) {
while (index >= 0) matchingInherited[index--] = null;
MethodBinding inheritedMethod = inherited[i];
if (inheritedMethod != null) {
matchingInherited[++index] = inheritedMethod;
for (int j = i + 1; j < length; j++) {
MethodBinding otherInheritedMethod = inherited[j];
if (canSkipInheritedMethods(inheritedMethod, otherInheritedMethod))
continue;
otherInheritedMethod = computeSubstituteMethod(otherInheritedMethod, inheritedMethod);
if (otherInheritedMethod != null && isSubstituteParameterSubsignature(inheritedMethod, otherInheritedMethod)) {
matchingInherited[++index] = otherInheritedMethod;
inherited[j] = null;
}
}
}
if (index > 0) {
MethodBinding first = matchingInherited[0];
int count = index + 1;
while (--count > 0) {
MethodBinding match = matchingInherited[count];
MethodBinding interfaceMethod = null, implementation = null;
if (first.declaringClass.isInterface()) {
interfaceMethod = first;
} else if (first.declaringClass.isClass()) {
implementation = first;
}
if (match.declaringClass.isInterface()) {
interfaceMethod = match;
} else if (match.declaringClass.isClass()) {
implementation = match;
}
if (interfaceMethod != null && implementation != null && !implementation.isAbstract() && !isAsVisible(implementation, interfaceMethod))
problemReporter().inheritedMethodReducesVisibility(typeParameter, implementation, new MethodBinding [] {interfaceMethod});
if (areReturnTypesCompatible(first, match)) continue;
if (first.declaringClass.isInterface() && match.declaringClass.isInterface() && areReturnTypesCompatible(match, first))
continue;
break;
}
if (count > 0) {
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(typeParameter, matchingInherited, index + 1);
continue nextSelector;
}
}
}
}
}
boolean detectInheritedNameClash(MethodBinding inherited, MethodBinding otherInherited) {
if (!inherited.areParameterErasuresEqual(otherInherited))
return false;
if (TypeBinding.notEquals(inherited.returnType.erasure(), otherInherited.returnType.erasure()))
return false;
if (TypeBinding.notEquals(inherited.declaringClass.erasure(), otherInherited.declaringClass.erasure())) {
if (inherited.declaringClass.findSuperTypeOriginatingFrom(otherInherited.declaringClass) != null)
return false;
if (otherInherited.declaringClass.findSuperTypeOriginatingFrom(inherited.declaringClass) != null)
return false;
}
problemReporter().inheritedMethodsHaveNameClash(this.type, inherited, otherInherited);
return true;
}
boolean detectNameClash(MethodBinding current, MethodBinding inherited, boolean treatAsSynthetic) {
MethodBinding methodToCheck = inherited;
MethodBinding original = methodToCheck.original();
if (!current.areParameterErasuresEqual(original))
return false;
int severity = ProblemSeverities.Error;
if (this.environment.globalOptions.complianceLevel == ClassFileConstants.JDK1_6) {
if (TypeBinding.notEquals(current.returnType.erasure(), original.returnType.erasure()))
severity = ProblemSeverities.Warning;
}
if (!treatAsSynthetic) {
MethodBinding[] currentNamesakes = (MethodBinding[]) this.currentMethods.get(inherited.selector);
if (currentNamesakes.length > 1) {
for (int i = 0, length = currentNamesakes.length; i < length; i++) {
MethodBinding currentMethod = currentNamesakes[i];
if (currentMethod != current && doesMethodOverride(currentMethod, inherited)) {
methodToCheck = currentMethod;
break;
}
}
}
}
original = methodToCheck.original();
if (!current.areParameterErasuresEqual(original))
return false;
original = inherited.original();
problemReporter(current).methodNameClash(current, inherited.declaringClass.isRawType() ? inherited : original, severity);
if (severity == ProblemSeverities.Warning) return false;
return true;
}
boolean doTypeVariablesClash(MethodBinding one, MethodBinding substituteTwo) {
return one.typeVariables != Binding.NO_TYPE_VARIABLES && !(substituteTwo instanceof ParameterizedGenericMethodBinding);
}
@Override
SimpleSet findSuperinterfaceCollisions(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) {
ReferenceBinding[] interfacesToVisit = null;
int nextPosition = 0;
ReferenceBinding[] itsInterfaces = superInterfaces;
if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
nextPosition = itsInterfaces.length;
interfacesToVisit = itsInterfaces;
}
boolean isInconsistent = this.type.isHierarchyInconsistent();
ReferenceBinding superType = superclass;
while (superType != null && superType.isValidBinding()) {
isInconsistent |= superType.isHierarchyInconsistent();
if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
if (interfacesToVisit == null) {
interfacesToVisit = itsInterfaces;
nextPosition = interfacesToVisit.length;
} else {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
superType = superType.superclass();
}
for (int i = 0; i < nextPosition; i++) {
superType = interfacesToVisit[i];
if (superType.isValidBinding()) {
isInconsistent |= superType.isHierarchyInconsistent();
if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
int itsLength = itsInterfaces.length;
if (nextPosition + itsLength >= interfacesToVisit.length)
System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
nextInterface : for (int a = 0; a < itsLength; a++) {
ReferenceBinding next = itsInterfaces[a];
for (int b = 0; b < nextPosition; b++)
if (TypeBinding.equalsEquals(next, interfacesToVisit[b])) continue nextInterface;
interfacesToVisit[nextPosition++] = next;
}
}
}
}
if (!isInconsistent) return null;
SimpleSet copy = null;
for (int i = 0; i < nextPosition; i++) {
ReferenceBinding current = interfacesToVisit[i];
if (current.isValidBinding()) {
TypeBinding erasure = current.erasure();
for (int j = i + 1; j < nextPosition; j++) {
ReferenceBinding next = interfacesToVisit[j];
if (next.isValidBinding() && TypeBinding.equalsEquals(next.erasure(), erasure)) {
if (copy == null)
copy = new SimpleSet(nextPosition);
copy.add(interfacesToVisit[i]);
copy.add(interfacesToVisit[j]);
}
}
}
}
return copy;
}
boolean isAcceptableReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
if (inheritedMethod.declaringClass.isRawType())
return true;
MethodBinding originalInherited = inheritedMethod.original();
TypeBinding originalInheritedReturnType = originalInherited.returnType.leafComponentType();
if (originalInheritedReturnType.isParameterizedTypeWithActualArguments())
return !currentMethod.returnType.leafComponentType().isRawType();
TypeBinding currentReturnType = currentMethod.returnType.leafComponentType();
switch (currentReturnType.kind()) {
case Binding.TYPE_PARAMETER :
if (TypeBinding.equalsEquals(currentReturnType, inheritedMethod.returnType.leafComponentType()))
return true;
default :
if (originalInheritedReturnType.isTypeVariable())
if (((TypeVariableBinding) originalInheritedReturnType).declaringElement == originalInherited)
return false;
return true;
}
}
@Override
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
return false;
inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod);
if (inheritedMethod == null || !doesMethodOverride(existingMethod, inheritedMethod))
return false;
return TypeBinding.equalsEquals(inheritedMethod.returnType, existingMethod.returnType)
|| (TypeBinding.notEquals(this.type, existingMethod.declaringClass)
&& !existingMethod.declaringClass.isInterface()
&& areReturnTypesCompatible(existingMethod, inheritedMethod));
}
@Override
public boolean isMethodSubsignature(MethodBinding method, MethodBinding inheritedMethod) {
if (!org.eclipse.jdt.core.compiler.CharOperation.equals(method.selector, inheritedMethod.selector))
return false;
if (method.declaringClass.isParameterizedType())
method = method.original();
MethodBinding inheritedOriginal = method.findOriginalInheritedMethod(inheritedMethod);
return isParameterSubsignature(method, inheritedOriginal == null ? inheritedMethod : inheritedOriginal);
}
boolean isUnsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
if (TypeBinding.equalsEquals(currentMethod.returnType, inheritedMethod.returnType.erasure())) {
TypeBinding[] currentParams = currentMethod.parameters;
TypeBinding[] inheritedParams = inheritedMethod.parameters;
for (int i = 0, l = currentParams.length; i < l; i++)
if (!areTypesEqual(currentParams[i], inheritedParams[i]))
return true;
}
if (currentMethod.typeVariables == Binding.NO_TYPE_VARIABLES
&& inheritedMethod.original().typeVariables != Binding.NO_TYPE_VARIABLES
&& currentMethod.returnType.erasure().findSuperTypeOriginatingFrom(inheritedMethod.returnType.erasure()) != null) {
return true;
}
return false;
}
@Override
boolean reportIncompatibleReturnTypeError(MethodBinding currentMethod, MethodBinding inheritedMethod) {
if (isUnsafeReturnTypeOverride(currentMethod, inheritedMethod)) {
problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, inheritedMethod, this.type);
return false;
}
return super.reportIncompatibleReturnTypeError(currentMethod, inheritedMethod);
}
@Override
void verify() {
if (this.type.isAnnotationType())
this.type.detectAnnotationCycle();
super.verify();
reportRawReferences();
for (int i = this.type.typeVariables.length; --i >= 0;) {
TypeVariableBinding var = this.type.typeVariables[i];
if (var.superInterfaces == Binding.NO_SUPERINTERFACES) continue;
if (var.superInterfaces.length == 1 && var.superclass.id == TypeIds.T_JavaLangObject) continue;
this.currentMethods = new HashtableOfObject(0);
ReferenceBinding superclass = var.superclass();
if (superclass.kind() == Binding.TYPE_PARAMETER)
superclass = (ReferenceBinding) superclass.erasure();
ReferenceBinding[] itsInterfaces = var.superInterfaces();
ReferenceBinding[] superInterfaces = new ReferenceBinding[itsInterfaces.length];
for (int j = itsInterfaces.length; --j >= 0;) {
superInterfaces[j] = itsInterfaces[j].kind() == Binding.TYPE_PARAMETER
? (ReferenceBinding) itsInterfaces[j].erasure()
: itsInterfaces[j];
}
computeInheritedMethods(superclass, superInterfaces);
checkTypeVariableMethods(this.type.scope.referenceContext.typeParameters[i]);
}
}
}