X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Flookup%2FSourceTypeBinding.java;fp=src%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Flookup%2FSourceTypeBinding.java;h=e791f1e03e3cc5919f751b404075981b7c9274a4;hb=040fa5af2cd00017cf3575950cdaade34a6d7f6c;hp=0000000000000000000000000000000000000000;hpb=a580fb8376d315d05e4d6bfdff9ff1101a151cd6;p=org.ibex.tool.git diff --git a/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java new file mode 100644 index 0000000..e791f1e --- /dev/null +++ b/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java @@ -0,0 +1,1068 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Common Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/cpl-v10.html + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.jdt.internal.compiler.lookup; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.eclipse.jdt.core.compiler.CharOperation; +import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.Argument; +import org.eclipse.jdt.internal.compiler.ast.AssertStatement; +import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration; +import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration; +import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration; +import org.eclipse.jdt.internal.compiler.ast.TypeReference; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; +import org.eclipse.jdt.internal.compiler.impl.Constant; +import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; + +public class SourceTypeBinding extends ReferenceBinding { + public ReferenceBinding superclass; + public ReferenceBinding[] superInterfaces; + public FieldBinding[] fields; + public MethodBinding[] methods; + public ReferenceBinding[] memberTypes; + + public ClassScope scope; + + // Synthetics are separated into 4 categories: methods, super methods, fields, class literals and changed declaring type bindings + 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; + + Hashtable[] synthetics; + +public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) { + this.compoundName = compoundName; + this.fPackage = fPackage; + this.fileName = scope.referenceCompilationUnit().getFileName(); + this.modifiers = scope.referenceContext.modifiers; + this.sourceName = scope.referenceContext.name; + this.scope = scope; + + // expect the fields & methods to be initialized correctly later + this.fields = NoFields; + this.methods = NoMethods; + + computeId(); +} +private void addDefaultAbstractMethod(MethodBinding abstractMethod) { + MethodBinding defaultAbstract = new MethodBinding( + abstractMethod.modifiers | AccDefaultAbstract, + abstractMethod.selector, + abstractMethod.returnType, + abstractMethod.parameters, + abstractMethod.thrownExceptions, + this); + + MethodBinding[] temp = new MethodBinding[methods.length + 1]; + System.arraycopy(methods, 0, temp, 0, methods.length); + temp[methods.length] = defaultAbstract; + methods = temp; +} +public void addDefaultAbstractMethods() { + if ((tagBits & KnowsDefaultAbstractMethods) != 0) return; + + tagBits |= KnowsDefaultAbstractMethods; + + if (isClass() && isAbstract()) { + if (fPackage.environment.options.targetJDK >= ClassFileConstants.JDK1_2) return; // no longer added for post 1.2 targets + + ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; + int lastPosition = 0; + interfacesToVisit[lastPosition] = superInterfaces(); + + for (int i = 0; i <= lastPosition; i++) { + ReferenceBinding[] interfaces = interfacesToVisit[i]; + for (int j = 0, length = interfaces.length; j < length; j++) { + ReferenceBinding superType = interfaces[j]; + if (superType.isValidBinding()) { + MethodBinding[] superMethods = superType.methods(); + for (int m = superMethods.length; --m >= 0;) { + MethodBinding method = superMethods[m]; + if (!implementsMethod(method)) + addDefaultAbstractMethod(method); + } + + ReferenceBinding[] itsInterfaces = superType.superInterfaces(); + if (itsInterfaces != NoSuperInterfaces) { + if (++lastPosition == interfacesToVisit.length) + System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition); + interfacesToVisit[lastPosition] = itsInterfaces; + } + } + } + } + } +} +/* Add a new synthetic field for . +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD_EMUL] == null) { + synthetics[FIELD_EMUL] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get(actualOuterLocalVariable); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + CharOperation.concat(SyntheticArgumentBinding.OuterLocalPrefix, actualOuterLocalVariable.name), + actualOuterLocalVariable.type, + AccPrivate | AccFinal | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[FIELD_EMUL].size()); + synthetics[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 = scope.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( + SyntheticArgumentBinding.OuterLocalPrefix, + actualOuterLocalVariable.name, + ("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$ + needRecheck = true; + break; + } + } + } + } while (needRecheck); + return synthField; +} +/* Add a new synthetic field for . +* Answer the new field or the existing field if one already existed. +*/ + +public FieldBinding addSyntheticField(ReferenceBinding enclosingType) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD_EMUL] == null) { + synthetics[FIELD_EMUL] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get(enclosingType); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + CharOperation.concat( + SyntheticArgumentBinding.EnclosingInstancePrefix, + String.valueOf(enclosingType.depth()).toCharArray()), + enclosingType, + AccDefault | AccFinal | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[FIELD_EMUL].size()); + synthetics[FIELD_EMUL].put(enclosingType, 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 = scope.referenceContext; + for (int i = 0, max = typeDecl.fields.length; i < max; i++) { + FieldDeclaration fieldDecl = typeDecl.fields[i]; + if (fieldDecl.binding == existingField) { + scope.problemReporter().duplicateFieldInType(this, fieldDecl); + break; + } + } + } + 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 addSyntheticField(TypeBinding targetType, BlockScope blockScope) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[CLASS_LITERAL_EMUL] == null) { + synthetics[CLASS_LITERAL_EMUL] = new Hashtable(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) synthetics[CLASS_LITERAL_EMUL].get(targetType); + if (synthField == null) { + synthField = new SyntheticFieldBinding( + ("class$" + synthetics[CLASS_LITERAL_EMUL].size()).toCharArray(), //$NON-NLS-1$ + blockScope.getJavaLangClass(), + AccDefault | AccStatic | AccSynthetic, + this, + Constant.NotAConstant, + synthetics[CLASS_LITERAL_EMUL].size()); + synthetics[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 addSyntheticField(AssertStatement assertStatement, BlockScope blockScope) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[FIELD_EMUL] == null) { + synthetics[FIELD_EMUL] = new Hashtable(5); + } + + FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get("assertionEmulation"); //$NON-NLS-1$ + if (synthField == null) { + synthField = new SyntheticFieldBinding( + "$assertionsDisabled".toCharArray(), //$NON-NLS-1$ + BooleanBinding, + AccDefault | AccStatic | AccSynthetic | AccFinal, + this, + Constant.NotAConstant, + synthetics[FIELD_EMUL].size()); + synthetics[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 = scope.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( + "$assertionsDisabled".toCharArray(), //$NON-NLS-1$ + ("_" + 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 . + Answer the new method or the existing method if one already existed. +*/ + +public SyntheticAccessMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[METHOD_EMUL] == null) { + synthetics[METHOD_EMUL] = new Hashtable(5); + } + + SyntheticAccessMethodBinding accessMethod = null; + SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(targetField); + if (accessors == null) { + accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this); + synthetics[METHOD_EMUL].put(targetField, accessors = new SyntheticAccessMethodBinding[2]); + accessors[isReadAccess ? 0 : 1] = accessMethod; + } else { + if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) { + accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this); + accessors[isReadAccess ? 0 : 1] = accessMethod; + } + } + return accessMethod; +} +/* Add a new synthetic access method for access to . + * 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 SyntheticAccessMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) { + + if (synthetics == null) { + synthetics = new Hashtable[4]; + } + if (synthetics[METHOD_EMUL] == null) { + synthetics[METHOD_EMUL] = new Hashtable(5); + } + + SyntheticAccessMethodBinding accessMethod = null; + SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(targetMethod); + if (accessors == null) { + accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this); + synthetics[METHOD_EMUL].put(targetMethod, accessors = new SyntheticAccessMethodBinding[2]); + accessors[isSuperAccess ? 0 : 1] = accessMethod; + } else { + if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) { + accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this); + accessors[isSuperAccess ? 0 : 1] = accessMethod; + } + } + return accessMethod; +} + +public FieldBinding[] availableFields() { + return fields(); +} +public MethodBinding[] availableMethods() { + return methods(); +} +void faultInTypesForFieldsAndMethods() { + fields(); + methods(); + + for (int i = 0, length = memberTypes.length; i < length; i++) + ((SourceTypeBinding) memberTypes[i]).faultInTypesForFieldsAndMethods(); +} +// NOTE: the type of each field of a source type is resolved when needed + +public FieldBinding[] fields() { + + try { + int failed = 0; + for (int f = 0, max = fields.length; f < max; f++) { + if (resolveTypeFor(fields[f]) == null) { + fields[f] = null; + failed++; + } + } + if (failed > 0) { + int newSize = fields.length - failed; + if (newSize == 0) + return fields = NoFields; + + FieldBinding[] newFields = new FieldBinding[newSize]; + for (int i = 0, n = 0, max = fields.length; i < max; i++) + if (fields[i] != null) + newFields[n++] = fields[i]; + fields = newFields; + } + } catch(AbortCompilation e){ + // ensure null fields are removed + FieldBinding[] newFields = null; + int count = 0; + for (int i = 0, max = fields.length; i < max; i++){ + FieldBinding field = fields[i]; + if (field == null && newFields == null){ + System.arraycopy(fields, 0, newFields = new FieldBinding[max], 0, i); + } else if (newFields != null && field != null) { + newFields[count++] = field; + } + } + if (newFields != null){ + System.arraycopy(newFields, 0, fields = new FieldBinding[count], 0, count); + } + throw e; + } + return fields; +} +public MethodBinding[] getDefaultAbstractMethods() { + int count = 0; + for (int i = methods.length; --i >= 0;) + if (methods[i].isDefaultAbstract()) + count++; + if (count == 0) return NoMethods; + + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int i = methods.length; --i >= 0;) + if (methods[i].isDefaultAbstract()) + result[count++] = methods[i]; + return result; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed + +public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) { + TypeBinding[] toMatch = method.parameters; + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } else { + MethodBinding[] constructors = getMethods(ConstructorDeclaration.ConstantPoolName); // takes care of duplicates & default abstract methods + nextConstructor : for (int c = constructors.length; --c >= 0;) { + MethodBinding constructor = constructors[c]; + TypeBinding[] toMatch = constructor.parameters; + if (toMatch.length == argCount) { + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextConstructor; + return constructor; + } + } + } + return null; +} +// 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. + +public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) { + int argCount = argumentTypes.length; + int selectorLength = selector.length; + boolean foundNothing = true; + + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + nextMethod : for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + 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 p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + } else { + MethodBinding[] matchingMethods = getMethods(selector); // takes care of duplicates & default abstract methods + foundNothing = matchingMethods == NoMethods; + nextMethod : for (int m = matchingMethods.length; --m >= 0;) { + MethodBinding method = matchingMethods[m]; + TypeBinding[] toMatch = method.parameters; + if (toMatch.length == argCount) { + for (int p = 0; p < argCount; p++) + if (toMatch[p] != argumentTypes[p]) + continue nextMethod; + return method; + } + } + } + + if (foundNothing) { + if (isInterface()) { + if (superInterfaces.length == 1) + return superInterfaces[0].getExactMethod(selector, argumentTypes); + } else if (superclass != null) { + return superclass.getExactMethod(selector, argumentTypes); + } + } + return null; +} +// NOTE: the type of a field of a source type is resolved when needed + +public FieldBinding getField(char[] fieldName, boolean needResolve) { + // always resolve anyway on source types + int fieldLength = fieldName.length; + for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; + if (field.name.length == fieldLength && CharOperation.equals(field.name, fieldName)) { + if (resolveTypeFor(field) != null) + return field; + + int newSize = fields.length - 1; + if (newSize == 0) { + fields = NoFields; + } else { + FieldBinding[] newFields = new FieldBinding[newSize]; + System.arraycopy(fields, 0, newFields, 0, f); + System.arraycopy(fields, f + 1, newFields, f, newSize - f); + fields = newFields; + } + return null; + } + } + return null; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed + +public MethodBinding[] getMethods(char[] selector) { + // handle forward references to potential default abstract methods + addDefaultAbstractMethods(); + + try{ + int count = 0; + int lastIndex = -1; + int selectorLength = selector.length; + if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + count++; + lastIndex = m; + } + } + } else { + boolean foundProblem = false; + int failed = 0; + for (int m = 0, length = methods.length; m < length; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + if (resolveTypesFor(method) == null) { + foundProblem = true; + methods[m] = null; // unable to resolve parameters + failed++; + } else if (method.returnType == null) { + foundProblem = true; + } else { + count++; + lastIndex = m; + } + } + } + + if (foundProblem || count > 1) { + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method != null && method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) { + AbstractMethodDeclaration methodDecl = null; + for (int i = 0; i < m; i++) { + MethodBinding method2 = methods[i]; + if (method2 != null && CharOperation.equals(method.selector, method2.selector)) { + if (method.areParametersEqual(method2)) { + if (methodDecl == null) { + methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost + scope.problemReporter().duplicateMethodInType(this, methodDecl); + methodDecl.binding = null; + methods[m] = null; + failed++; + } + scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod()); + method2.sourceMethod().binding = null; + methods[i] = null; + failed++; + } + } + } + if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions + method.sourceMethod().binding = null; + methods[m] = null; + failed++; + } + } + } + + if (failed > 0) { + int newSize = methods.length - failed; + if (newSize == 0) + return methods = NoMethods; + + MethodBinding[] newMethods = new MethodBinding[newSize]; + for (int i = 0, n = 0, max = methods.length; i < max; i++) + if (methods[i] != null) + newMethods[n++] = methods[i]; + methods = newMethods; + return getMethods(selector); // try again now that the problem methods have been removed + } + } + } + if (count == 1) + return new MethodBinding[] {methods[lastIndex]}; + if (count > 1) { + MethodBinding[] result = new MethodBinding[count]; + count = 0; + for (int m = 0; m <= lastIndex; m++) { + MethodBinding method = methods[m]; + if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) + result[count++] = method; + } + return result; + } + } catch(AbortCompilation e){ + // ensure null methods are removed + MethodBinding[] newMethods = null; + int count = 0; + for (int i = 0, max = methods.length; i < max; i++){ + MethodBinding method = methods[i]; + if (method == null && newMethods == null){ + System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i); + } else if (newMethods != null && method != null) { + newMethods[count++] = method; + } + } + if (newMethods != null){ + System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count); + } + modifiers ^= AccUnresolved; + throw e; + } + return NoMethods; +} +/* Answer the synthetic field for +* or null if one does not exist. +*/ + +public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) { + + if (synthetics == null || synthetics[FIELD_EMUL] == null) return null; + return (FieldBinding) synthetics[FIELD_EMUL].get(actualOuterLocalVariable); +} +public ReferenceBinding[] memberTypes() { + return this.memberTypes; +} +public FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) { + + if (this.synthetics == null) { + this.synthetics = new Hashtable[4]; + } + if (this.synthetics[RECEIVER_TYPE_EMUL] == null) { + this.synthetics[RECEIVER_TYPE_EMUL] = new Hashtable(5); + } + + Hashtable fieldMap = (Hashtable) this.synthetics[RECEIVER_TYPE_EMUL].get(targetField); + if (fieldMap == null) { + fieldMap = new Hashtable(5); + this.synthetics[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 Hashtable[4]; + } + if (this.synthetics[RECEIVER_TYPE_EMUL] == null) { + this.synthetics[RECEIVER_TYPE_EMUL] = new Hashtable(5); + } + + + Hashtable methodMap = (Hashtable) synthetics[RECEIVER_TYPE_EMUL].get(targetMethod); + if (methodMap == null) { + methodMap = new Hashtable(5); + this.synthetics[RECEIVER_TYPE_EMUL].put(targetMethod, methodMap); + } + MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass); + if (updatedMethod == null){ + updatedMethod = new MethodBinding(targetMethod, newDeclaringClass); + methodMap.put(newDeclaringClass, updatedMethod); + } + return updatedMethod; +} +public boolean hasMemberTypes() { + return this.memberTypes.length > 0; +} +// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed +public MethodBinding[] methods() { + try { + if ((modifiers & AccUnresolved) == 0) + return methods; + + int failed = 0; + for (int m = 0, max = methods.length; m < max; m++) { + if (resolveTypesFor(methods[m]) == null) { + methods[m] = null; // unable to resolve parameters + failed++; + } + } + + for (int m = methods.length; --m >= 0;) { + MethodBinding method = methods[m]; + if (method != null) { + AbstractMethodDeclaration methodDecl = null; + for (int i = 0; i < m; i++) { + MethodBinding method2 = methods[i]; + if (method2 != null && CharOperation.equals(method.selector, method2.selector)) { + if (method.areParametersEqual(method2)) { + if (methodDecl == null) { + methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost + scope.problemReporter().duplicateMethodInType(this, methodDecl); + methodDecl.binding = null; + methods[m] = null; + failed++; + } + scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod()); + method2.sourceMethod().binding = null; + methods[i] = null; + failed++; + } + } + } + if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions + method.sourceMethod().binding = null; + methods[m] = null; + failed++; + } + } + } + + if (failed > 0) { + int newSize = methods.length - failed; + if (newSize == 0) { + methods = NoMethods; + } else { + MethodBinding[] newMethods = new MethodBinding[newSize]; + for (int m = 0, n = 0, max = methods.length; m < max; m++) + if (methods[m] != null) + newMethods[n++] = methods[m]; + methods = newMethods; + } + } + + // handle forward references to potential default abstract methods + addDefaultAbstractMethods(); + } catch(AbortCompilation e){ + // ensure null methods are removed + MethodBinding[] newMethods = null; + int count = 0; + for (int i = 0, max = methods.length; i < max; i++){ + MethodBinding method = methods[i]; + if (method == null && newMethods == null){ + System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i); + } else if (newMethods != null && method != null) { + newMethods[count++] = method; + } + } + if (newMethods != null){ + System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count); + } + modifiers ^= AccUnresolved; + throw e; + } + modifiers ^= AccUnresolved; + return methods; +} +private FieldBinding resolveTypeFor(FieldBinding field) { + if ((field.modifiers & AccUnresolved) == 0) + return field; + + FieldDeclaration[] fieldDecls = scope.referenceContext.fields; + for (int f = 0, length = fieldDecls.length; f < length; f++) { + if (fieldDecls[f].binding != field) + continue; + + field.type = fieldDecls[f].getTypeBinding(scope); + field.modifiers ^= AccUnresolved; + if (!field.type.isValidBinding()) { + scope.problemReporter().fieldTypeProblem(this, fieldDecls[f], field.type); + //scope.problemReporter().invalidType(fieldDecls[f].type, field.type); + fieldDecls[f].binding = null; + return null; + } + if (field.type == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoid(fieldDecls[f]); + fieldDecls[f].binding = null; + return null; + } + if (field.type.isArrayType() && ((ArrayBinding) field.type).leafComponentType == VoidBinding) { + scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecls[f]); + fieldDecls[f].binding = null; + return null; + } + return field; + } + return null; // should never reach this point +} +private MethodBinding resolveTypesFor(MethodBinding method) { + if ((method.modifiers & AccUnresolved) == 0) + return method; + + AbstractMethodDeclaration methodDecl = method.sourceMethod(); + TypeReference[] exceptionTypes = methodDecl.thrownExceptions; + if (exceptionTypes != null) { + int size = exceptionTypes.length; + method.thrownExceptions = new ReferenceBinding[size]; + ReferenceBinding throwable = scope.getJavaLangThrowable(); + int count = 0; + ReferenceBinding resolvedExceptionType; + for (int i = 0; i < size; i++) { + resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].getTypeBinding(scope); + if (!resolvedExceptionType.isValidBinding()) { + methodDecl.scope.problemReporter().exceptionTypeProblem(this, methodDecl, exceptionTypes[i], resolvedExceptionType); + //methodDecl.scope.problemReporter().invalidType(exceptionTypes[i], resolvedExceptionType); + continue; + } + if (throwable != resolvedExceptionType && !throwable.isSuperclassOf(resolvedExceptionType)) { + methodDecl.scope.problemReporter().cannotThrowType(this, methodDecl, exceptionTypes[i], resolvedExceptionType); + continue; + } + 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 = new TypeBinding[size]; + for (int i = 0; i < size; i++) { + Argument arg = arguments[i]; + method.parameters[i] = arg.type.getTypeBinding(scope); + if (!method.parameters[i].isValidBinding()) { + methodDecl.scope.problemReporter().argumentTypeProblem(this, methodDecl, arg, method.parameters[i]); + //methodDecl.scope.problemReporter().invalidType(arg, method.parameters[i]); + foundArgProblem = true; + } else if (method.parameters[i] == VoidBinding) { + methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(this, methodDecl, arg); + foundArgProblem = true; + } else if (method.parameters[i].isArrayType() && ((ArrayBinding) method.parameters[i]).leafComponentType == VoidBinding) { + methodDecl.scope.problemReporter().argumentTypeCannotBeVoidArray(this, methodDecl, arg); + foundArgProblem = true; + } + } + } + + boolean foundReturnTypeProblem = false; + if (!method.isConstructor()) { + TypeReference returnType = ((MethodDeclaration) methodDecl).returnType; + if (returnType == null) { + methodDecl.scope.problemReporter().missingReturnType(methodDecl); + method.returnType = null; + foundReturnTypeProblem = true; + } else { + method.returnType = returnType.getTypeBinding(scope); + if (!method.returnType.isValidBinding()) { + methodDecl.scope.problemReporter().returnTypeProblem(this, (MethodDeclaration) methodDecl, method.returnType); + //methodDecl.scope.problemReporter().invalidType(returnType, method.returnType); + method.returnType = null; + foundReturnTypeProblem = true; + } else if (method.returnType.isArrayType() && ((ArrayBinding) method.returnType).leafComponentType == VoidBinding) { + methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray(this, (MethodDeclaration) methodDecl); + method.returnType = null; + foundReturnTypeProblem = true; + } + } + } + if (foundArgProblem) { + methodDecl.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 ^= AccUnresolved; + return method; +} +public final int sourceEnd() { + return scope.referenceContext.sourceEnd; +} +public final int sourceStart() { + return scope.referenceContext.sourceStart; +} +public ReferenceBinding superclass() { + return superclass; +} +public ReferenceBinding[] superInterfaces() { + return superInterfaces; +} +public SyntheticAccessMethodBinding[] syntheticAccessMethods() { + + if (synthetics == null || synthetics[METHOD_EMUL] == null || synthetics[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; + SyntheticAccessMethodBinding[] bindings = new SyntheticAccessMethodBinding[1]; + Enumeration fieldsOrMethods = synthetics[METHOD_EMUL].keys(); + while (fieldsOrMethods.hasMoreElements()) { + + Object fieldOrMethod = fieldsOrMethods.nextElement(); + + if (fieldOrMethod instanceof MethodBinding) { + + SyntheticAccessMethodBinding[] methodAccessors = (SyntheticAccessMethodBinding[]) synthetics[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 SyntheticAccessMethodBinding[index + numberOfAccessors]), 0, index); + if (methodAccessors[0] != null) + bindings[index++] = methodAccessors[0]; // super access + if (methodAccessors[1] != null) + bindings[index++] = methodAccessors[1]; // normal access + + } else { + + SyntheticAccessMethodBinding[] fieldAccessors = (SyntheticAccessMethodBinding[]) synthetics[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 SyntheticAccessMethodBinding[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; + SyntheticAccessMethodBinding[] sortedBindings = new SyntheticAccessMethodBinding[length = bindings.length]; + for (int i = 0; i < length; i++){ + SyntheticAccessMethodBinding binding = bindings[i]; + sortedBindings[binding.index] = binding; + } + return sortedBindings; +} +/** + * Answer the collection of synthetic fields to append into the classfile + */ +public FieldBinding[] syntheticFields() { + + if (synthetics == null) return null; + + int fieldSize = synthetics[FIELD_EMUL] == null ? 0 : synthetics[FIELD_EMUL].size(); + int literalSize = synthetics[CLASS_LITERAL_EMUL] == null ? 0 :synthetics[CLASS_LITERAL_EMUL].size(); + int totalSize = fieldSize + literalSize; + if (totalSize == 0) return null; + FieldBinding[] bindings = new FieldBinding[totalSize]; + + // add innerclass synthetics + if (synthetics[FIELD_EMUL] != null){ + Enumeration elements = synthetics[FIELD_EMUL].elements(); + for (int i = 0; i < fieldSize; i++) { + SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement(); + bindings[synthBinding.index] = synthBinding; + } + } + // add class literal synthetics + if (synthetics[CLASS_LITERAL_EMUL] != null){ + Enumeration elements = synthetics[CLASS_LITERAL_EMUL].elements(); + for (int i = 0; i < literalSize; i++) { + SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement(); + bindings[fieldSize+synthBinding.index] = synthBinding; + } + } + return bindings; +} +public String toString() { + String s = "(id="+(id == NoId ? "NoId" : (""+id) ) +")\n"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-4$ //$NON-NLS-1$ + + if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$ + if (isPublic()) s += "public "; //$NON-NLS-1$ + if (isProtected()) s += "protected "; //$NON-NLS-1$ + if (isPrivate()) s += "private "; //$NON-NLS-1$ + if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$ + if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$ + if (isFinal()) s += "final "; //$NON-NLS-1$ + + s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$ + s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$ + + s += "\n\textends "; //$NON-NLS-1$ + s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$ + + if (superInterfaces != null) { + if (superInterfaces != NoSuperInterfaces) { + s += "\n\timplements : "; //$NON-NLS-1$ + for (int i = 0, length = superInterfaces.length; i < length; i++) { + if (i > 0) + s += ", "; //$NON-NLS-1$ + s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$ + } + } + } else { + s += "NULL SUPERINTERFACES"; //$NON-NLS-1$ + } + + if (enclosingType() != null) { + s += "\n\tenclosing type : "; //$NON-NLS-1$ + s += enclosingType().debugName(); + } + + if (fields != null) { + if (fields != NoFields) { + s += "\n/* fields */"; //$NON-NLS-1$ + for (int i = 0, length = fields.length; i < length; i++) + s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL FIELDS"; //$NON-NLS-1$ + } + + if (methods != null) { + if (methods != NoMethods) { + s += "\n/* methods */"; //$NON-NLS-1$ + for (int i = 0, length = methods.length; i < length; i++) + s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL METHODS"; //$NON-NLS-1$ + } + + if (memberTypes != null) { + if (memberTypes != NoMemberTypes) { + s += "\n/* members */"; //$NON-NLS-1$ + for (int i = 0, length = memberTypes.length; i < length; i++) + s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$ + } + } else { + s += "NULL MEMBER TYPES"; //$NON-NLS-1$ + } + + s += "\n\n\n"; //$NON-NLS-1$ + return s; +} +void verifyMethods(MethodVerifier verifier) { + verifier.verify(this); + + for (int i = memberTypes.length; --i >= 0;) + ((SourceTypeBinding) memberTypes[i]).verifyMethods(verifier); +} + +/* Answer the synthetic field for +* or null if one does not exist. +*/ + +public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) { + + if (synthetics == null || synthetics[FIELD_EMUL] == null) return null; + FieldBinding field = (FieldBinding) synthetics[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){ + Enumeration accessFields = synthetics[FIELD_EMUL].elements(); + while (accessFields.hasMoreElements()) { + field = (FieldBinding) accessFields.nextElement(); + if (CharOperation.prefixEquals(SyntheticArgumentBinding.EnclosingInstancePrefix, field.name) + && targetEnclosingType.isSuperclassOf((ReferenceBinding) field.type)) + return field; + } + } + return null; +} +}