import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / MethodVerifier15.java
diff --git a/src/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java b/src/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java
new file mode 100644 (file)
index 0000000..cec3089
--- /dev/null
@@ -0,0 +1,228 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
+
+class MethodVerifier15 extends MethodVerifier {
+
+MethodVerifier15(LookupEnvironment environment) {
+       super(environment);
+}
+boolean areMethodsEqual(MethodBinding one, MethodBinding substituteTwo) {
+       TypeBinding[] oneParams = one.parameters;
+       TypeBinding[] twoParams = substituteTwo.parameters;
+       boolean checkParameters = false;
+       if (oneParams != twoParams) {
+               int length = oneParams.length;
+               if (length != twoParams.length) return false; // no match
+
+               for (int i = 0; i < length; i++) {
+                       if (oneParams[i] != twoParams[i]) {
+                               checkParameters |= oneParams[i].leafComponentType().isParameterizedType();
+                               if (!areTypesEqual(oneParams[i], twoParams[i])) {
+                                       while (!checkParameters && ++i < length)
+                                               checkParameters |= oneParams[i].leafComponentType().isParameterizedType();
+                                       if (one.areParameterErasuresEqual(substituteTwo)) // at least one parameter may cause a name clash
+                                               detectNameClash(one, substituteTwo, checkParameters);
+                                       return false; // no match but needed to check for a name clash
+                               }
+                       }
+               }
+       }
+       return !detectNameClash(one, substituteTwo, checkParameters);
+}
+boolean areReturnTypesEqual(MethodBinding one, MethodBinding substituteTwo) {
+       if (one.returnType == substituteTwo.returnType) return true;
+
+       // methods from classes are always before methods from interfaces
+       if (one.declaringClass.isClass() || one.declaringClass.implementsInterface(substituteTwo.declaringClass, true))
+               return one.returnType.isCompatibleWith(substituteTwo.returnType);
+
+       if (substituteTwo.declaringClass.implementsInterface(one.declaringClass, true))
+               return substituteTwo.returnType.isCompatibleWith(one.returnType);
+
+       // unrelated interfaces... one must be a subtype of the other
+       return one.returnType.isCompatibleWith(substituteTwo.returnType)
+               || substituteTwo.returnType.isCompatibleWith(one.returnType);
+}
+boolean areTypesEqual(TypeBinding one, TypeBinding two) {
+       if (one == two) return true;
+
+       switch (one.kind()) {
+               case Binding.PARAMETERIZED_TYPE :
+               case Binding.RAW_TYPE :
+                       return one.isEquivalentTo(two);
+//             case Binding.TYPE_PARAMETER : // won't work for variables from different classes - need substitution
+       }
+
+       // Can skip this since we resolved each method before comparing it, see computeSubstituteMethod()
+       //      if (one instanceof UnresolvedReferenceBinding)
+       //              return ((UnresolvedReferenceBinding) one).resolvedType == two;
+       //      if (two instanceof UnresolvedReferenceBinding)
+       //              return ((UnresolvedReferenceBinding) two).resolvedType == one;
+       return false; // all other type bindings are identical
+}
+boolean canSkipInheritedMethods() {
+       if (this.type.superclass() != null)
+               if (this.type.superclass().isAbstract() || this.type.superclass().isParameterizedType())
+                       return false;
+       return this.type.superInterfaces() == NoSuperInterfaces;
+}
+boolean canSkipInheritedMethods(MethodBinding one, MethodBinding two) {
+       return two == null // already know one is not null
+               || (one.declaringClass == two.declaringClass && !one.declaringClass.isParameterizedType());
+}
+void checkForBridgeMethod(MethodBinding currentMethod, MethodBinding inheritedMethod) {
+       MethodBinding originalInherited = inheritedMethod.original();
+       if (inheritedMethod != originalInherited) {
+               MethodBinding[] toCheck = (MethodBinding[]) this.currentMethods.get(currentMethod.selector);
+               if (toCheck.length > 1) {
+                       // must check to see if a bridge method will collide with another current method (see 77861)
+                       for (int i = 0, length = toCheck.length; i < length; i++) {
+                               if (currentMethod != toCheck[i] && toCheck[i].areParameterErasuresEqual(originalInherited)) {
+                                       problemReporter(toCheck[i]).methodNameClash(toCheck[i], originalInherited); // bridge method will collide
+                                       return;
+                               }
+                       }
+               }
+       }
+
+       // so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
+       // then when do you need a bridge method?
+       if (originalInherited.returnType != currentMethod.returnType) {
+               switch (originalInherited.returnType.leafComponentType().kind()) {
+                       case Binding.PARAMETERIZED_TYPE :
+                               if (!currentMethod.returnType.leafComponentType().isParameterizedType())
+                                       problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, ((MethodDeclaration) currentMethod.sourceMethod()).returnType);
+                               break;
+                       case Binding.TYPE_PARAMETER :
+                               if (!currentMethod.returnType.leafComponentType().isTypeVariable())
+                                       problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, ((MethodDeclaration) currentMethod.sourceMethod()).returnType);
+                               break;
+               }   
+       }
+       this.type.addSyntheticBridgeMethod(originalInherited, currentMethod);
+}
+void checkInheritedMethods(MethodBinding[] methods, int length) {
+       int count = length;
+       nextMethod : for (int i = 0, l = length - 1; i < l;) {
+               MethodBinding method = methods[i++];
+               for (int j = i; j <= l; j++) {
+                       if (method.declaringClass == methods[j].declaringClass && doesMethodOverride(method, methods[j])) {
+                               // found an inherited ParameterizedType that defines duplicate methods
+                               problemReporter().duplicateInheritedMethods(this.type, method, methods[j]);
+                               count--;
+                               methods[i - 1] = null;
+                               continue nextMethod;
+                       }
+               }
+       }
+       if (count < length) {
+               if (count == 1) return; // no need to continue since only 1 inherited method is left
+               MethodBinding[] newMethods = new MethodBinding[count];
+               for (int i = length; --i >= 0;)
+                       if (methods[i] != null)
+                               newMethods[--count] = methods[i];
+               methods = newMethods;
+               length = newMethods.length;
+       }
+
+       super.checkInheritedMethods(methods, length);
+}
+MethodBinding computeSubstituteMethod(MethodBinding inheritedMethod, MethodBinding currentMethod) {
+       if (inheritedMethod == null) return null;
+
+       // due to hierarchy & compatibility checks, we need to ensure these 2 methods are resolved
+       // should we push these tests to where they're needed? returnType.isCompatibleWith && parameter isEquivalentTo ?
+       if (currentMethod.declaringClass instanceof BinaryTypeBinding)
+               ((BinaryTypeBinding) currentMethod.declaringClass).resolveTypesFor(currentMethod);
+       if (inheritedMethod.declaringClass instanceof BinaryTypeBinding)
+               ((BinaryTypeBinding) inheritedMethod.declaringClass).resolveTypesFor(inheritedMethod);
+
+       TypeVariableBinding[] inheritedTypeVariables = inheritedMethod.typeVariables();
+       if (inheritedTypeVariables == NoTypeVariables) return inheritedMethod;
+       TypeVariableBinding[] typeVariables = currentMethod == null ? NoTypeVariables : currentMethod.typeVariables;
+
+       int inheritedLength = inheritedTypeVariables.length;
+       int length = typeVariables.length;
+       TypeBinding[] arguments = new TypeBinding[inheritedLength];
+       if (inheritedLength <= length) {
+               System.arraycopy(typeVariables, 0, arguments, 0, inheritedLength);
+       } else {
+               System.arraycopy(typeVariables, 0, arguments, 0, length);
+               for (int i = length; i < inheritedLength; i++)
+                       arguments[i] = inheritedTypeVariables[i].erasure();
+       }
+       ParameterizedGenericMethodBinding substitute =
+               new ParameterizedGenericMethodBinding(inheritedMethod, arguments, this.environment);
+       for (int i = 0; i < inheritedLength; i++)
+           if (!inheritedTypeVariables[i].boundCheck(substitute, arguments[i]))
+               return inheritedMethod; // incompatible due to bound check
+   return substitute;
+}
+boolean detectNameClash(MethodBinding one, MethodBinding substituteTwo, boolean checkParameters) {
+       if (doTypeVariablesClash(one, substituteTwo) || (checkParameters && doParametersClash(one, substituteTwo))) {
+               if (this.type == one.declaringClass)
+                       problemReporter(one).methodNameClash(one, substituteTwo);
+               else
+                       problemReporter().inheritedMethodsHaveNameClash(this.type, one, substituteTwo);
+               return true;
+       }
+       return false;
+}
+public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
+       return super.doesMethodOverride(method, computeSubstituteMethod(inheritedMethod, method));
+}
+boolean doParametersClash(MethodBinding one, MethodBinding substituteTwo) {
+       // must check each parameter pair to see if parameterized types are compatible
+       TypeBinding[] oneParams = one.parameters;
+       TypeBinding[] twoParams = substituteTwo.parameters;
+       for (int i = 0, l = oneParams.length; i < l; i++) {
+               if (oneParams[i] == twoParams[i]) continue;
+               if (!oneParams[i].leafComponentType().isParameterizedType()) continue;
+
+               if (!twoParams[i].leafComponentType().isParameterizedType()
+                       || !oneParams[i].isEquivalentTo(twoParams[i])
+                       || !twoParams[i].isEquivalentTo(oneParams[i])) {
+                               return true;
+               }
+       }
+       return false;
+}
+boolean doTypeVariablesClash(MethodBinding one, MethodBinding substituteTwo) {
+       TypeBinding[] currentVars = one.typeVariables;
+       TypeBinding[] inheritedVars = substituteTwo.original().typeVariables;
+       return currentVars.length != inheritedVars.length
+               && currentVars.length > 0 && inheritedVars.length > 0; // must match unless all are replaced
+//             && currentVars.length > 0;
+}
+boolean hasBoundedParameters(ParameterizedTypeBinding parameterizedType) {
+       TypeBinding[] arguments = parameterizedType.arguments;
+       if (arguments == null) return false;
+
+       nextArg : for (int i = 0, l = arguments.length; i < l; i++) {
+               if (arguments[i].isWildcard())
+                       if (((WildcardBinding) arguments[i]).kind == org.eclipse.jdt.internal.compiler.ast.Wildcard.UNBOUND)
+                               continue nextArg;
+               if (arguments[i].isTypeVariable())
+                       if (((TypeVariableBinding) arguments[i]).firstBound == null)
+                               continue nextArg;
+               return true;
+       }
+       return false;
+}
+boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
+       inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod);
+       return inheritedMethod.returnType == existingMethod.returnType
+               && super.isInterfaceMethodImplemented(inheritedMethod, existingMethod, superType);
+}
+}
\ No newline at end of file