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.ast.ConstructorDeclaration;
15 import net.sourceforge.phpdt.internal.compiler.env.IBinaryField;
16 import net.sourceforge.phpdt.internal.compiler.env.IBinaryMethod;
17 import net.sourceforge.phpdt.internal.compiler.env.IBinaryNestedType;
18 import net.sourceforge.phpdt.internal.compiler.env.IBinaryType;
19 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
22 * Not all fields defined by this type are initialized when it is created. Some
23 * are initialized only when needed.
25 * Accessors have been provided for some public fields so all TypeBindings have
26 * the same API... but access public fields directly whenever possible.
27 * Non-public fields have accessors which should be used everywhere you expect
28 * the field to be initialized.
30 * null is NOT a valid value for a non-public field... it just means the field
34 public final class BinaryTypeBinding extends ReferenceBinding {
35 // all of these fields are ONLY guaranteed to be initialized if accessed
36 // using their public accessor method
37 private ReferenceBinding superclass;
39 private ReferenceBinding enclosingType;
41 private ReferenceBinding[] superInterfaces;
43 private FieldBinding[] fields;
45 private MethodBinding[] methods;
47 private ReferenceBinding[] memberTypes;
49 // For the link with the principle structure
50 private LookupEnvironment environment;
52 public BinaryTypeBinding(PackageBinding packageBinding,
53 IBinaryType binaryType, LookupEnvironment environment) {
54 this.compoundName = CharOperation.splitOn('/', binaryType.getName());
57 this.tagBits |= IsBinaryBinding;
58 this.environment = environment;
59 this.fPackage = packageBinding;
60 this.fileName = binaryType.getFileName();
62 // source name must be one name without "$".
63 char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
64 int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
66 this.sourceName = possibleSourceName;
68 this.sourceName = new char[possibleSourceName.length - start];
69 System.arraycopy(possibleSourceName, start, this.sourceName, 0,
70 this.sourceName.length);
73 this.modifiers = binaryType.getModifiers();
74 if (binaryType.isInterface())
75 this.modifiers |= AccInterface;
78 public FieldBinding[] availableFields() {
79 FieldBinding[] availableFields = new FieldBinding[fields.length];
82 for (int i = 0; i < fields.length; i++) {
84 availableFields[count] = resolveTypeFor(fields[i]);
86 } catch (AbortCompilation a) {
90 System.arraycopy(availableFields, 0,
91 availableFields = new FieldBinding[count], 0, count);
92 return availableFields;
95 public MethodBinding[] availableMethods() {
96 if ((modifiers & AccUnresolved) == 0)
99 MethodBinding[] availableMethods = new MethodBinding[methods.length];
102 for (int i = 0; i < methods.length; i++) {
104 availableMethods[count] = resolveTypesFor(methods[i]);
106 } catch (AbortCompilation a) {
109 System.arraycopy(availableMethods, 0,
110 availableMethods = new MethodBinding[count], 0, count);
111 return availableMethods;
114 void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
115 char[] superclassName = binaryType.getSuperclassName();
116 if (superclassName != null)
117 // attempt to find the superclass if it exists in the cache
118 // (otherwise - resolve it when requested)
119 this.superclass = environment.getTypeFromConstantPoolName(
120 superclassName, 0, -1);
122 char[] enclosingTypeName = binaryType.getEnclosingTypeName();
123 if (enclosingTypeName != null) {
124 // attempt to find the enclosing type if it exists in the cache
125 // (otherwise - resolve it when requested)
126 this.enclosingType = environment.getTypeFromConstantPoolName(
127 enclosingTypeName, 0, -1);
128 this.tagBits |= MemberTypeMask; // must be a member type not a
129 // top-level or local type
130 // if (this.enclosingType().isStrictfp())
131 // this.modifiers |= AccStrictfp;
132 if (this.enclosingType().isDeprecated())
133 this.modifiers |= AccDeprecatedImplicitly;
136 this.memberTypes = NoMemberTypes;
137 IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
138 if (memberTypeStructures != null) {
139 int size = memberTypeStructures.length;
141 this.memberTypes = new ReferenceBinding[size];
142 for (int i = 0; i < size; i++)
143 // attempt to find each member type if it exists in the
144 // cache (otherwise - resolve it when requested)
145 this.memberTypes[i] = environment
146 .getTypeFromConstantPoolName(
147 memberTypeStructures[i].getName(), 0, -1);
151 this.superInterfaces = NoSuperInterfaces;
152 char[][] interfaceNames = binaryType.getInterfaceNames();
153 if (interfaceNames != null) {
154 int size = interfaceNames.length;
156 this.superInterfaces = new ReferenceBinding[size];
157 for (int i = 0; i < size; i++)
158 // attempt to find each superinterface if it exists in the
159 // cache (otherwise - resolve it when requested)
160 this.superInterfaces[i] = environment
161 .getTypeFromConstantPoolName(interfaceNames[i], 0,
165 if (needFieldsAndMethods) {
166 createFields(binaryType.getFields());
167 createMethods(binaryType.getMethods());
171 private void createFields(IBinaryField[] iFields) {
172 this.fields = NoFields;
173 if (iFields != null) {
174 int size = iFields.length;
176 this.fields = new FieldBinding[size];
177 for (int i = 0; i < size; i++) {
178 IBinaryField field = iFields[i];
179 this.fields[i] = new FieldBinding(field.getName(),
180 environment.getTypeFromSignature(field
181 .getTypeName(), 0, -1), field
182 .getModifiers(), this, field.getConstant());
188 private MethodBinding createMethod(IBinaryMethod method) {
189 int modifiers = method.getModifiers() | AccUnresolved;
191 ReferenceBinding[] exceptions = NoExceptions;
192 char[][] exceptionTypes = method.getExceptionTypeNames();
193 if (exceptionTypes != null) {
194 int size = exceptionTypes.length;
196 exceptions = new ReferenceBinding[size];
197 for (int i = 0; i < size; i++)
198 exceptions[i] = environment.getTypeFromConstantPoolName(
199 exceptionTypes[i], 0, -1);
203 TypeBinding[] parameters = NoParameters;
204 char[] signature = method.getMethodDescriptor(); // of the form
205 // (I[Ljava/jang/String;)V
208 int index = 0; // first character is always '(' so skip it
209 while ((nextChar = signature[++index]) != ')') {
210 if (nextChar != '[') {
213 while ((nextChar = signature[++index]) != ';')
218 // Ignore synthetic argument for member types.
219 int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1
221 int size = numOfParams - startIndex;
223 parameters = new TypeBinding[size];
225 int end = 0; // first character is always '(' so skip it
226 for (int i = 0; i < numOfParams; i++) {
227 while ((nextChar = signature[++end]) == '[')
230 while ((nextChar = signature[++end]) != ';')
233 if (i >= startIndex) // skip the synthetic arg if necessary
234 parameters[i - startIndex] = environment
235 .getTypeFromSignature(signature, index, end);
240 MethodBinding binding = null;
241 if (method.isConstructor())
242 binding = new MethodBinding(modifiers, parameters, exceptions, this);
244 binding = new MethodBinding(modifiers, method.getSelector(),
245 environment.getTypeFromSignature(signature, index + 1, -1), // index
252 parameters, exceptions, this);
257 * Create method bindings for binary type, filtering out <clinit> and
260 private void createMethods(IBinaryMethod[] iMethods) {
261 int total = 0, initialTotal = 0, iClinit = -1;
263 if (iMethods != null) {
264 total = initialTotal = iMethods.length;
265 for (int i = total; --i >= 0;) {
266 IBinaryMethod method = iMethods[i];
267 // if ((method.getModifiers() & AccSynthetic) != 0) {
268 // // discard synthetics methods
269 // if (toSkip == null) toSkip = new int[iMethods.length];
274 char[] methodName = method.getSelector();
275 if (methodName.length == 8 && methodName[0] == '<') {
284 this.methods = NoMethods;
288 this.methods = new MethodBinding[total];
289 if (total == initialTotal) {
290 for (int i = 0; i < initialTotal; i++)
291 this.methods[i] = createMethod(iMethods[i]);
293 for (int i = 0, index = 0; i < initialTotal; i++)
294 if (iClinit != i && (toSkip == null || toSkip[i] != -1))
295 this.methods[index++] = createMethod(iMethods[i]);
297 modifiers |= AccUnresolved; // until methods() is sent
301 * Answer the receiver's enclosing type... null if the receiver is a top
304 * NOTE: enclosingType of a binary type is resolved when needed
307 public ReferenceBinding enclosingType() {
308 if (enclosingType == null)
310 if (enclosingType instanceof UnresolvedReferenceBinding)
311 enclosingType = ((UnresolvedReferenceBinding) enclosingType)
312 .resolve(environment);
313 return enclosingType;
316 // NOTE: the type of each field of a binary type is resolved when needed
318 public FieldBinding[] fields() {
319 for (int i = fields.length; --i >= 0;)
320 resolveTypeFor(fields[i]);
324 // NOTE: the return type, arg & exception types of each method of a binary
325 // type are resolved when needed
327 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
328 int argCount = argumentTypes.length;
329 nextMethod: for (int m = methods.length; --m >= 0;) {
330 MethodBinding method = methods[m];
331 if (method.selector == ConstructorDeclaration.ConstantPoolName
332 && method.parameters.length == argCount) {
333 resolveTypesFor(method);
334 TypeBinding[] toMatch = method.parameters;
335 for (int p = 0; p < argCount; p++)
336 if (toMatch[p] != argumentTypes[p])
344 // NOTE: the return type, arg & exception types of each method of a binary
345 // type are resolved when needed
346 // searches up the hierarchy as long as no potential (but not exact) match
349 public MethodBinding getExactMethod(char[] selector,
350 TypeBinding[] argumentTypes) {
351 int argCount = argumentTypes.length;
352 int selectorLength = selector.length;
353 boolean foundNothing = true;
354 nextMethod: for (int m = methods.length; --m >= 0;) {
355 MethodBinding method = methods[m];
356 if (method.selector.length == selectorLength
357 && CharOperation.prefixEquals(method.selector, selector)) {
358 foundNothing = false; // inner type lookups must know that a
359 // method with this name exists
360 if (method.parameters.length == argCount) {
361 resolveTypesFor(method);
362 TypeBinding[] toMatch = method.parameters;
363 for (int p = 0; p < argCount; p++)
364 if (toMatch[p] != argumentTypes[p])
373 if (superInterfaces.length == 1)
374 return superInterfaces[0].getExactMethod(selector,
376 } else if (superclass != null) {
377 return superclass.getExactMethod(selector, argumentTypes);
383 // NOTE: the type of a field of a binary type is resolved when needed
385 public FieldBinding getField(char[] fieldName) {
386 int fieldLength = fieldName.length;
387 for (int f = fields.length; --f >= 0;) {
388 char[] name = fields[f].name;
389 if (name.length == fieldLength
390 && CharOperation.prefixEquals(name, fieldName))
391 return resolveTypeFor(fields[f]);
396 // NOTE: the return type, arg & exception types of each method of a binary
397 // type are resolved when needed
399 public MethodBinding[] getMethods(char[] selector) {
402 int selectorLength = selector.length;
403 for (int m = 0, length = methods.length; m < length; m++) {
404 MethodBinding method = methods[m];
405 if (method.selector.length == selectorLength
406 && CharOperation.prefixEquals(method.selector, selector)) {
407 resolveTypesFor(method);
413 return new MethodBinding[] { methods[lastIndex] };
415 MethodBinding[] result = new MethodBinding[count];
417 for (int m = 0; m <= lastIndex; m++) {
418 MethodBinding method = methods[m];
419 if (method.selector.length == selectorLength
421 .prefixEquals(method.selector, selector))
422 result[count++] = method;
429 // NOTE: member types of binary types are resolved when needed
431 public ReferenceBinding[] memberTypes() {
432 for (int i = memberTypes.length; --i >= 0;)
433 if (memberTypes[i] instanceof UnresolvedReferenceBinding)
434 memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i])
435 .resolve(environment);
439 // NOTE: the return type, arg & exception types of each method of a binary
440 // type are resolved when needed
442 public MethodBinding[] methods() {
443 if ((modifiers & AccUnresolved) == 0)
446 for (int i = methods.length; --i >= 0;)
447 resolveTypesFor(methods[i]);
448 modifiers ^= AccUnresolved;
452 private TypeBinding resolveType(TypeBinding type) {
453 if (type instanceof UnresolvedReferenceBinding)
454 return ((UnresolvedReferenceBinding) type).resolve(environment);
455 if (type instanceof ArrayBinding) {
456 ArrayBinding array = (ArrayBinding) type;
457 if (array.leafComponentType instanceof UnresolvedReferenceBinding)
458 array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType)
459 .resolve(environment);
464 private FieldBinding resolveTypeFor(FieldBinding field) {
465 field.type = resolveType(field.type);
469 private MethodBinding resolveTypesFor(MethodBinding method) {
470 if ((method.modifiers & AccUnresolved) == 0)
473 if (!method.isConstructor())
474 method.returnType = resolveType(method.returnType);
475 for (int i = method.parameters.length; --i >= 0;)
476 method.parameters[i] = resolveType(method.parameters[i]);
477 for (int i = method.thrownExceptions.length; --i >= 0;)
478 if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding)
479 method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i])
480 .resolve(environment);
481 method.modifiers ^= AccUnresolved;
486 * Answer the receiver's superclass... null if the receiver is Object or an
489 * NOTE: superclass of a binary type is resolved when needed
492 public ReferenceBinding superclass() {
493 if (superclass == null)
495 if (superclass instanceof UnresolvedReferenceBinding)
496 superclass = ((UnresolvedReferenceBinding) superclass)
497 .resolve(environment);
501 // NOTE: superInterfaces of binary types are resolved when needed
503 public ReferenceBinding[] superInterfaces() {
504 for (int i = superInterfaces.length; --i >= 0;)
505 if (superInterfaces[i] instanceof UnresolvedReferenceBinding)
506 superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i])
507 .resolve(environment);
508 return superInterfaces;
511 public String toString() {
512 String s = ""; //$NON-NLS-1$
515 s += "deprecated "; //$NON-NLS-1$
517 s += "public "; //$NON-NLS-1$
519 s += "protected "; //$NON-NLS-1$
521 s += "private "; //$NON-NLS-1$
522 if (isAbstract() && isClass())
523 s += "abstract "; //$NON-NLS-1$
524 if (isStatic() && isNestedType())
525 s += "static "; //$NON-NLS-1$
527 s += "final "; //$NON-NLS-1$
529 s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
530 s += (compoundName != null) ? CharOperation.toString(compoundName)
531 : "UNNAMED TYPE"; //$NON-NLS-1$
533 s += "\n\textends "; //$NON-NLS-1$
534 s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
536 if (superInterfaces != null) {
537 if (superInterfaces != NoSuperInterfaces) {
538 s += "\n\timplements : "; //$NON-NLS-1$
539 for (int i = 0, length = superInterfaces.length; i < length; i++) {
541 s += ", "; //$NON-NLS-1$
542 s += (superInterfaces[i] != null) ? superInterfaces[i]
543 .debugName() : "NULL TYPE"; //$NON-NLS-1$
547 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
550 if (enclosingType != null) {
551 s += "\n\tenclosing type : "; //$NON-NLS-1$
552 s += enclosingType.debugName();
555 if (fields != null) {
556 if (fields != NoFields) {
557 s += "\n/* fields */"; //$NON-NLS-1$
558 for (int i = 0, length = fields.length; i < length; i++)
559 s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
562 s += "NULL FIELDS"; //$NON-NLS-1$
565 if (methods != null) {
566 if (methods != NoMethods) {
567 s += "\n/* methods */"; //$NON-NLS-1$
568 for (int i = 0, length = methods.length; i < length; i++)
569 s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
572 s += "NULL METHODS"; //$NON-NLS-1$
575 if (memberTypes != null) {
576 if (memberTypes != NoMemberTypes) {
577 s += "\n/* members */"; //$NON-NLS-1$
578 for (int i = 0, length = memberTypes.length; i < length; i++)
579 s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
582 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
585 s += "\n\n\n"; //$NON-NLS-1$