blob: fb1a2f337d75007c3f106fcb4178843e1d674f42 [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 java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import org.eclipse.wst.jsdt.core.JavaScriptCore;
import org.eclipse.wst.jsdt.core.UnimplementedException;
import org.eclipse.wst.jsdt.core.compiler.CharOperation;
import org.eclipse.wst.jsdt.core.infer.InferredAttribute;
import org.eclipse.wst.jsdt.core.infer.InferredMethod;
import org.eclipse.wst.jsdt.core.infer.InferredType;
import org.eclipse.wst.jsdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.Argument;
import org.eclipse.wst.jsdt.internal.compiler.ast.FieldDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.MethodDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeDeclaration;
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeParameter;
import org.eclipse.wst.jsdt.internal.compiler.ast.TypeReference;
import org.eclipse.wst.jsdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.wst.jsdt.internal.compiler.impl.Constant;
import org.eclipse.wst.jsdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.wst.jsdt.internal.compiler.util.SimpleLookupTable;
import org.eclipse.wst.jsdt.internal.compiler.util.Util;
public class SourceTypeBinding extends ReferenceBinding {
public ReferenceBinding superclass;
public ReferenceBinding[] superInterfaces= Binding.NO_SUPERINTERFACES;
protected FieldBinding[] fields;
protected MethodBinding[] methods;
public ReferenceBinding[] memberTypes=Binding.NO_MEMBER_TYPES;
public TypeVariableBinding[] typeVariables=Binding.NO_TYPE_VARIABLES;
public Scope scope;
public ClassScope classScope;
// Synthetics are separated into 5 categories: methods, super methods, fields, class literals, changed declaring type bindings and bridge methods
public final static int METHOD_EMUL = 0;
public final static int FIELD_EMUL = 1;
public final static int CLASS_LITERAL_EMUL = 2;
public final static int RECEIVER_TYPE_EMUL = 3;
HashMap[] synthetics;
char[] genericReferenceTypeSignature;
public SourceTypeBinding nextType;
private SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder
public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, Scope scope) {
this.compoundName = compoundName;
this.fPackage = fPackage;
this.fileName = scope.referenceCompilationUnit().getFileName();
if (scope instanceof ClassScope)
{
this.classScope=(ClassScope)scope;
if (this.classScope.referenceContext!=null) {
this.modifiers = this.classScope.referenceContext.modifiers;
this.sourceName = this.classScope.referenceContext.name;
}
else
{
this.sourceName = this.classScope.inferredType.getName();
this.modifiers=ClassFileConstants.AccPublic;
}
}
this.scope = scope;
// expect the fields & methods to be initialized correctly later
this.fields = Binding.NO_FIELDS;
this.methods = Binding.NO_METHODS;
computeId();
}
protected SourceTypeBinding()
{
}
void buildFieldsAndMethods() {
buildFields();
buildMethods();
}
public InferredType getInferredType() {
if (this.nextType!=null)
throw new UnimplementedException("should not get here"); //$NON-NLS-1$
ClassScope classScope = scope.classScope();
return classScope.inferredType;
}
private void buildFields() {
FieldBinding prototype = new FieldBinding(TypeConstants.PROTOTYPE, TypeBinding.UNKNOWN, modifiers | ExtraCompilerModifiers.AccUnresolved, this,null);
InferredType inferredType=this.classScope.inferredType;
int size = inferredType.numberAttributes;
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++) {
InferredAttribute field = inferredType.attributes[i];
int modifiers=0;
if (field.isStatic)
modifiers|=ClassFileConstants.AccStatic;
InferredType fieldType = field.type;
TypeBinding fieldTypeBinding=null;
if(fieldType!=null) {
//fieldTypeBinding = BaseTypeBinding.UNKNOWN;
// fieldTypeBinding = scope.getType(fieldType.getName());
fieldTypeBinding = fieldType.resolveType(scope, field.node);
}
if (fieldTypeBinding==null)
fieldTypeBinding = TypeBinding.UNKNOWN;
FieldBinding fieldBinding = new FieldBinding(field, fieldTypeBinding, modifiers | ExtraCompilerModifiers.AccUnresolved, this);
fieldBinding.id = count;
// field's type will be resolved when needed for top level types
// checkAndSetModifiersForField(fieldBinding, field);
if (knownFieldNames.containsKey(field.name)) {
duplicate = true;
FieldBinding previousBinding = (FieldBinding) knownFieldNames.get(field.name);
if (previousBinding != null) {
for (int f = 0; f < i; f++) {
InferredAttribute previousField = inferredType.attributes[f];
if (previousField.binding == previousBinding) {
scope.problemReporter().duplicateFieldInType(this, previousField);
previousField.binding = null;
break;
}
}
}
knownFieldNames.put(field.name, null); // ensure that the duplicate field is found & removed
scope.problemReporter().duplicateFieldInType(this, field);
field.binding = null;
} else {
knownFieldNames.put(field.name, 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() {
InferredType inferredType=this.classScope.inferredType;
int size = (inferredType.methods!=null)?inferredType.methods.size() :0;
if (size==0 ) {
setMethods(Binding.NO_METHODS);
return;
}
int count = 0;
MethodBinding[] methodBindings = new MethodBinding[size];
// create bindings for source methods
for (int i = 0; i < size; i++) {
InferredMethod method = (InferredMethod)inferredType.methods.get(i);
MethodScope scope = new MethodScope(this.scope, (MethodDeclaration)method.getFunctionDeclaration(), false);
MethodBinding methodBinding = scope.createMethod(method,this);
method.methodBinding=methodBinding;
if (methodBinding != null) // is null if binding could not be created
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 void addDefaultAbstractMethods() {
// if ((this.tagBits & TagBits.KnowsDefaultAbstractMethods) != 0) return;
//
// this.tagBits |= TagBits.KnowsDefaultAbstractMethods;
// if (isClass() && isAbstract()) {
// if (this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_2)
// return; // no longer added for post 1.2 targets
//
// ReferenceBinding[] itsInterfaces = superInterfaces();
// if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
// FunctionBinding[] defaultAbstracts = null;
// int defaultAbstractsCount = 0;
// ReferenceBinding[] interfacesToVisit = itsInterfaces;
// int nextPosition = interfacesToVisit.length;
// for (int i = 0; i < nextPosition; i++) {
// ReferenceBinding superType = interfacesToVisit[i];
// if (superType.isValidBinding()) {
// FunctionBinding[] superMethods = superType.methods();
// nextAbstractMethod: for (int m = superMethods.length; --m >= 0;) {
// FunctionBinding method = superMethods[m];
// // explicitly implemented ?
// if (implementsMethod(method))
// continue nextAbstractMethod;
// if (defaultAbstractsCount == 0) {
// defaultAbstracts = new FunctionBinding[5];
// } else {
// // already added as default abstract ?
// for (int k = 0; k < defaultAbstractsCount; k++) {
// FunctionBinding alreadyAdded = defaultAbstracts[k];
// if (CharOperation.equals(alreadyAdded.selector, method.selector) && alreadyAdded.areParametersEqual(method))
// continue nextAbstractMethod;
// }
// }
// FunctionBinding defaultAbstract = new FunctionBinding(
// method.modifiers | ExtraCompilerModifiers.AccDefaultAbstract,
// method.selector,
// method.returnType,
// method.parameters,
// method.thrownExceptions,
// this);
// if (defaultAbstractsCount == defaultAbstracts.length)
// System.arraycopy(defaultAbstracts, 0, defaultAbstracts = new FunctionBinding[2 * defaultAbstractsCount], 0, defaultAbstractsCount);
// defaultAbstracts[defaultAbstractsCount++] = defaultAbstract;
// }
//
// 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 (next == interfacesToVisit[b]) continue nextInterface;
// interfacesToVisit[nextPosition++] = next;
// }
// }
// }
// }
// if (defaultAbstractsCount > 0) {
// int length = this.methods.length;
// System.arraycopy(this.methods, 0, this.methods = new FunctionBinding[length + defaultAbstractsCount], 0, length);
// System.arraycopy(defaultAbstracts, 0, this.methods, length, defaultAbstractsCount);
// // re-sort methods
// length = length + defaultAbstractsCount;
// if (length > 1)
// ReferenceBinding.sortMethods(this.methods, 0, length);
// // this.tagBits |= TagBits.AreMethodsSorted; -- already set in #methods()
// }
// }
// }
//}
/* Add a new synthetic field for <actualOuterLocalVariable>.
* Answer the new field or the existing field if one already existed.
*/
public FieldBinding addSyntheticFieldForInnerclass(LocalVariableBinding actualOuterLocalVariable) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap(5);
FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable);
if (synthField == null) {
synthField = new SyntheticFieldBinding(
CharOperation.concat(TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX, actualOuterLocalVariable.name),
actualOuterLocalVariable.type,
ClassFileConstants.AccPrivate | ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic,
this,
Constant.NotAConstant,
this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
this.synthetics[SourceTypeBinding.FIELD_EMUL].put(actualOuterLocalVariable, synthField);
}
// ensure there is not already such a field defined by the user
boolean needRecheck;
int index = 1;
do {
needRecheck = false;
FieldBinding existingField;
if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
TypeDeclaration typeDecl = this.classScope.referenceContext;
for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
FieldDeclaration fieldDecl = typeDecl.fields[i];
if (fieldDecl.binding == existingField) {
synthField.name = CharOperation.concat(
TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX,
actualOuterLocalVariable.name,
("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
needRecheck = true;
break;
}
}
}
} while (needRecheck);
return synthField;
}
/* Add a new synthetic field for <enclosingType>.
* Answer the new field or the existing field if one already existed.
*/
public FieldBinding addSyntheticFieldForInnerclass(ReferenceBinding enclosingType) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap(5);
FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(enclosingType);
if (synthField == null) {
synthField = new SyntheticFieldBinding(
CharOperation.concat(
TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX,
String.valueOf(enclosingType.depth()).toCharArray()),
enclosingType,
ClassFileConstants.AccDefault | ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic,
this,
Constant.NotAConstant,
this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
this.synthetics[SourceTypeBinding.FIELD_EMUL].put(enclosingType, synthField);
}
// ensure there is not already such a field defined by the user
boolean needRecheck;
do {
needRecheck = false;
FieldBinding existingField;
if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
TypeDeclaration typeDecl = this.classScope.referenceContext;
for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
FieldDeclaration fieldDecl = typeDecl.fields[i];
if (fieldDecl.binding == existingField) {
if (this.scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5) {
synthField.name = CharOperation.concat(
synthField.name,
"$".toCharArray()); //$NON-NLS-1$
needRecheck = true;
} else {
this.scope.problemReporter().duplicateFieldInType(this, fieldDecl);
}
break;
}
}
}
} while (needRecheck);
return synthField;
}
/* Add a new synthetic field for a class literal access.
* Answer the new field or the existing field if one already existed.
*/
public FieldBinding addSyntheticFieldForClassLiteral(TypeBinding targetType, BlockScope blockScope) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] == null)
this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] = new HashMap(5);
// use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class.
FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].get(targetType);
if (synthField == null) {
synthField = new SyntheticFieldBinding(
CharOperation.concat(
TypeConstants.SYNTHETIC_CLASS,
String.valueOf(this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size()).toCharArray()),
blockScope.getJavaLangClass(),
ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic,
this,
Constant.NotAConstant,
this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size());
this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].put(targetType, synthField);
}
// ensure there is not already such a field defined by the user
FieldBinding existingField;
if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
TypeDeclaration typeDecl = blockScope.referenceType();
for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
FieldDeclaration fieldDecl = typeDecl.fields[i];
if (fieldDecl.binding == existingField) {
blockScope.problemReporter().duplicateFieldInType(this, fieldDecl);
break;
}
}
}
return synthField;
}
/* Add a new synthetic field for the emulation of the assert statement.
* Answer the new field or the existing field if one already existed.
*/
public FieldBinding addSyntheticFieldForAssert(BlockScope blockScope) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap(5);
FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get("assertionEmulation"); //$NON-NLS-1$
if (synthField == null) {
synthField = new SyntheticFieldBinding(
TypeConstants.SYNTHETIC_ASSERT_DISABLED,
TypeBinding.BOOLEAN,
ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic | ClassFileConstants.AccFinal,
this,
Constant.NotAConstant,
this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
this.synthetics[SourceTypeBinding.FIELD_EMUL].put("assertionEmulation", synthField); //$NON-NLS-1$
}
// ensure there is not already such a field defined by the user
// ensure there is not already such a field defined by the user
boolean needRecheck;
int index = 0;
do {
needRecheck = false;
FieldBinding existingField;
if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
TypeDeclaration typeDecl = this.classScope.referenceContext;
for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
FieldDeclaration fieldDecl = typeDecl.fields[i];
if (fieldDecl.binding == existingField) {
synthField.name = CharOperation.concat(
TypeConstants.SYNTHETIC_ASSERT_DISABLED,
("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
needRecheck = true;
break;
}
}
}
} while (needRecheck);
return synthField;
}
/* Add a new synthetic field for recording all enum constant values
* Answer the new field or the existing field if one already existed.
*/
public FieldBinding addSyntheticFieldForEnumValues() {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap(5);
FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get("enumConstantValues"); //$NON-NLS-1$
if (synthField == null) {
synthField = new SyntheticFieldBinding(
TypeConstants.SYNTHETIC_ENUM_VALUES,
this.scope.createArrayType(this,1),
ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic | ClassFileConstants.AccFinal,
this,
Constant.NotAConstant,
this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
this.synthetics[SourceTypeBinding.FIELD_EMUL].put("enumConstantValues", synthField); //$NON-NLS-1$
}
// ensure there is not already such a field defined by the user
// ensure there is not already such a field defined by the user
boolean needRecheck;
int index = 0;
do {
needRecheck = false;
FieldBinding existingField;
if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
TypeDeclaration typeDecl = this.classScope.referenceContext;
for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
FieldDeclaration fieldDecl = typeDecl.fields[i];
if (fieldDecl.binding == existingField) {
synthField.name = CharOperation.concat(
TypeConstants.SYNTHETIC_ENUM_VALUES,
("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
needRecheck = true;
break;
}
}
}
} while (needRecheck);
return synthField;
}
/* Add a new synthetic access method for read/write access to <targetField>.
Answer the new method or the existing method if one already existed.
*/
public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
SyntheticMethodBinding accessMethod = null;
SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(targetField);
if (accessors == null) {
accessMethod = new SyntheticMethodBinding(targetField, isReadAccess, this);
this.synthetics[SourceTypeBinding.METHOD_EMUL].put(targetField, accessors = new SyntheticMethodBinding[2]);
accessors[isReadAccess ? 0 : 1] = accessMethod;
} else {
if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) {
accessMethod = new SyntheticMethodBinding(targetField, isReadAccess, this);
accessors[isReadAccess ? 0 : 1] = accessMethod;
}
}
return accessMethod;
}
/* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.
* char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
*/
public SyntheticMethodBinding addSyntheticEnumMethod(char[] selector) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
SyntheticMethodBinding accessMethod = null;
SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(selector);
if (accessors == null) {
accessMethod = new SyntheticMethodBinding(this, selector);
this.synthetics[SourceTypeBinding.METHOD_EMUL].put(selector, accessors = new SyntheticMethodBinding[2]);
accessors[0] = accessMethod;
} else {
if ((accessMethod = accessors[0]) == null) {
accessMethod = new SyntheticMethodBinding(this, selector);
accessors[0] = accessMethod;
}
}
return accessMethod;
}
/*
* Add a synthetic field to handle the cache of the switch translation table for the corresponding enum type
*/
public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, String key) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap(5);
SyntheticFieldBinding synthField = (SyntheticFieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(key);
if (synthField == null) {
synthField = new SyntheticFieldBinding(
fieldName,
this.scope.createArrayType(TypeBinding.INT,1),
ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic,
this,
Constant.NotAConstant,
this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
this.synthetics[SourceTypeBinding.FIELD_EMUL].put(key, synthField);
}
// ensure there is not already such a field defined by the user
boolean needRecheck;
int index = 0;
do {
needRecheck = false;
FieldBinding existingField;
if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
TypeDeclaration typeDecl = this.classScope.referenceContext;
for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
FieldDeclaration fieldDecl = typeDecl.fields[i];
if (fieldDecl.binding == existingField) {
synthField.name = CharOperation.concat(
fieldName,
("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
needRecheck = true;
break;
}
}
}
} while (needRecheck);
return synthField;
}
/* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.
* char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
*/
public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBinding) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
SyntheticMethodBinding accessMethod = null;
char[] selector = CharOperation.concat(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, enumBinding.constantPoolName());
CharOperation.replace(selector, '/', '$');
final String key = new String(selector);
SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(key);
// first add the corresponding synthetic field
if (accessors == null) {
// then create the synthetic method
final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);
accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);
this.synthetics[SourceTypeBinding.METHOD_EMUL].put(key, accessors = new SyntheticMethodBinding[2]);
accessors[0] = accessMethod;
} else {
if ((accessMethod = accessors[0]) == null) {
final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);
accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);
accessors[0] = accessMethod;
}
}
return accessMethod;
}
/* Add a new synthetic access method for access to <targetMethod>.
* Must distinguish access method used for super access from others (need to use invokespecial bytecode)
Answer the new method or the existing method if one already existed.
*/
public SyntheticMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
SyntheticMethodBinding accessMethod = null;
SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(targetMethod);
if (accessors == null) {
accessMethod = new SyntheticMethodBinding(targetMethod, isSuperAccess, this);
this.synthetics[SourceTypeBinding.METHOD_EMUL].put(targetMethod, accessors = new SyntheticMethodBinding[2]);
accessors[isSuperAccess ? 0 : 1] = accessMethod;
} else {
if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) {
accessMethod = new SyntheticMethodBinding(targetMethod, isSuperAccess, this);
accessors[isSuperAccess ? 0 : 1] = accessMethod;
}
}
return accessMethod;
}
/*
* Record the fact that bridge methods need to be generated to override certain inherited methods
*/
public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge, MethodBinding targetMethod) {
if (isInterface()) return null; // only classes & enums get bridge methods
// targetMethod may be inherited
if (inheritedMethodToBridge.returnType.erasure() == targetMethod.returnType.erasure()
&& inheritedMethodToBridge.areParameterErasuresEqual(targetMethod)) {
return null; // do not need bridge method
}
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) {
this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap(5);
} else {
// check to see if there is another equivalent inheritedMethod already added
Iterator synthMethods = this.synthetics[SourceTypeBinding.METHOD_EMUL].keySet().iterator();
while (synthMethods.hasNext()) {
Object synthetic = synthMethods.next();
if (synthetic instanceof MethodBinding) {
MethodBinding method = (MethodBinding) synthetic;
if (CharOperation.equals(inheritedMethodToBridge.selector, method.selector)
&& inheritedMethodToBridge.returnType.erasure() == method.returnType.erasure()
&& inheritedMethodToBridge.areParameterErasuresEqual(method)) {
return null;
}
}
}
}
SyntheticMethodBinding accessMethod = null;
SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);
if (accessors == null) {
accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, targetMethod, this);
this.synthetics[SourceTypeBinding.METHOD_EMUL].put(inheritedMethodToBridge, accessors = new SyntheticMethodBinding[2]);
accessors[1] = accessMethod;
} else {
if ((accessMethod = accessors[1]) == null) {
accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, targetMethod, this);
accessors[1] = accessMethod;
}
}
return accessMethod;
}
public int kind() {
if (this.typeVariables != Binding.NO_TYPE_VARIABLES) return Binding.GENERIC_TYPE;
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)) 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)
{
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;
}
if (this.nextType!=null)
{
FieldBinding[] moreFields=this.nextType.fields();
FieldBinding[] combinedFields=new FieldBinding[this.fields.length+moreFields.length];
System.arraycopy(this.fields, 0, combinedFields, 0, this.fields.length);
System.arraycopy(moreFields, 0, combinedFields, this.fields.length, moreFields.length);
return combinedFields;
}
else
return this.fields;
}
/**
* @see org.eclipse.wst.jsdt.internal.compiler.lookup.TypeBinding#genericTypeSignature()
*/
public char[] genericTypeSignature() {
if (this.genericReferenceTypeSignature == null)
this.genericReferenceTypeSignature = computeGenericTypeSignature(this.typeVariables);
return this.genericReferenceTypeSignature;
}
/**
* <param1 ... paramN>superclass superinterface1 ... superinterfaceN
* <T:LY<TT;>;U:Ljava/lang/Object;V::Ljava/lang/Runnable;:Ljava/lang/Cloneable;:Ljava/util/Map;>Ljava/lang/Exception;Ljava/lang/Runnable;
*/
public char[] genericSignature() {
StringBuffer sig = null;
if (this.typeVariables != Binding.NO_TYPE_VARIABLES) {
sig = new StringBuffer(10);
sig.append('<');
for (int i = 0, length = this.typeVariables.length; i < length; i++)
sig.append(this.typeVariables[i].genericSignature());
sig.append('>');
} else {
// could still need a signature if any of supertypes is parameterized
noSignature: if (this.superclass == null || !this.superclass.isParameterizedType()) {
for (int i = 0, length = this.superInterfaces.length; i < length; i++)
if (this.superInterfaces[i].isParameterizedType())
break noSignature;
return null;
}
sig = new StringBuffer(10);
}
if (this.superclass != null)
sig.append(this.superclass.genericTypeSignature());
else // interface scenario only (as Object cannot be generic) - 65953
sig.append(this.scope.getJavaLangObject().genericTypeSignature());
for (int i = 0, length = this.superInterfaces.length; i < length; i++)
sig.append(this.superInterfaces[i].genericTypeSignature());
return sig.toString().toCharArray();
}
/**
* Compute the tagbits for standard annotations. For source types, these could require
* lazily resolving corresponding annotation nodes, in case of forward references.
* @see org.eclipse.wst.jsdt.internal.compiler.lookup.Binding#getAnnotationTagBits()
*/
public long getAnnotationTagBits() {
// if ((this.tagBits & TagBits.AnnotationResolved) == 0 && this.scope != null) {
// TypeDeclaration typeDecl = this.classScope.referenceContext;
// boolean old = typeDecl.staticInitializerScope.insideTypeAnnotation;
// try {
// typeDecl.staticInitializerScope.insideTypeAnnotation = true;
// ASTNode.resolveAnnotations(typeDecl.staticInitializerScope, typeDecl.annotations, this);
// } finally {
// typeDecl.staticInitializerScope.insideTypeAnnotation = old;
// }
// if ((this.tagBits & TagBits.AnnotationDeprecated) != 0)
// this.modifiers |= ClassFileConstants.AccDeprecated;
// }
return this.tagBits;
}
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) {
MethodBinding exactConstructor = getExactConstructor0(argumentTypes);
if (exactConstructor==null && this.nextType!=null)
exactConstructor=this.nextType.getExactConstructor(argumentTypes);
return exactConstructor;
}
// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
private MethodBinding getExactConstructor0(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 {
// 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) {
MethodBinding exactMethod = getExactMethod0(selector, argumentTypes, refScope);
if (exactMethod==null && this.nextType!=null)
exactMethod=this.nextType.getExactMethod(selector, argumentTypes, refScope);
return exactMethod;
}
//NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
//searches up the hierarchy as long as no potential (but not exact) match was found.
private MethodBinding getExactMethod0(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 {
// 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) {
FieldBinding field = getField0(fieldName, needResolve);
if (field==null && this.nextType!=null)
field=this.nextType.getField(fieldName, needResolve);
return field;
}
//NOTE: the type of a field of a source type is resolved when needed
private FieldBinding getField0(char[] fieldName, boolean needResolve) {
if ((this.tagBits & TagBits.AreFieldsComplete) != 0)
return ReferenceBinding.binarySearch(fieldName, this.fields);
// 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) {
MethodBinding[] meths = getMethods0(selector);
if (this.nextType==null)
return meths;
MethodBinding[] moreMethods=this.nextType.getMethods(selector);
MethodBinding[] combinedMethods=new MethodBinding[meths.length+moreMethods.length];
System.arraycopy( meths, 0, combinedMethods, 0, meths.length);
System.arraycopy(moreMethods, 0, combinedMethods, meths.length, moreMethods.length);
return combinedMethods;
}
// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
private MethodBinding[] getMethods0(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;
}
}
// 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.scope.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;
}
/* Answer the synthetic field for <actualOuterLocalVariable>
* or null if one does not exist.
*/
public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null;
return (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable);
}
/* Answer the synthetic field for <targetEnclosingType>
* or null if one does not exist.
*/
public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) {
if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null;
FieldBinding field = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(targetEnclosingType);
if (field != null) return field;
// type compatibility : to handle cases such as
// class T { class M{}}
// class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N().
if (!onlyExactMatch){
Iterator accessFields = this.synthetics[SourceTypeBinding.FIELD_EMUL].values().iterator();
while (accessFields.hasNext()) {
field = (FieldBinding) accessFields.next();
if (CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX, field.name)
&& field.type.findSuperTypeWithSameErasure(targetEnclosingType) != null)
return field;
}
}
return null;
}
/*
* Answer the bridge method associated for an inherited methods or null if one does not exist
*/
public SyntheticMethodBinding getSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) {
if (this.synthetics == null) return null;
if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) return null;
SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);
if (accessors == null) return null;
return accessors[1];
}
/**
* @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;
switch(otherType.kind()) {
case Binding.WILDCARD_TYPE :
return ((WildcardBinding) otherType).boundCheck(this);
case Binding.PARAMETERIZED_TYPE :
if ((otherType.tagBits & TagBits.HasDirectWildcard) == 0 && (!this.isMemberType() || !otherType.isMemberType()))
return false; // should have been identical
ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;
if (this != otherParamType.genericType())
return false;
if (!isStatic()) { // static member types do not compare their enclosing
ReferenceBinding enclosing = enclosingType();
if (enclosing != null) {
ReferenceBinding otherEnclosing = otherParamType.enclosingType();
if (otherEnclosing == null) return false;
if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {
if (enclosing != otherEnclosing) return false;
} else {
if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;
}
}
}
int length = this.typeVariables == null ? 0 : this.typeVariables.length;
TypeBinding[] otherArguments = otherParamType.arguments;
int otherLength = otherArguments == null ? 0 : otherArguments.length;
if (otherLength != length)
return false;
for (int i = 0; i < length; i++)
if (!this.typeVariables[i].isTypeArgumentContainedBy(otherArguments[i]))
return false;
return true;
case Binding.RAW_TYPE :
return otherType.erasure() == this;
}
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 FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] == null)
this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] = new HashMap(5);
Hashtable fieldMap = (Hashtable) this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].get(targetField);
if (fieldMap == null) {
fieldMap = new Hashtable(5);
this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].put(targetField, fieldMap);
}
FieldBinding updatedField = (FieldBinding) fieldMap.get(newDeclaringClass);
if (updatedField == null){
updatedField = new FieldBinding(targetField, newDeclaringClass);
fieldMap.put(newDeclaringClass, updatedField);
}
return updatedField;
}
public MethodBinding getUpdatedMethodBinding(MethodBinding targetMethod, ReferenceBinding newDeclaringClass) {
if (this.synthetics == null)
this.synthetics = new HashMap[4];
if (this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] == null)
this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] = new HashMap(5);
Hashtable methodMap = (Hashtable) this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].get(targetMethod);
if (methodMap == null) {
methodMap = new Hashtable(5);
this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].put(targetMethod, methodMap);
}
MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass);
if (updatedMethod == null){
updatedMethod = new MethodBinding(targetMethod, newDeclaringClass);
updatedMethod.createFunctionTypeBinding(scope);
methodMap.put(newDeclaringClass, updatedMethod);
}
return updatedMethod;
}
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) {
// 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.scope!=null && this.scope.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.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);
}
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);
}
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 MethodBinding[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 MethodBinding[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;
// FieldDeclaration[] fieldDecls = this.classScope.referenceContext.fields;
// for (int f = 0, length = fieldDecls.length; f < length; f++) {
// if (fieldDecls[f].binding != field)
// continue;
//
// MethodScope initializationScope = field.isStatic()
// ? this.classScope.referenceContext.staticInitializerScope
// : this.classScope.referenceContext.initializerScope;
// FieldBinding previousField = initializationScope.initializedField;
// try {
// initializationScope.initializedField = field;
// FieldDeclaration fieldDecl = fieldDecls[f];
// TypeBinding fieldType =
// fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT
// ? initializationScope.environment().convertToRawType(this) // enum constant is implicitly of declaring enum type
// : fieldDecl.type.resolveType(initializationScope, true /* check bounds*/);
// field.type = fieldType;
// field.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;
// if (fieldType == null) {
// fieldDecl.binding = null;
// return null;
// }
// if (fieldType == TypeBinding.VOID) {
// this.scope.problemReporter().variableTypeCannotBeVoid(fieldDecl);
// fieldDecl.binding = null;
// return null;
// }
// if (fieldType.isArrayType() && ((ArrayBinding) fieldType).leafComponentType == TypeBinding.VOID) {
// this.scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecl);
// fieldDecl.binding = null;
// return null;
// }
// TypeBinding leafType = fieldType.leafComponentType();
// if (leafType instanceof ReferenceBinding && (((ReferenceBinding)leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0) {
// field.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
// }
// } finally {
// initializationScope.initializedField = previousField;
// }
// return field;
// }
// return null; // should never reach this point
}
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;
AbstractMethodDeclaration methodDecl = method.sourceMethod();
if (methodDecl == null) return null; // method could not be resolved in previous iteration
TypeParameter[] typeParameters = methodDecl.typeParameters();
if (JavaScriptCore.IS_ECMASCRIPT4)
{
if (typeParameters != null) {
methodDecl.scope.connectTypeVariables(typeParameters, true);
// Perform deferred bound checks for type variables (only done after type variable hierarchy is connected)
for (int i = 0, paramLength = typeParameters.length; i < paramLength; i++)
typeParameters[i].checkBounds(methodDecl.scope);
}
TypeReference[] exceptionTypes = methodDecl.thrownExceptions;
if (exceptionTypes != null) {
int size = exceptionTypes.length;
method.thrownExceptions = new ReferenceBinding[size];
int count = 0;
ReferenceBinding resolvedExceptionType;
for (int i = 0; i < size; i++) {
resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].resolveType(methodDecl.scope, true /* check bounds*/);
if (resolvedExceptionType == null)
continue;
if (resolvedExceptionType.isBoundParameterizedType()) {
methodDecl.scope.problemReporter().invalidParameterizedExceptionType(resolvedExceptionType, exceptionTypes[i]);
continue;
}
if (resolvedExceptionType.findSuperTypeErasingTo(TypeIds.T_JavaLangThrowable, true) == null) {
methodDecl.scope.problemReporter().cannotThrowType(exceptionTypes[i], resolvedExceptionType);
continue;
}
if ((resolvedExceptionType.modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
method.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
method.thrownExceptions[count++] = resolvedExceptionType;
}
if (count < size)
System.arraycopy(method.thrownExceptions, 0, method.thrownExceptions = new ReferenceBinding[count], 0, count);
}
}
boolean foundArgProblem = false;
Argument[] arguments = methodDecl.arguments;
if (arguments != null) {
int size = arguments.length;
method.parameters = Binding.NO_PARAMETERS;
TypeBinding[] newParameters = new TypeBinding[size];
for (int i = 0; i < size; i++) {
Argument arg = arguments[i];
TypeBinding parameterType = TypeBinding.UNKNOWN;
if (arg.type!=null) parameterType = arg.type.resolveType(methodDecl.scope, true /* check bounds*/) ;
else if (arg.inferredType!=null) parameterType = arg.inferredType.resolveType(methodDecl.scope, arg);
if (parameterType == null) {
// foundArgProblem = true;
parameterType=TypeBinding.ANY;
}
// else
if (parameterType == TypeBinding.VOID) {
methodDecl.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;
arg.binding = new LocalVariableBinding(arg, parameterType, arg.modifiers, true);
}
}
// only assign parameters if no problems are found
if (!foundArgProblem)
method.parameters = newParameters;
}
boolean foundReturnTypeProblem = false;
if (!method.isConstructor()) {
TypeReference returnType = methodDecl instanceof MethodDeclaration
? ((MethodDeclaration) methodDecl).returnType
: null;
if (returnType == null && !(methodDecl instanceof MethodDeclaration)) {
methodDecl.scope.problemReporter().missingReturnType(methodDecl);
method.returnType = null;
foundReturnTypeProblem = true;
} else {
TypeBinding methodType = (returnType!=null )? returnType.resolveType(methodDecl.scope, true /* check bounds*/) : null;
if (methodType==null)
methodType=(methodDecl.inferredType!=null)?methodDecl.inferredType.resolveType(methodDecl.scope, methodDecl):TypeBinding.UNKNOWN;
if (methodType == null) {
foundReturnTypeProblem = true;
} else if (methodType.isArrayType() && ((ArrayBinding) methodType).leafComponentType == TypeBinding.VOID) {
methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray((MethodDeclaration) methodDecl);
foundReturnTypeProblem = true;
} else {
method.returnType = methodType;
TypeBinding leafType = methodType.leafComponentType();
if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
method.modifiers |= ExtraCompilerModifiers.AccGenericSignature;
}
}
}
if (foundArgProblem) {
methodDecl.binding = null;
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)
if (JavaScriptCore.IS_ECMASCRIPT4)
{
if (typeParameters != null)
for (int i = 0, length = typeParameters.length; i < length; i++)
typeParameters[i].binding = null;
}
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 int sourceEnd() {
if (this.classScope.referenceContext!=null)
return this.classScope.referenceContext.sourceEnd;
else
return this.classScope.inferredType.sourceEnd;
}
public int sourceStart() {
if (this.classScope.referenceContext!=null)
return this.classScope.referenceContext.sourceStart;
else
return this.classScope.inferredType.sourceStart;
}
SimpleLookupTable storedAnnotations(boolean forceInitialize) {
if (forceInitialize && this.storedAnnotations == null && this.scope != null) { // scope null when no annotation cached, and type got processed fully (159631)
this.scope.referenceCompilationUnit().compilationResult.hasAnnotations = true;
if (!this.scope.environment().globalOptions.storeAnnotations)
return null; // not supported during this compile
this.storedAnnotations = new SimpleLookupTable(3);
}
return this.storedAnnotations;
}
public ReferenceBinding superclass() {
if (this.nextType==null)
return this.superclass;
if (this.superclass!=null && this.superclass.id!=TypeIds.T_JavaLangObject)
return this.superclass;
return this.nextType.superclass();
}
public ReferenceBinding[] superInterfaces() {
return this.superInterfaces;
}
// TODO (philippe) could be a performance issue since some senders are building the list just to count them
public SyntheticMethodBinding[] syntheticMethods() {
if (this.synthetics == null || this.synthetics[SourceTypeBinding.METHOD_EMUL] == null || this.synthetics[SourceTypeBinding.METHOD_EMUL].size() == 0) return null;
// difficult to compute size up front because of the embedded arrays so assume there is only 1
int index = 0;
SyntheticMethodBinding[] bindings = new SyntheticMethodBinding[1];
Iterator fieldsOrMethods = this.synthetics[SourceTypeBinding.METHOD_EMUL].keySet().iterator();
while (fieldsOrMethods.hasNext()) {
Object fieldOrMethod = fieldsOrMethods.next();
if (fieldOrMethod instanceof MethodBinding) {
SyntheticMethodBinding[] methodAccessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(fieldOrMethod);
int numberOfAccessors = 0;
if (methodAccessors[0] != null) numberOfAccessors++;
if (methodAccessors[1] != null) numberOfAccessors++;
if (index + numberOfAccessors > bindings.length)
System.arraycopy(bindings, 0, (bindings = new SyntheticMethodBinding[index + numberOfAccessors]), 0, index);
if (methodAccessors[0] != null)
bindings[index++] = methodAccessors[0]; // super access
if (methodAccessors[1] != null)
bindings[index++] = methodAccessors[1]; // normal access or bridge
} else {
SyntheticMethodBinding[] fieldAccessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(fieldOrMethod);
int numberOfAccessors = 0;
if (fieldAccessors[0] != null) numberOfAccessors++;
if (fieldAccessors[1] != null) numberOfAccessors++;
if (index + numberOfAccessors > bindings.length)
System.arraycopy(bindings, 0, (bindings = new SyntheticMethodBinding[index + numberOfAccessors]), 0, index);
if (fieldAccessors[0] != null)
bindings[index++] = fieldAccessors[0]; // read access
if (fieldAccessors[1] != null)
bindings[index++] = fieldAccessors[1]; // write access
}
}
// sort them in according to their own indexes
int length;
SyntheticMethodBinding[] sortedBindings = new SyntheticMethodBinding[length = bindings.length];
for (int i = 0; i < length; i++){
SyntheticMethodBinding binding = bindings[i];
sortedBindings[binding.index] = binding;
}
return sortedBindings;
}
/**
* Answer the collection of synthetic fields to append into the classfile
*/
public FieldBinding[] syntheticFields() {
if (this.synthetics == null) return null;
int fieldSize = this.synthetics[SourceTypeBinding.FIELD_EMUL] == null ? 0 : this.synthetics[SourceTypeBinding.FIELD_EMUL].size();
int literalSize = this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] == null ? 0 :this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size();
int totalSize = fieldSize + literalSize;
if (totalSize == 0) return null;
FieldBinding[] bindings = new FieldBinding[totalSize];
// add innerclass synthetics
if (this.synthetics[SourceTypeBinding.FIELD_EMUL] != null){
Iterator elements = this.synthetics[SourceTypeBinding.FIELD_EMUL].values().iterator();
for (int i = 0; i < fieldSize; i++) {
SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.next();
bindings[synthBinding.index] = synthBinding;
}
}
// add class literal synthetics
if (this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] != null){
Iterator elements = this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].values().iterator();
for (int i = 0; i < literalSize; i++) {
SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.next();
bindings[fieldSize+synthBinding.index] = synthBinding;
}
}
return bindings;
}
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) {
if (this.classScope==null)
return null;
InferredType inferredType=this.classScope.inferredType;
InferredMethod inferredMethod = inferredType.findMethod(binding.selector, null);
if (inferredMethod!=null)
return (AbstractMethodDeclaration) inferredMethod.getFunctionDeclaration();
// AbstractMethodDeclaration[] methods = classScope.referenceContext.methods;
// for (int i = methods.length; --i >= 0;)
// if (binding == methods[i].binding)
// return methods[i];
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;
// 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)
{
if (binding==this)
return true;
if (this.nextType!=null)
return this.nextType.contains(binding);
return false;
}
public void addNextType(SourceTypeBinding type) {
SourceTypeBinding binding=this;
while (binding.nextType!=null)
binding=binding.nextType;
binding.nextType=type;
}
}