1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.core.compiler.CharOperation;
14 import net.sourceforge.phpdt.internal.compiler.env.IBinaryField;
15 import net.sourceforge.phpdt.internal.compiler.env.IBinaryMethod;
16 import net.sourceforge.phpdt.internal.compiler.env.IBinaryNestedType;
17 import net.sourceforge.phpdt.internal.compiler.env.IBinaryType;
18 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
19 import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
22 Not all fields defined by this type are initialized when it is created.
23 Some are initialized only when needed.
25 Accessors have been provided for some public fields so all TypeBindings have the same API...
26 but access public fields directly whenever possible.
27 Non-public fields have accessors which should be used everywhere you expect the field to be initialized.
29 null is NOT a valid value for a non-public field... it just means the field is not initialized.
32 public final class BinaryTypeBinding extends ReferenceBinding {
33 // all of these fields are ONLY guaranteed to be initialized if accessed using their public accessor method
34 private ReferenceBinding superclass;
35 private ReferenceBinding enclosingType;
36 private ReferenceBinding[] superInterfaces;
37 private FieldBinding[] fields;
38 private MethodBinding[] methods;
39 private ReferenceBinding[] memberTypes;
41 // For the link with the principle structure
42 private LookupEnvironment environment;
43 public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, LookupEnvironment environment) {
44 this.compoundName = CharOperation.splitOn('/', binaryType.getName());
47 this.tagBits |= IsBinaryBinding;
48 this.environment = environment;
49 this.fPackage = packageBinding;
50 this. fileName = binaryType.getFileName();
52 // source name must be one name without "$".
53 char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
54 int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
56 this.sourceName = possibleSourceName;
58 this.sourceName = new char[possibleSourceName.length - start];
59 System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length);
62 this.modifiers = binaryType.getModifiers();
63 if (binaryType.isInterface())
64 this.modifiers |= AccInterface;
67 public FieldBinding[] availableFields() {
68 FieldBinding[] availableFields = new FieldBinding[fields.length];
71 for (int i = 0; i < fields.length;i++) {
73 availableFields[count] = resolveTypeFor(fields[i]);
75 } catch (AbortCompilation a){
79 System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count);
80 return availableFields;
83 public MethodBinding[] availableMethods() {
84 if ((modifiers & AccUnresolved) == 0)
87 MethodBinding[] availableMethods = new MethodBinding[methods.length];
90 for (int i = 0; i < methods.length;i++) {
92 availableMethods[count] = resolveTypesFor(methods[i]);
94 } catch (AbortCompilation a){
97 System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count);
98 return availableMethods;
101 void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
102 char[] superclassName = binaryType.getSuperclassName();
103 if (superclassName != null)
104 // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
105 this.superclass = environment.getTypeFromConstantPoolName(superclassName, 0, -1);
107 char[] enclosingTypeName = binaryType.getEnclosingTypeName();
108 if (enclosingTypeName != null) {
109 // attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested)
110 this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1);
111 this.tagBits |= MemberTypeMask; // must be a member type not a top-level or local type
112 // if (this.enclosingType().isStrictfp())
113 // this.modifiers |= AccStrictfp;
114 if (this.enclosingType().isDeprecated())
115 this.modifiers |= AccDeprecatedImplicitly;
118 this.memberTypes = NoMemberTypes;
119 IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
120 if (memberTypeStructures != null) {
121 int size = memberTypeStructures.length;
123 this.memberTypes = new ReferenceBinding[size];
124 for (int i = 0; i < size; i++)
125 // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested)
126 this.memberTypes[i] = environment.getTypeFromConstantPoolName(memberTypeStructures[i].getName(), 0, -1);
130 this.superInterfaces = NoSuperInterfaces;
131 char[][] interfaceNames = binaryType.getInterfaceNames();
132 if (interfaceNames != null) {
133 int size = interfaceNames.length;
135 this.superInterfaces = new ReferenceBinding[size];
136 for (int i = 0; i < size; i++)
137 // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
138 this.superInterfaces[i] = environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1);
141 if (needFieldsAndMethods){
142 createFields(binaryType.getFields());
143 createMethods(binaryType.getMethods());
146 private void createFields(IBinaryField[] iFields) {
147 this.fields = NoFields;
148 if (iFields != null) {
149 int size = iFields.length;
151 this.fields = new FieldBinding[size];
152 for (int i = 0; i < size; i++) {
153 IBinaryField field = iFields[i];
157 environment.getTypeFromSignature(field.getTypeName(), 0, -1),
158 field.getModifiers(),
160 field.getConstant());
165 private MethodBinding createMethod(IBinaryMethod method) {
166 int modifiers = method.getModifiers() | AccUnresolved;
168 ReferenceBinding[] exceptions = NoExceptions;
169 char[][] exceptionTypes = method.getExceptionTypeNames();
170 if (exceptionTypes != null) {
171 int size = exceptionTypes.length;
173 exceptions = new ReferenceBinding[size];
174 for (int i = 0; i < size; i++)
175 exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1);
179 TypeBinding[] parameters = NoParameters;
180 char[] signature = method.getMethodDescriptor(); // of the form (I[Ljava/jang/String;)V
183 int index = 0; // first character is always '(' so skip it
184 while ((nextChar = signature[++index]) != ')') {
185 if (nextChar != '[') {
188 while ((nextChar = signature[++index]) != ';');
192 // Ignore synthetic argument for member types.
193 int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
194 int size = numOfParams - startIndex;
196 parameters = new TypeBinding[size];
198 int end = 0; // first character is always '(' so skip it
199 for (int i = 0; i < numOfParams; i++) {
200 while ((nextChar = signature[++end]) == '[');
202 while ((nextChar = signature[++end]) != ';');
204 if (i >= startIndex) // skip the synthetic arg if necessary
205 parameters[i - startIndex] = environment.getTypeFromSignature(signature, index, end);
210 MethodBinding binding = null;
211 if (method.isConstructor())
212 binding = new MethodBinding(modifiers, parameters, exceptions, this);
214 binding = new MethodBinding(
216 method.getSelector(),
217 environment.getTypeFromSignature(signature, index + 1, -1), // index is currently pointing at the ')'
224 * Create method bindings for binary type, filtering out <clinit> and synthetics
226 private void createMethods(IBinaryMethod[] iMethods) {
227 int total = 0, initialTotal = 0, iClinit = -1;
229 if (iMethods != null) {
230 total = initialTotal = iMethods.length;
231 for (int i = total; --i >= 0;) {
232 IBinaryMethod method = iMethods[i];
233 // if ((method.getModifiers() & AccSynthetic) != 0) {
234 // // discard synthetics methods
235 // if (toSkip == null) toSkip = new int[iMethods.length];
240 char[] methodName = method.getSelector();
241 if (methodName.length == 8 && methodName[0] == '<') {
250 this.methods = NoMethods;
254 this.methods = new MethodBinding[total];
255 if (total == initialTotal) {
256 for (int i = 0; i < initialTotal; i++)
257 this.methods[i] = createMethod(iMethods[i]);
259 for (int i = 0, index = 0; i < initialTotal; i++)
260 if (iClinit != i && (toSkip == null || toSkip[i] != -1))
261 this.methods[index++] = createMethod(iMethods[i]);
263 modifiers |= AccUnresolved; // until methods() is sent
265 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
267 * NOTE: enclosingType of a binary type is resolved when needed
270 public ReferenceBinding enclosingType() {
271 if (enclosingType == null)
273 if (enclosingType instanceof UnresolvedReferenceBinding)
274 enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
275 return enclosingType;
277 // NOTE: the type of each field of a binary type is resolved when needed
279 public FieldBinding[] fields() {
280 for (int i = fields.length; --i >= 0;)
281 resolveTypeFor(fields[i]);
284 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
286 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
287 int argCount = argumentTypes.length;
288 nextMethod : for (int m = methods.length; --m >= 0;) {
289 MethodBinding method = methods[m];
290 if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) {
291 resolveTypesFor(method);
292 TypeBinding[] toMatch = method.parameters;
293 for (int p = 0; p < argCount; p++)
294 if (toMatch[p] != argumentTypes[p])
301 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
302 // searches up the hierarchy as long as no potential (but not exact) match was found.
304 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) {
305 int argCount = argumentTypes.length;
306 int selectorLength = selector.length;
307 boolean foundNothing = true;
308 nextMethod : for (int m = methods.length; --m >= 0;) {
309 MethodBinding method = methods[m];
310 if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) {
311 foundNothing = false; // inner type lookups must know that a method with this name exists
312 if (method.parameters.length == argCount) {
313 resolveTypesFor(method);
314 TypeBinding[] toMatch = method.parameters;
315 for (int p = 0; p < argCount; p++)
316 if (toMatch[p] != argumentTypes[p])
325 if (superInterfaces.length == 1)
326 return superInterfaces[0].getExactMethod(selector, argumentTypes);
327 } else if (superclass != null) {
328 return superclass.getExactMethod(selector, argumentTypes);
333 // NOTE: the type of a field of a binary type is resolved when needed
335 public FieldBinding getField(char[] fieldName) {
336 int fieldLength = fieldName.length;
337 for (int f = fields.length; --f >= 0;) {
338 char[] name = fields[f].name;
339 if (name.length == fieldLength && CharOperation.prefixEquals(name, fieldName))
340 return resolveTypeFor(fields[f]);
344 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
346 public MethodBinding[] getMethods(char[] selector) {
349 int selectorLength = selector.length;
350 for (int m = 0, length = methods.length; m < length; m++) {
351 MethodBinding method = methods[m];
352 if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) {
353 resolveTypesFor(method);
359 return new MethodBinding[] {methods[lastIndex]};
361 MethodBinding[] result = new MethodBinding[count];
363 for (int m = 0; m <= lastIndex; m++) {
364 MethodBinding method = methods[m];
365 if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector))
366 result[count++] = method;
372 // NOTE: member types of binary types are resolved when needed
374 public ReferenceBinding[] memberTypes() {
375 for (int i = memberTypes.length; --i >= 0;)
376 if (memberTypes[i] instanceof UnresolvedReferenceBinding)
377 memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment);
380 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
382 public MethodBinding[] methods() {
383 if ((modifiers & AccUnresolved) == 0)
386 for (int i = methods.length; --i >= 0;)
387 resolveTypesFor(methods[i]);
388 modifiers ^= AccUnresolved;
391 private TypeBinding resolveType(TypeBinding type) {
392 if (type instanceof UnresolvedReferenceBinding)
393 return ((UnresolvedReferenceBinding) type).resolve(environment);
394 if (type instanceof ArrayBinding) {
395 ArrayBinding array = (ArrayBinding) type;
396 if (array.leafComponentType instanceof UnresolvedReferenceBinding)
397 array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment);
401 private FieldBinding resolveTypeFor(FieldBinding field) {
402 field.type = resolveType(field.type);
405 private MethodBinding resolveTypesFor(MethodBinding method) {
406 if ((method.modifiers & AccUnresolved) == 0)
409 if (!method.isConstructor())
410 method.returnType = resolveType(method.returnType);
411 for (int i = method.parameters.length; --i >= 0;)
412 method.parameters[i] = resolveType(method.parameters[i]);
413 for (int i = method.thrownExceptions.length; --i >= 0;)
414 if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding)
415 method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment);
416 method.modifiers ^= AccUnresolved;
419 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
421 * NOTE: superclass of a binary type is resolved when needed
424 public ReferenceBinding superclass() {
425 if (superclass == null)
427 if (superclass instanceof UnresolvedReferenceBinding)
428 superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
431 // NOTE: superInterfaces of binary types are resolved when needed
433 public ReferenceBinding[] superInterfaces() {
434 for (int i = superInterfaces.length; --i >= 0;)
435 if (superInterfaces[i] instanceof UnresolvedReferenceBinding)
436 superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment);
437 return superInterfaces;
439 public String toString() {
440 String s = ""; //$NON-NLS-1$
442 if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$
443 if (isPublic()) s += "public "; //$NON-NLS-1$
444 if (isProtected()) s += "protected "; //$NON-NLS-1$
445 if (isPrivate()) s += "private "; //$NON-NLS-1$
446 if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$
447 if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$
448 if (isFinal()) s += "final "; //$NON-NLS-1$
450 s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
451 s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
453 s += "\n\textends "; //$NON-NLS-1$
454 s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
456 if (superInterfaces != null) {
457 if (superInterfaces != NoSuperInterfaces) {
458 s += "\n\timplements : "; //$NON-NLS-1$
459 for (int i = 0, length = superInterfaces.length; i < length; i++) {
461 s += ", "; //$NON-NLS-1$
462 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
466 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
469 if (enclosingType != null) {
470 s += "\n\tenclosing type : "; //$NON-NLS-1$
471 s += enclosingType.debugName();
474 if (fields != null) {
475 if (fields != NoFields) {
476 s += "\n/* fields */"; //$NON-NLS-1$
477 for (int i = 0, length = fields.length; i < length; i++)
478 s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
481 s += "NULL FIELDS"; //$NON-NLS-1$
484 if (methods != null) {
485 if (methods != NoMethods) {
486 s += "\n/* methods */"; //$NON-NLS-1$
487 for (int i = 0, length = methods.length; i < length; i++)
488 s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
491 s += "NULL METHODS"; //$NON-NLS-1$
494 if (memberTypes != null) {
495 if (memberTypes != NoMemberTypes) {
496 s += "\n/* members */"; //$NON-NLS-1$
497 for (int i = 0, length = memberTypes.length; i < length; i++)
498 s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
501 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
504 s += "\n\n\n"; //$NON-NLS-1$