1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
13 import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
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.phpdt.internal.compiler.util.CharOperation;
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 ')'
223 private void createMethods(IBinaryMethod[] iMethods) {
225 int clinitIndex = -1;
226 if (iMethods != null) {
227 total = iMethods.length;
228 for (int i = total; --i >= 0;) {
229 char[] methodName = iMethods[i].getSelector();
230 if (methodName[0] == '<' && methodName.length == 8) { // Can only match <clinit>
238 this.methods = NoMethods;
242 this.methods = new MethodBinding[total];
244 for (int i = 0, length = iMethods.length; i < length; i++)
245 if (i != clinitIndex)
246 this.methods[next++] = createMethod(iMethods[i]);
247 modifiers |= AccUnresolved; // until methods() is sent
249 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
251 * NOTE: enclosingType of a binary type is resolved when needed
254 public ReferenceBinding enclosingType() {
255 if (enclosingType == null)
257 if (enclosingType instanceof UnresolvedReferenceBinding)
258 enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
259 return enclosingType;
261 // NOTE: the type of each field of a binary type is resolved when needed
263 public FieldBinding[] fields() {
264 for (int i = fields.length; --i >= 0;)
265 resolveTypeFor(fields[i]);
268 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
270 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
271 int argCount = argumentTypes.length;
272 nextMethod : for (int m = methods.length; --m >= 0;) {
273 MethodBinding method = methods[m];
274 if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) {
275 resolveTypesFor(method);
276 TypeBinding[] toMatch = method.parameters;
277 for (int p = 0; p < argCount; p++)
278 if (toMatch[p] != argumentTypes[p])
285 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
286 // searches up the hierarchy as long as no potential (but not exact) match was found.
288 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) {
289 int argCount = argumentTypes.length;
290 int selectorLength = selector.length;
291 boolean foundNothing = true;
292 nextMethod : for (int m = methods.length; --m >= 0;) {
293 MethodBinding method = methods[m];
294 if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) {
295 foundNothing = false; // inner type lookups must know that a method with this name exists
296 if (method.parameters.length == argCount) {
297 resolveTypesFor(method);
298 TypeBinding[] toMatch = method.parameters;
299 for (int p = 0; p < argCount; p++)
300 if (toMatch[p] != argumentTypes[p])
309 if (superInterfaces.length == 1)
310 return superInterfaces[0].getExactMethod(selector, argumentTypes);
311 } else if (superclass != null) {
312 return superclass.getExactMethod(selector, argumentTypes);
317 // NOTE: the type of a field of a binary type is resolved when needed
319 public FieldBinding getField(char[] fieldName) {
320 int fieldLength = fieldName.length;
321 for (int f = fields.length; --f >= 0;) {
322 char[] name = fields[f].name;
323 if (name.length == fieldLength && CharOperation.prefixEquals(name, fieldName))
324 return resolveTypeFor(fields[f]);
328 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
330 public MethodBinding[] getMethods(char[] selector) {
333 int selectorLength = selector.length;
334 for (int m = 0, length = methods.length; m < length; m++) {
335 MethodBinding method = methods[m];
336 if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector)) {
337 resolveTypesFor(method);
343 return new MethodBinding[] {methods[lastIndex]};
345 MethodBinding[] result = new MethodBinding[count];
347 for (int m = 0; m <= lastIndex; m++) {
348 MethodBinding method = methods[m];
349 if (method.selector.length == selectorLength && CharOperation.prefixEquals(method.selector, selector))
350 result[count++] = method;
356 // NOTE: member types of binary types are resolved when needed
358 public ReferenceBinding[] memberTypes() {
359 for (int i = memberTypes.length; --i >= 0;)
360 if (memberTypes[i] instanceof UnresolvedReferenceBinding)
361 memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment);
364 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
366 public MethodBinding[] methods() {
367 if ((modifiers & AccUnresolved) == 0)
370 for (int i = methods.length; --i >= 0;)
371 resolveTypesFor(methods[i]);
372 modifiers ^= AccUnresolved;
375 private TypeBinding resolveType(TypeBinding type) {
376 if (type instanceof UnresolvedReferenceBinding)
377 return ((UnresolvedReferenceBinding) type).resolve(environment);
378 if (type instanceof ArrayBinding) {
379 ArrayBinding array = (ArrayBinding) type;
380 if (array.leafComponentType instanceof UnresolvedReferenceBinding)
381 array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment);
385 private FieldBinding resolveTypeFor(FieldBinding field) {
386 field.type = resolveType(field.type);
389 private MethodBinding resolveTypesFor(MethodBinding method) {
390 if ((method.modifiers & AccUnresolved) == 0)
393 if (!method.isConstructor())
394 method.returnType = resolveType(method.returnType);
395 for (int i = method.parameters.length; --i >= 0;)
396 method.parameters[i] = resolveType(method.parameters[i]);
397 for (int i = method.thrownExceptions.length; --i >= 0;)
398 if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding)
399 method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment);
400 method.modifiers ^= AccUnresolved;
403 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
405 * NOTE: superclass of a binary type is resolved when needed
408 public ReferenceBinding superclass() {
409 if (superclass == null)
411 if (superclass instanceof UnresolvedReferenceBinding)
412 superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
415 // NOTE: superInterfaces of binary types are resolved when needed
417 public ReferenceBinding[] superInterfaces() {
418 for (int i = superInterfaces.length; --i >= 0;)
419 if (superInterfaces[i] instanceof UnresolvedReferenceBinding)
420 superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment);
421 return superInterfaces;
423 public String toString() {
424 String s = ""; //$NON-NLS-1$
426 if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$
427 if (isPublic()) s += "public "; //$NON-NLS-1$
428 if (isProtected()) s += "protected "; //$NON-NLS-1$
429 if (isPrivate()) s += "private "; //$NON-NLS-1$
430 if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$
431 if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$
432 if (isFinal()) s += "final "; //$NON-NLS-1$
434 s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
435 s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
437 s += "\n\textends "; //$NON-NLS-1$
438 s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
440 if (superInterfaces != null) {
441 if (superInterfaces != NoSuperInterfaces) {
442 s += "\n\timplements : "; //$NON-NLS-1$
443 for (int i = 0, length = superInterfaces.length; i < length; i++) {
445 s += ", "; //$NON-NLS-1$
446 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
450 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
453 if (enclosingType != null) {
454 s += "\n\tenclosing type : "; //$NON-NLS-1$
455 s += enclosingType.debugName();
458 if (fields != null) {
459 if (fields != NoFields) {
460 s += "\n/* fields */"; //$NON-NLS-1$
461 for (int i = 0, length = fields.length; i < length; i++)
462 s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
465 s += "NULL FIELDS"; //$NON-NLS-1$
468 if (methods != null) {
469 if (methods != NoMethods) {
470 s += "\n/* methods */"; //$NON-NLS-1$
471 for (int i = 0, length = methods.length; i < length; i++)
472 s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
475 s += "NULL METHODS"; //$NON-NLS-1$
478 if (memberTypes != null) {
479 if (memberTypes != NoMemberTypes) {
480 s += "\n/* members */"; //$NON-NLS-1$
481 for (int i = 0, length = memberTypes.length; i < length; i++)
482 s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
485 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
488 s += "\n\n\n"; //$NON-NLS-1$