blob: 817e9c070502e54cab40eca27e115b0fc1c8c7a7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.jsdt.internal.compiler.lookup;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.wst.jsdt.internal.compiler.util.Util;
import org.eclipse.wst.jsdt.internal.oaametadata.ClassData;
import org.eclipse.wst.jsdt.internal.oaametadata.Method;
import org.eclipse.wst.jsdt.internal.oaametadata.Parameter;
import org.eclipse.wst.jsdt.internal.oaametadata.Property;
public class MetatdataTypeBinding extends SourceTypeBinding {
ClassData classData;
LibraryAPIsScope libraryScope;
boolean methodsBuilt=false;
boolean fieldsBuilt=false;
public MetatdataTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassData classData, LibraryAPIsScope scope) {
this.compoundName = compoundName;
this.fPackage = fPackage;
this.fileName = scope.getFileName();
this.sourceName = compoundName[0];
this.classData=classData;
// expect the fields & methods to be initialized correctly later
this.fields = Binding.NO_FIELDS;
this.methods = Binding.NO_METHODS;
this.scope=this.libraryScope = scope;
}
private void buildFields() {
FieldBinding prototype = new FieldBinding(TypeConstants.PROTOTYPE, TypeBinding.UNKNOWN, modifiers | ExtraCompilerModifiers.AccUnresolved, this,null);
Property[] classFields = this.classData.getFields();
int size = classFields.length;
if (size == 0) {
setFields(new FieldBinding[]{prototype});
return;
}
// iterate the field declarations to create the bindings, lose all duplicates
FieldBinding[] fieldBindings = new FieldBinding[size+1];
HashtableOfObject knownFieldNames = new HashtableOfObject(size);
boolean duplicate = false;
int count = 0;
for (int i = 0; i < size; i++) {
Property field =classFields[i];
char [] fieldName=field.name.toCharArray();
int modifiers=0;
if (field.isStatic())
modifiers|=ClassFileConstants.AccStatic;
TypeBinding fieldTypeBinding = libraryScope.resolveType(field.type);
FieldBinding fieldBinding = new FieldBinding(fieldName, fieldTypeBinding, modifiers | ExtraCompilerModifiers.AccUnresolved, this, null);
fieldBinding.id = count;
// field's type will be resolved when needed for top level types
// checkAndSetModifiersForField(fieldBinding, field);
if (knownFieldNames.containsKey(fieldName)) {
duplicate = true;
FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(fieldName);
// if (previousBinding != null) {
// for (int f = 0; f < i; f++) {
// InferredAttribute previousField = inferredType.attributes[f];
// if (previousField.binding == previousBinding) {
// libraryScope.problemReporter().duplicateFieldInType(this, previousField);
// previousField.binding = null;
// break;
// }
// }
// }
knownFieldNames.put(fieldName, null); // ensure that the duplicate field is found & removed
// libraryScope.problemReporter().duplicateFieldInType(this, field);
// field.binding = null;
} else {
knownFieldNames.put(fieldName, fieldBinding);
// remember that we have seen a field with this name
if (fieldBinding != null)
fieldBindings[count++] = fieldBinding;
}
}
fieldBindings[count++]=prototype;
// remove duplicate fields
if (duplicate) {
FieldBinding[] newFieldBindings = new FieldBinding[fieldBindings.length];
// we know we'll be removing at least 1 duplicate name
size = count;
count = 0;
for (int i = 0; i < size; i++) {
FieldBinding fieldBinding = fieldBindings[i];
if (knownFieldNames.get(fieldBinding.name) != null) {
fieldBinding.id = count;
newFieldBindings[count++] = fieldBinding;
}
}
fieldBindings = newFieldBindings;
}
if (count != fieldBindings.length)
System.arraycopy(fieldBindings, 0, fieldBindings = new FieldBinding[count], 0, count);
setFields(fieldBindings);
}
private void buildMethods() {
int methodsSize = (this.classData.methods!=null)?this.classData.methods.length :0;
int constructorsSize = (this.classData.constructors!=null)?this.classData.constructors.length :0;
if (constructorsSize + methodsSize ==0 ) {
setMethods(Binding.NO_METHODS);
return;
}
int count = 0;
MethodBinding[] methodBindings = new MethodBinding[methodsSize+constructorsSize];
// create bindings for source methods
for (int i = 0; i < methodsSize; i++) {
Method method = this.classData.methods[i];
MethodBinding methodBinding = createMethodBinding(method,false);
methodBindings[count++] = methodBinding;
}
for (int i = 0; i < constructorsSize; i++) {
Method method = this.classData.constructors[i];
MethodBinding methodBinding = createMethodBinding(method,true);
methodBindings[count++] = methodBinding;
}
if (count != methodBindings.length)
System.arraycopy(methodBindings, 0, methodBindings = new MethodBinding[count], 0, count);
tagBits &= ~TagBits.AreMethodsSorted; // in case some static imports reached already into this type
setMethods(methodBindings);
}
private MethodBinding createMethodBinding(Method method, boolean isConstructor) {
int modifiers = ExtraCompilerModifiers.AccUnresolved;
if (method.isStatic())
modifiers|=ClassFileConstants.AccStatic;
modifiers|=ClassFileConstants.AccPublic;
MethodBinding methodBinding =null;
if (isConstructor)
{
methodBinding =new MethodBinding(modifiers, null, null, this);
methodBinding.tagBits|=TagBits.IsConstructor;
}
else
{
TypeBinding returnType = (method.returns!=null ) ? this.libraryScope.resolveType(method.returns.type) : TypeBinding.UNKNOWN;
// TypeBinding returnType =
// (method instanceof FunctionDeclaration && ((FunctionDeclaration)method).returnType!=null && method.inferredMethod!=null)?method.inferredType.resolveType(this,((FunctionDeclaration)method).returnType):TypeBinding.ANY;
methodBinding =
new MethodBinding(modifiers, method.name.toCharArray(),returnType, null, null, this);
methodBinding.createFunctionTypeBinding(this.libraryScope);
}
methodBinding.oaaMethod=method;
return methodBinding;
}
public int kind() {
return Binding.TYPE;
}
public char[] computeUniqueKey(boolean isLeaf) {
char[] uniqueKey = super.computeUniqueKey(isLeaf);
if (uniqueKey.length == 2) return uniqueKey; // problem type's unique key is "L;"
if (Util.isClassFileName(this.fileName)
||org.eclipse.wst.jsdt.internal.core.util.Util.isMetadataFileName(new String(this.fileName)))
return uniqueKey; // no need to insert compilation unit name for a .class file
// insert compilation unit name if the type name is not the main type name
int end = CharOperation.lastIndexOf('.', this.fileName);
if (end != -1) {
int start = CharOperation.lastIndexOf('/', this.fileName) + 1;
char[] mainTypeName = CharOperation.subarray(this.fileName, start, end);
start = CharOperation.lastIndexOf('/', uniqueKey) + 1;
if (start == 0)
start = 1; // start after L
end = CharOperation.indexOf('$', uniqueKey, start);
if (end == -1)
end = CharOperation.indexOf('<', uniqueKey, start);
if (end == -1)
end = CharOperation.indexOf(';', uniqueKey, start);
char[] topLevelType = CharOperation.subarray(uniqueKey, start, end);
if (!CharOperation.equals(topLevelType, mainTypeName)) {
StringBuffer buffer = new StringBuffer();
buffer.append(uniqueKey, 0, start);
buffer.append(mainTypeName);
buffer.append('~');
buffer.append(topLevelType);
buffer.append(uniqueKey, end, uniqueKey.length - end);
int length = buffer.length();
uniqueKey = new char[length];
buffer.getChars(0, length, uniqueKey, 0);
return uniqueKey;
}
}
return uniqueKey;
}
void faultInTypesForFieldsAndMethods() {
// check @Deprecated annotation
// getAnnotationTagBits(); // marks as deprecated by side effect
ReferenceBinding enclosingType = this.enclosingType();
if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !this.isDeprecated())
this.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;
fields();
methods();
// for (int i = 0, length = this.memberTypes.length; i < length; i++)
// ((SourceTypeBinding) this.memberTypes[i]).faultInTypesForFieldsAndMethods();
}
// NOTE: the type of each field of a source type is resolved when needed
public FieldBinding[] fields() {
if ((this.tagBits & TagBits.AreFieldsComplete) == 0)
{
if (!fieldsBuilt)
{
buildFields();
fieldsBuilt=true;
}
int failed = 0;
FieldBinding[] resolvedFields = this.fields;
try {
// lazily sort fields
if ((this.tagBits & TagBits.AreFieldsSorted) == 0) {
int length = this.fields.length;
if (length > 1)
ReferenceBinding.sortFields(this.fields, 0, length);
this.tagBits |= TagBits.AreFieldsSorted;
}
for (int i = 0, length = this.fields.length; i < length; i++) {
if (resolveTypeFor(this.fields[i]) == null) {
// do not alter original field array until resolution is over, due to reentrance (143259)
if (resolvedFields == this.fields) {
System.arraycopy(this.fields, 0, resolvedFields = new FieldBinding[length], 0, length);
}
resolvedFields[i] = null;
failed++;
}
}
} finally {
if (failed > 0) {
// ensure fields are consistent reqardless of the error
int newSize = resolvedFields.length - failed;
if (newSize == 0)
return this.fields = Binding.NO_FIELDS;
FieldBinding[] newFields = new FieldBinding[newSize];
for (int i = 0, j = 0, length = resolvedFields.length; i < length; i++) {
if (resolvedFields[i] != null)
newFields[j++] = resolvedFields[i];
}
this.fields = newFields;
}
}
this.tagBits |= TagBits.AreFieldsComplete;
}
return this.fields;
}
public MethodBinding[] getDefaultAbstractMethods() {
int count = 0;
for (int i = this.methods.length; --i >= 0;)
if (this.methods[i].isDefaultAbstract())
count++;
if (count == 0) return Binding.NO_METHODS;
MethodBinding[] result = new MethodBinding[count];
count = 0;
for (int i = this.methods.length; --i >= 0;)
if (this.methods[i].isDefaultAbstract())
result[count++] = this.methods[i];
return result;
}
public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
int argCount = argumentTypes.length;
if ((this.tagBits & TagBits.AreMethodsComplete) != 0) { // have resolved all arg types & return type of the methods
long range;
if ((range = ReferenceBinding.binarySearch(TypeConstants.INIT, this.methods)) >= 0) {
// nextMethod:
for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
MethodBinding method = this.methods[imethod];
// if (method.parameters.length == argCount) {
// TypeBinding[] toMatch = method.parameters;
// for (int iarg = 0; iarg < argCount; iarg++)
// if (toMatch[iarg] != argumentTypes[iarg])
// continue nextMethod;
return method;
// }
}
}
} else {
if (!methodsBuilt)
{
buildMethods();
methodsBuilt=true;
}
// lazily sort methods
if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {
int length = this.methods.length;
if (length > 1)
ReferenceBinding.sortMethods(this.methods, 0, length);
this.tagBits |= TagBits.AreMethodsSorted;
}
long range;
if ((range = ReferenceBinding.binarySearch(TypeConstants.INIT, this.methods)) >= 0) {
// nextMethod:
for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
MethodBinding method = this.methods[imethod];
if (resolveTypesFor(method) == null || method.returnType == null) {
methods();
return getExactConstructor(argumentTypes); // try again since the problem methods have been removed
}
// if (method.parameters.length == argCount) {
// TypeBinding[] toMatch = method.parameters;
// for (int iarg = 0; iarg < argCount; iarg++)
// if (toMatch[iarg] != argumentTypes[iarg])
// continue nextMethod;
// return method;
// }
return method;
}
}
}
return null;
}
public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {
// sender from refScope calls recordTypeReference(this)
// int argCount = argumentTypes.length;
boolean foundNothing = true;
if ((this.tagBits & TagBits.AreMethodsComplete) != 0) { // have resolved all arg types & return type of the methods
long range;
if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {
// nextMethod:
for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {
MethodBinding method = this.methods[imethod];
foundNothing = false; // inner type lookups must know that a method with this name exists
// if (method.parameters.length == argCount) {
// TypeBinding[] toMatch = method.parameters;
// for (int iarg = 0; iarg < argCount; iarg++)
// if (toMatch[iarg] != argumentTypes[iarg])
// {
// if (toMatch[iarg].id!=TypeIds.T_any && argumentTypes[iarg].id!=TypeIds.T_any)
// continue nextMethod;
// }
// return method;
// }
return method;
}
}
} else {
if (!methodsBuilt)
{
buildMethods();
methodsBuilt=true;
}
// lazily sort methods
if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {
int length = this.methods.length;
if (length > 1)
ReferenceBinding.sortMethods(this.methods, 0, length);
this.tagBits |= TagBits.AreMethodsSorted;
}
long range;
if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {
// check unresolved method
int start = (int) range, end = (int) (range >> 32);
for (int imethod = start; imethod <= end; imethod++) {
MethodBinding method = this.methods[imethod];
if (resolveTypesFor(method) == null || method.returnType == null) {
methods();
return getExactMethod(selector, argumentTypes, refScope); // try again since the problem methods have been removed
}
}
// check dup collisions
boolean isSource15 = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
for (int i = start; i <= end; i++) {
MethodBinding method1 = this.methods[i];
for (int j = end; j > i; j--) {
MethodBinding method2 = this.methods[j];
boolean paramsMatch = isSource15
? method1.areParameterErasuresEqual(method2)
: method1.areParametersEqual(method2);
if (paramsMatch) {
methods();
return getExactMethod(selector, argumentTypes, refScope); // try again since the problem methods have been removed
}
}
}
return this.methods[start];
// nextMethod: for (int imethod = start; imethod <= end; imethod++) {
// FunctionBinding method = this.methods[imethod];
// TypeBinding[] toMatch = method.parameters;
// if (toMatch.length == argCount) {
// for (int iarg = 0; iarg < argCount; iarg++)
// if (toMatch[iarg] != argumentTypes[iarg])
// continue nextMethod;
// return method;
// }
// }
}
}
if (foundNothing) {
if (JavaScriptCore.IS_ECMASCRIPT4 && isInterface()) {
if (this.superInterfaces.length == 1) {
if (refScope != null)
refScope.recordTypeReference(this.superInterfaces[0]);
return this.superInterfaces[0].getExactMethod(selector, argumentTypes, refScope);
}
/* BC- Added cycle check BUG 200501 */
} else if (this.superclass != null && this.superclass!=this) {
if (refScope != null)
refScope.recordTypeReference(this.superclass);
return this.superclass.getExactMethod(selector, argumentTypes, refScope);
}
}
return null;
}
public FieldBinding getField(char[] fieldName, boolean needResolve) {
if ((this.tagBits & TagBits.AreFieldsComplete) != 0)
return ReferenceBinding.binarySearch(fieldName, this.fields);
if (!fieldsBuilt)
{
buildFields();
fieldsBuilt=true;
}
// lazily sort fields
if ((this.tagBits & TagBits.AreFieldsSorted) == 0) {
int length = this.fields.length;
if (length > 1)
ReferenceBinding.sortFields(this.fields, 0, length);
this.tagBits |= TagBits.AreFieldsSorted;
}
// always resolve anyway on source types
FieldBinding field = ReferenceBinding.binarySearch(fieldName, this.fields);
if (field != null) {
FieldBinding result = null;
try {
result = resolveTypeFor(field);
return result;
} finally {
if (result == null) {
// ensure fields are consistent reqardless of the error
int newSize = this.fields.length - 1;
if (newSize == 0) {
this.fields = Binding.NO_FIELDS;
} else {
FieldBinding[] newFields = new FieldBinding[newSize];
int index = 0;
for (int i = 0, length = this.fields.length; i < length; i++) {
FieldBinding f = this.fields[i];
if (f == field) continue;
newFields[index++] = f;
}
this.fields = newFields;
}
}
}
}
return null;
}
public MethodBinding[] getMethods(char[] selector) {
if ((this.tagBits & TagBits.AreMethodsComplete) != 0) {
long range;
if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {
int start = (int) range, end = (int) (range >> 32);
int length = end - start + 1;
MethodBinding[] result;
System.arraycopy(this.methods, start, result = new MethodBinding[length], 0, length);
return result;
} else {
return Binding.NO_METHODS;
}
}
if (!methodsBuilt)
{
buildMethods();
methodsBuilt=true;
}
// lazily sort methods
if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {
int length = this.methods.length;
if (length > 1)
ReferenceBinding.sortMethods(this.methods, 0, length);
this.tagBits |= TagBits.AreMethodsSorted;
}
MethodBinding[] result;
long range;
if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {
int start = (int) range, end = (int) (range >> 32);
for (int i = start; i <= end; i++) {
MethodBinding method = this.methods[i];
if (resolveTypesFor(method) == null || method.returnType == null) {
methods();
return getMethods(selector); // try again since the problem methods have been removed
}
}
int length = end - start + 1;
System.arraycopy(this.methods, start, result = new MethodBinding[length], 0, length);
} else {
return Binding.NO_METHODS;
}
boolean isSource15 = this.libraryScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
for (int i = 0, length = result.length - 1; i < length; i++) {
MethodBinding method = result[i];
for (int j = length; j > i; j--) {
boolean paramsMatch = isSource15
? method.areParameterErasuresEqual(result[j])
: method.areParametersEqual(result[j]);
if (paramsMatch) {
methods();
return getMethods(selector); // try again since the duplicate methods have been removed
}
}
}
return result;
}
/**
* @see org.eclipse.wst.jsdt.internal.compiler.lookup.Binding#initializeDeprecatedAnnotationTagBits()
*/
public void initializeDeprecatedAnnotationTagBits() {
// if ((this.tagBits & TagBits.DeprecatedAnnotationResolved) == 0) {
// TypeDeclaration typeDecl = this.classScope.referenceContext;
// boolean old = typeDecl.staticInitializerScope.insideTypeAnnotation;
// try {
// typeDecl.staticInitializerScope.insideTypeAnnotation = true;
// ASTNode.resolveDeprecatedAnnotations(typeDecl.staticInitializerScope, typeDecl.annotations, this);
// this.tagBits |= TagBits.DeprecatedAnnotationResolved;
// } finally {
// typeDecl.staticInitializerScope.insideTypeAnnotation = old;
// }
// if ((this.tagBits & TagBits.AnnotationDeprecated) != 0) {
// this.modifiers |= ClassFileConstants.AccDeprecated;
// }
// }
}
/**
* Returns true if a type is identical to another one,
* or for generic types, true if compared to its raw type.
*/
public boolean isEquivalentTo(TypeBinding otherType) {
if (this == otherType) return true;
if (otherType == null) return false;
return false;
}
public boolean isGenericType() {
return this.typeVariables != Binding.NO_TYPE_VARIABLES;
}
public ReferenceBinding[] memberTypes() {
if (this.nextType==null)
return this.memberTypes;
ReferenceBinding[] moreTypes=this.nextType.memberTypes();
ReferenceBinding[] combinedTypes=new ReferenceBinding[this.memberTypes.length+moreTypes.length];
System.arraycopy(this.memberTypes, 0, combinedTypes, 0, this.memberTypes.length);
System.arraycopy(moreTypes, 0, combinedTypes, this.memberTypes.length, moreTypes.length);
return combinedTypes;
}
public boolean hasMemberTypes() {
boolean hasMembers= this.memberTypes!=null && this.memberTypes.length > 0;
if (!hasMembers && this.nextType!=null)
hasMembers=this.nextType.hasMemberTypes();
return hasMembers;
}
// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
public MethodBinding[] methods() {
if ((this.tagBits & TagBits.AreMethodsComplete) == 0) {
if (!methodsBuilt)
{
buildMethods();
methodsBuilt=true;
}
// lazily sort methods
if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {
int length = this.methods.length;
if (length > 1)
ReferenceBinding.sortMethods(this.methods, 0, length);
this.tagBits |= TagBits.AreMethodsSorted;
}
int failed = 0;
MethodBinding[] resolvedMethods = this.methods;
try {
for (int i = 0, length = this.methods.length; i < length; i++) {
if (resolveTypesFor(this.methods[i]) == 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; // unable to resolve parameters
failed++;
}
}
// find & report collision cases
boolean complyTo15 =
(this.libraryScope!=null && this.libraryScope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5);
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.libraryScope.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 MetatdataTypeBinding
&& 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.libraryScope.problemReporter()
// .duplicateEnumSpecialMethod(this,
// methodDecl);
// } else {
// this.libraryScope
// .problemReporter()
// .duplicateMethodInType(this, methodDecl);
// }
// 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 FunctionBinding[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.libraryScope.problemReporter()
// .duplicateEnumSpecialMethod(this,
// method2Decl);
// } else {
// this.libraryScope.problemReporter().duplicateMethodInType(
// this, method2Decl);
// }
// method2Decl.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 FunctionBinding[length],
// 0, length);
// }
// resolvedMethods[j] = null;
// failed++;
// }
}
// if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
// methodDecl = method.sourceMethod();
// if (methodDecl != null) {
// 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 FunctionBinding[length], 0,
// length);
// }
// resolvedMethods[i] = null;
// failed++;
// }
}
} finally {
if (failed > 0) {
int newSize = resolvedMethods.length - failed;
if (newSize == 0) {
this.methods = Binding.NO_METHODS;
} else {
MethodBinding[] newMethods = new MethodBinding[newSize];
for (int i = 0, j = 0, length = resolvedMethods.length; i < length; i++)
if (resolvedMethods[i] != null)
newMethods[j++] = resolvedMethods[i];
this.methods = newMethods;
}
}
// handle forward references to potential default abstract methods
// addDefaultAbstractMethods();
this.tagBits |= TagBits.AreMethodsComplete;
}
}
if (this.nextType!=null)
{
MethodBinding[] moreMethods=this.nextType.methods();
MethodBinding[] combinedMethods=new MethodBinding[this.methods.length+moreMethods.length];
System.arraycopy(this.methods, 0, combinedMethods, 0, this.methods.length);
System.arraycopy(moreMethods, 0, combinedMethods, this.methods.length, moreMethods.length);
return combinedMethods;
}
else
return this.methods;
}
private FieldBinding resolveTypeFor(FieldBinding field) {
if ((field.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
return field;
if (this.scope!=null && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
if ((field.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0)
field.modifiers |= ClassFileConstants.AccDeprecated;
}
if (isViewedAsDeprecated() && !field.isDeprecated())
field.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;
if (hasRestrictedAccess())
field.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
return field;
}
public MethodBinding resolveTypesFor(MethodBinding method) {
if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)
return method;
if (this.scope!=null && this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {
if ((method.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0)
method.modifiers |= ClassFileConstants.AccDeprecated;
}
if (isViewedAsDeprecated() && !method.isDeprecated())
method.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;
if (hasRestrictedAccess())
method.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;
Method methodDecl = method.oaaMethod;
if (methodDecl == null) return null; // method could not be resolved in previous iteration
boolean foundArgProblem = false;
Parameter[] arguments = methodDecl.parameters;
if (arguments != null) {
int size = arguments.length;
method.parameters = Binding.NO_PARAMETERS;
TypeBinding[] newParameters = new TypeBinding[size];
for (int i = 0; i < size; i++) {
Parameter arg = arguments[i];
TypeBinding parameterType = TypeBinding.UNKNOWN;
parameterType = libraryScope.resolveType(arg.type) ;
// else
if (parameterType == TypeBinding.VOID) {
// scope.problemReporter().argumentTypeCannotBeVoid(this, methodDecl, arg);
foundArgProblem = true;
} else {
TypeBinding leafType = parameterType.leafComponentType();
if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
method.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
newParameters[i] = parameterType;
}
}
// only assign parameters if no problems are found
if (!foundArgProblem)
method.parameters = newParameters;
}
boolean foundReturnTypeProblem = false;
if (foundArgProblem) {
method.parameters = Binding.NO_PARAMETERS; // see 107004
// nullify type parameter bindings as well as they have a backpointer to the method binding
// (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81134)
return null;
}
if (foundReturnTypeProblem)
return method; // but its still unresolved with a null return type & is still connected to its method declaration
method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
return method;
}
public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {
if (forceInitialization)
binding.getAnnotationTagBits(); // ensure annotations are up to date
return super.retrieveAnnotationHolder(binding, false);
}
public void setFields(FieldBinding[] fields) {
// if (this.nextType!=null)
// throw new UnimplementedException("should not get here"); //$NON-NLS-1$
this.fields = fields;
}
public void setMethods(MethodBinding[] methods) {
// if (this.nextType!=null)
// throw new UnimplementedException("should not get here"); //$NON-NLS-1$
this.methods = methods;
}
public final int sourceEnd() {
return -1;
}
public final int sourceStart() {
return -1;
}
public ReferenceBinding superclass() {
return this.superclass;
}
public ReferenceBinding[] superInterfaces() {
return this.superInterfaces;
}
public String toString() {
StringBuffer buffer = new StringBuffer(30);
buffer.append("(id="); //$NON-NLS-1$
if (this.id == TypeIds.NoId)
buffer.append("NoId"); //$NON-NLS-1$
else
buffer.append(this.id);
buffer.append(")\n"); //$NON-NLS-1$
if (isDeprecated()) buffer.append("deprecated "); //$NON-NLS-1$
if (isPublic()) buffer.append("public "); //$NON-NLS-1$
if (isProtected()) buffer.append("protected "); //$NON-NLS-1$
if (isPrivate()) buffer.append("private "); //$NON-NLS-1$
if (isAbstract() && isClass()) buffer.append("abstract "); //$NON-NLS-1$
if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$
if (isFinal()) buffer.append("final "); //$NON-NLS-1$
if (isEnum()) buffer.append("enum "); //$NON-NLS-1$
else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$
else if (isClass()) buffer.append("class "); //$NON-NLS-1$
else buffer.append("interface "); //$NON-NLS-1$
buffer.append((this.compoundName != null) ? CharOperation.toString(this.compoundName) : "UNNAMED TYPE"); //$NON-NLS-1$
if (this.typeVariables == null) {
buffer.append("<NULL TYPE VARIABLES>"); //$NON-NLS-1$
} else if (this.typeVariables != Binding.NO_TYPE_VARIABLES) {
buffer.append("\n\t<"); //$NON-NLS-1$
for (int i = 0, length = this.typeVariables.length; i < length; i++) {
if (i > 0)
buffer.append(", "); //$NON-NLS-1$
buffer.append((this.typeVariables[i] != null) ? this.typeVariables[i].toString() : "NULL TYPE VARIABLE"); //$NON-NLS-1$
}
buffer.append(">"); //$NON-NLS-1$
}
buffer.append("\n\textends "); //$NON-NLS-1$
buffer.append((this.superclass != null) ? this.superclass.debugName() : "NULL TYPE"); //$NON-NLS-1$
if (this.superInterfaces != null) {
if (this.superInterfaces != Binding.NO_SUPERINTERFACES) {
buffer.append("\n\timplements : "); //$NON-NLS-1$
for (int i = 0, length = this.superInterfaces.length; i < length; i++) {
if (i > 0)
buffer.append(", "); //$NON-NLS-1$
buffer.append((this.superInterfaces[i] != null) ? this.superInterfaces[i].debugName() : "NULL TYPE"); //$NON-NLS-1$
}
}
} else {
buffer.append("NULL SUPERINTERFACES"); //$NON-NLS-1$
}
if (enclosingType() != null) {
buffer.append("\n\tenclosing type : "); //$NON-NLS-1$
buffer.append(enclosingType().debugName());
}
if (this.fields != null) {
if (this.fields != Binding.NO_FIELDS) {
buffer.append("\n/* fields */"); //$NON-NLS-1$
for (int i = 0, length = this.fields.length; i < length; i++)
buffer.append('\n').append((this.fields[i] != null) ? this.fields[i].toString() : "NULL FIELD"); //$NON-NLS-1$
}
} else {
buffer.append("NULL FIELDS"); //$NON-NLS-1$
}
if (this.methods != null) {
if (this.methods != Binding.NO_METHODS) {
buffer.append("\n/* methods */"); //$NON-NLS-1$
for (int i = 0, length = this.methods.length; i < length; i++)
buffer.append('\n').append((this.methods[i] != null) ? this.methods[i].toString() : "NULL METHOD"); //$NON-NLS-1$
}
} else {
buffer.append("NULL METHODS"); //$NON-NLS-1$
}
if (this.memberTypes != null) {
if (this.memberTypes != Binding.NO_MEMBER_TYPES) {
buffer.append("\n/* members */"); //$NON-NLS-1$
for (int i = 0, length = this.memberTypes.length; i < length; i++)
buffer.append('\n').append((this.memberTypes[i] != null) ? this.memberTypes[i].toString() : "NULL TYPE"); //$NON-NLS-1$
}
} else {
buffer.append("NULL MEMBER TYPES"); //$NON-NLS-1$
}
buffer.append("\n\n"); //$NON-NLS-1$
return buffer.toString();
}
public TypeVariableBinding[] typeVariables() {
return this.typeVariables;
}
void verifyMethods(MethodVerifier verifier) {
verifier.verify(this);
// for (int i = this.memberTypes.length; --i >= 0;)
// ((SourceTypeBinding) this.memberTypes[i]).verifyMethods(verifier);
}
public AbstractMethodDeclaration sourceMethod(MethodBinding binding) {
return null;
}
public void addMethod(MethodBinding binding)
{
int length=this.methods.length;
System.arraycopy(this.methods, 0, this.methods=new MethodBinding[length+1], 0, length);
this.methods[length]=binding;
}
public void cleanup()
{
this.scope=null;
this.classScope=null;
super.cleanup();
// clean up should be called for each compilation unit, so it shouldnt be necessary to chain the cleanups
//if (this.nextType!=null)
// this.nextType.cleanup();
}
public boolean contains(ReferenceBinding binding)
{
return false;
}
public ClassData getClassData()
{
return this.classData;
}
public LibraryAPIsScope getLibraryAPIsScope()
{
return this.libraryScope;
}
}