totally new file layout
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / lookup / BinaryTypeBinding.java
diff --git a/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/lookup/BinaryTypeBinding.java
new file mode 100644 (file)
index 0000000..6ada2f8
--- /dev/null
@@ -0,0 +1,550 @@
+/*******************************************************************************
+ * Copyright (c) 2000, 2004 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials 
+ * are made available under the terms of the Common Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/cpl-v10.html
+ * 
+ * Contributors:
+ *     IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.jdt.internal.compiler.lookup;
+
+import org.eclipse.jdt.core.compiler.CharOperation;
+import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
+import org.eclipse.jdt.internal.compiler.env.IBinaryField;
+import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
+import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
+import org.eclipse.jdt.internal.compiler.env.IBinaryType;
+import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
+
+/*
+Not all fields defined by this type are initialized when it is created.
+Some are initialized only when needed.
+
+Accessors have been provided for some public fields so all TypeBindings have the same API...
+but access public fields directly whenever possible.
+Non-public fields have accessors which should be used everywhere you expect the field to be initialized.
+
+null is NOT a valid value for a non-public field... it just means the field is not initialized.
+*/
+
+public final class BinaryTypeBinding extends ReferenceBinding {
+       // all of these fields are ONLY guaranteed to be initialized if accessed using their public accessor method
+       private ReferenceBinding superclass;
+       private ReferenceBinding enclosingType;
+       private ReferenceBinding[] superInterfaces;
+       private FieldBinding[] fields;
+       private MethodBinding[] methods;
+       private ReferenceBinding[] memberTypes;
+
+       // For the link with the principle structure
+       private LookupEnvironment environment;
+public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, LookupEnvironment environment) {
+       this.compoundName = CharOperation.splitOn('/', binaryType.getName());
+       computeId();
+
+       this.tagBits |= IsBinaryBinding;
+       this.environment = environment;
+       this.fPackage = packageBinding;
+       this.fileName = binaryType.getFileName();
+
+       // source name must be one name without "$".
+       char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
+       int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
+       if (start == 0) {
+               this.sourceName = possibleSourceName;
+       } else {
+               this.sourceName = new char[possibleSourceName.length - start];
+               System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length);
+       }
+
+       this.modifiers = binaryType.getModifiers();
+       if (binaryType.isInterface())
+               this.modifiers |= AccInterface;
+               
+       if (binaryType.isAnonymous()) {
+               this.tagBits |= AnonymousTypeMask;
+       } else if (binaryType.isLocal()) {
+               this.tagBits |= LocalTypeMask;
+       } else if (binaryType.isMember()) {
+               this.tagBits |= MemberTypeMask;
+       }
+}
+
+public FieldBinding[] availableFields() {
+       FieldBinding[] availableFields = new FieldBinding[fields.length];
+       int count = 0;
+       
+       for (int i = 0; i < fields.length;i++) {
+               try {
+                       availableFields[count] = resolveTypeFor(fields[i]);
+                       count++;
+               } catch (AbortCompilation a){
+                       // silent abort
+               }
+       }
+       
+       System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count);
+       return availableFields;
+}
+
+public MethodBinding[] availableMethods() {
+       if ((modifiers & AccUnresolved) == 0)
+               return methods;
+               
+       MethodBinding[] availableMethods = new MethodBinding[methods.length];
+       int count = 0;
+       
+       for (int i = 0; i < methods.length;i++) {
+               try {
+                       availableMethods[count] = resolveTypesFor(methods[i]);
+                       count++;
+               } catch (AbortCompilation a){
+                       // silent abort
+               }
+       }
+       System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count);
+       return availableMethods;
+}
+
+void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
+       
+       // default initialization for super-interfaces early, in case some aborting compilation error occurs,
+       // and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748).
+       this.superInterfaces = NoSuperInterfaces;
+       
+       char[] superclassName = binaryType.getSuperclassName();
+       if (superclassName != null)
+               // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
+               this.superclass = environment.getTypeFromConstantPoolName(superclassName, 0, -1);
+
+       char[] enclosingTypeName = binaryType.getEnclosingTypeName();
+       if (enclosingTypeName != null) {
+               // attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested)
+               this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1);
+               this.tagBits |= MemberTypeMask;   // must be a member type not a top-level or local type
+               if (this.enclosingType().isStrictfp())
+                       this.modifiers |= AccStrictfp;
+               if (this.enclosingType().isDeprecated())
+                       this.modifiers |= AccDeprecatedImplicitly;
+       }
+
+       this.memberTypes = NoMemberTypes;
+       IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
+       if (memberTypeStructures != null) {
+               int size = memberTypeStructures.length;
+               if (size > 0) {
+                       this.memberTypes = new ReferenceBinding[size];
+                       for (int i = 0; i < size; i++)
+                               // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested)
+                               this.memberTypes[i] = environment.getTypeFromConstantPoolName(memberTypeStructures[i].getName(), 0, -1);
+               }
+       }
+
+       char[][] interfaceNames = binaryType.getInterfaceNames();
+       if (interfaceNames != null) {
+               int size = interfaceNames.length;
+               if (size > 0) {
+                       this.superInterfaces = new ReferenceBinding[size];
+                       for (int i = 0; i < size; i++)
+                               // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
+                               this.superInterfaces[i] = environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1);
+               }
+       }
+       if (needFieldsAndMethods) {
+               createFields(binaryType.getFields());
+               createMethods(binaryType.getMethods());
+       } else { // protect against incorrect use of the needFieldsAndMethods flag, see 48459
+               this.fields = NoFields;
+               this.methods = NoMethods;
+       }
+}
+private void createFields(IBinaryField[] iFields) {
+       this.fields = NoFields;
+       if (iFields != null) {
+               int size = iFields.length;
+               if (size > 0) {
+                       this.fields = new FieldBinding[size];
+                       for (int i = 0; i < size; i++) {
+                               IBinaryField field = iFields[i];
+                               this.fields[i] =
+                                       new FieldBinding(
+                                               field.getName(),
+                                               environment.getTypeFromSignature(field.getTypeName(), 0, -1),
+                                               field.getModifiers() | AccUnresolved,
+                                               this,
+                                               field.getConstant());
+                       }
+               }
+       }
+}
+private MethodBinding createMethod(IBinaryMethod method) {
+       int methodModifiers = method.getModifiers() | AccUnresolved;
+
+       ReferenceBinding[] exceptions = NoExceptions;
+       char[][] exceptionTypes = method.getExceptionTypeNames();
+       if (exceptionTypes != null) {
+               int size = exceptionTypes.length;
+               if (size > 0) {
+                       exceptions = new ReferenceBinding[size];
+                       for (int i = 0; i < size; i++)
+                               exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1);
+               }
+       }
+
+       TypeBinding[] parameters = NoParameters;
+       char[] methodSignature = method.getMethodDescriptor();   // of the form (I[Ljava/jang/String;)V
+       int numOfParams = 0;
+       char nextChar;
+       int index = 0;   // first character is always '(' so skip it
+       while ((nextChar = methodSignature[++index]) != ')') {
+               if (nextChar != '[') {
+                       numOfParams++;
+                       if (nextChar == 'L')
+                               while ((nextChar = methodSignature[++index]) != ';'){/*empty*/}
+               }
+       }
+
+       // Ignore synthetic argument for member types.
+       int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
+       int size = numOfParams - startIndex;
+       if (size > 0) {
+               parameters = new TypeBinding[size];
+               index = 1;
+               int end = 0;   // first character is always '(' so skip it
+               for (int i = 0; i < numOfParams; i++) {
+                       while ((nextChar = methodSignature[++end]) == '['){/*empty*/}
+                       if (nextChar == 'L')
+                               while ((nextChar = methodSignature[++end]) != ';'){/*empty*/}
+
+                       if (i >= startIndex)   // skip the synthetic arg if necessary
+                               parameters[i - startIndex] = environment.getTypeFromSignature(methodSignature, index, end);
+                       index = end + 1;
+               }
+       }
+
+       MethodBinding binding = null;
+       if (method.isConstructor())
+               binding = new MethodBinding(methodModifiers, parameters, exceptions, this);
+       else
+               binding = new MethodBinding(
+                       methodModifiers,
+                       method.getSelector(),
+                       environment.getTypeFromSignature(methodSignature, index + 1, -1),   // index is currently pointing at the ')'
+                       parameters,
+                       exceptions,
+                       this);
+       return binding;
+}
+/**
+ * Create method bindings for binary type, filtering out <clinit> and synthetics
+ */
+private void createMethods(IBinaryMethod[] iMethods) {
+       int total = 0, initialTotal = 0, iClinit = -1;
+       int[] toSkip = null;
+       if (iMethods != null) {
+               total = initialTotal = iMethods.length;
+               for (int i = total; --i >= 0;) {
+                       IBinaryMethod method = iMethods[i];
+                       if ((method.getModifiers() & AccSynthetic) != 0) {
+                               // discard synthetics methods
+                               if (toSkip == null) toSkip = new int[iMethods.length];
+                               toSkip[i] = -1;
+                               total--;
+                       } else if (iClinit == -1) {
+                               char[] methodName = method.getSelector();
+                               if (methodName.length == 8 && methodName[0] == '<') {
+                                       // discard <clinit>
+                                       iClinit = i;
+                                       total--;
+                               }
+                       }
+               }
+       }
+       if (total == 0) {
+               this.methods = NoMethods;
+               return;
+       }
+
+       this.methods = new MethodBinding[total];
+       if (total == initialTotal) {
+               for (int i = 0; i < initialTotal; i++)
+                       this.methods[i] = createMethod(iMethods[i]);
+       } else {
+               for (int i = 0, index = 0; i < initialTotal; i++)
+                       if (iClinit != i && (toSkip == null || toSkip[i] != -1))
+                               this.methods[index++] = createMethod(iMethods[i]);
+       }
+       modifiers |= AccUnresolved; // until methods() is sent
+}
+/* Answer the receiver's enclosing type... null if the receiver is a top level type.
+*
+* NOTE: enclosingType of a binary type is resolved when needed
+*/
+
+public ReferenceBinding enclosingType() {
+       if (enclosingType == null)
+               return null;
+       if (enclosingType instanceof UnresolvedReferenceBinding)
+               enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
+       return enclosingType;
+}
+// NOTE: the type of each field of a binary type is resolved when needed
+
+public FieldBinding[] fields() {
+       for (int i = fields.length; --i >= 0;)
+               resolveTypeFor(fields[i]);
+       return fields;
+}
+// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+
+public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
+       int argCount = argumentTypes.length;
+       nextMethod : for (int m = methods.length; --m >= 0;) {
+               MethodBinding method = methods[m];
+               if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) {
+                       resolveTypesFor(method);
+                       TypeBinding[] toMatch = method.parameters;
+                       for (int p = 0; p < argCount; p++)
+                               if (toMatch[p] != argumentTypes[p])
+                                       continue nextMethod;
+                       return method;
+               }
+       }
+       return null;
+}
+// NOTE: the return type, arg & exception types of each method of a binary 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;
+       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) {
+                               resolveTypesFor(method);
+                               TypeBinding[] toMatch = method.parameters;
+                               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 binary type is resolved when needed
+
+public FieldBinding getField(char[] fieldName, boolean needResolve) {
+       int fieldLength = fieldName.length;
+       for (int f = fields.length; --f >= 0;) {
+               char[] name = fields[f].name;
+               if (name.length == fieldLength && CharOperation.equals(name, fieldName))
+                       return needResolve ? resolveTypeFor(fields[f]) : fields[f];
+       }
+       return null;
+}
+/**
+ *  Rewrite of default getMemberType to avoid resolving eagerly all member types when one is requested
+ */
+public ReferenceBinding getMemberType(char[] typeName) {
+       for (int i = this.memberTypes.length; --i >= 0;) {
+           ReferenceBinding memberType = this.memberTypes[i];
+           if (memberType instanceof UnresolvedReferenceBinding) {
+                       char[] name = memberType.sourceName; // source name is qualified with enclosing type name
+                       int prefixLength = this.compoundName[this.compoundName.length - 1].length + 1; // enclosing$
+                       if (name.length == (prefixLength + typeName.length)) // enclosing $ typeName
+                               if (CharOperation.fragmentEquals(typeName, name, prefixLength, true)) // only check trailing portion
+                                       return this.memberTypes[i] = ((UnresolvedReferenceBinding) memberType).resolve(environment);
+           } else if (CharOperation.equals(typeName, memberType.sourceName)) {
+               return memberType;
+           }
+       }
+       return null;
+}
+// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+
+public MethodBinding[] getMethods(char[] selector) {
+       int count = 0;
+       int lastIndex = -1;
+       int selectorLength = selector.length;
+       for (int m = 0, length = methods.length; m < length; m++) {
+               MethodBinding method = methods[m];
+               if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
+                       resolveTypesFor(method);
+                       count++;
+                       lastIndex = m;
+               }
+       }
+       if (count == 1)
+               return new MethodBinding[] {methods[lastIndex]};
+       if (count > 0) {
+               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;
+       }
+       return NoMethods;
+}
+public boolean hasMemberTypes() {
+    return this.memberTypes.length > 0;
+}
+// NOTE: member types of binary types are resolved when needed
+
+public ReferenceBinding[] memberTypes() {
+       for (int i = memberTypes.length; --i >= 0;)
+               if (memberTypes[i] instanceof UnresolvedReferenceBinding)
+                       memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment);
+       return memberTypes;
+}
+// NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
+
+public MethodBinding[] methods() {
+       if ((modifiers & AccUnresolved) == 0)
+               return methods;
+
+       for (int i = methods.length; --i >= 0;)
+               resolveTypesFor(methods[i]);
+       modifiers ^= AccUnresolved;
+       return methods;
+}
+TypeBinding resolveType(TypeBinding type) {
+       if (type instanceof UnresolvedReferenceBinding)
+               return ((UnresolvedReferenceBinding) type).resolve(environment);
+       if (type instanceof ArrayBinding) {
+               ArrayBinding array = (ArrayBinding) type;
+               if (array.leafComponentType instanceof UnresolvedReferenceBinding)
+                       array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment);
+       }
+       return type;
+}
+private FieldBinding resolveTypeFor(FieldBinding field) {
+       if ((field.modifiers & AccUnresolved) != 0) {
+               field.type = resolveType(field.type);
+               field.modifiers ^= AccUnresolved;
+       }
+       return field;
+}
+private MethodBinding resolveTypesFor(MethodBinding method) {
+       if ((method.modifiers & AccUnresolved) == 0)
+               return method;
+
+       if (!method.isConstructor())
+               method.returnType = resolveType(method.returnType);
+       for (int i = method.parameters.length; --i >= 0;)
+               method.parameters[i] = resolveType(method.parameters[i]);
+       for (int i = method.thrownExceptions.length; --i >= 0;)
+               if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding)
+                       method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment);
+       method.modifiers ^= AccUnresolved;
+       return method;
+}
+/* Answer the receiver's superclass... null if the receiver is Object or an interface.
+*
+* NOTE: superclass of a binary type is resolved when needed
+*/
+
+public ReferenceBinding superclass() {
+       if (superclass == null)
+               return null;
+       if (superclass instanceof UnresolvedReferenceBinding)
+               superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
+       return superclass;
+}
+// NOTE: superInterfaces of binary types are resolved when needed
+
+public ReferenceBinding[] superInterfaces() {
+       for (int i = superInterfaces.length; --i >= 0;)
+               if (superInterfaces[i] instanceof UnresolvedReferenceBinding)
+                       superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment);
+       return superInterfaces;
+}
+MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
+       return methods;
+}
+public String toString() {
+       String s = ""; //$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;
+}
+}