04dd47d4022c664181559ce2131e5d31b5800dff
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / lookup / BinaryTypeBinding.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.lookup;
12
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;
20
21 /*
22 Not all fields defined by this type are initialized when it is created.
23 Some are initialized only when needed.
24
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.
28
29 null is NOT a valid value for a non-public field... it just means the field is not initialized.
30 */
31
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;
40
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());
45 //      computeId();
46
47         this.tagBits |= IsBinaryBinding;
48         this.environment = environment;
49         this.fPackage = packageBinding;
50         this.   fileName = binaryType.getFileName();
51
52         // source name must be one name without "$".
53         char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
54         int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
55         if (start == 0) {
56                 this.sourceName = possibleSourceName;
57         } else {
58                 this.sourceName = new char[possibleSourceName.length - start];
59                 System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length);
60         }
61
62         this.modifiers = binaryType.getModifiers();
63         if (binaryType.isInterface())
64                 this.modifiers |= AccInterface;
65 }
66
67 public FieldBinding[] availableFields() {
68         FieldBinding[] availableFields = new FieldBinding[fields.length];
69         int count = 0;
70         
71         for (int i = 0; i < fields.length;i++) {
72                 try {
73                         availableFields[count] = resolveTypeFor(fields[i]);
74                         count++;
75                 } catch (AbortCompilation a){
76                 }
77         }
78         
79         System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count);
80         return availableFields;
81 }
82
83 public MethodBinding[] availableMethods() {
84         if ((modifiers & AccUnresolved) == 0)
85                 return methods;
86                 
87         MethodBinding[] availableMethods = new MethodBinding[methods.length];
88         int count = 0;
89         
90         for (int i = 0; i < methods.length;i++) {
91                 try {
92                         availableMethods[count] = resolveTypesFor(methods[i]);
93                         count++;
94                 } catch (AbortCompilation a){
95                 }
96         }
97         System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count);
98         return availableMethods;
99 }
100
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);
106
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;
116         }
117
118         this.memberTypes = NoMemberTypes;
119         IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
120         if (memberTypeStructures != null) {
121                 int size = memberTypeStructures.length;
122                 if (size > 0) {
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);
127                 }
128         }
129
130         this.superInterfaces = NoSuperInterfaces;
131         char[][] interfaceNames = binaryType.getInterfaceNames();
132         if (interfaceNames != null) {
133                 int size = interfaceNames.length;
134                 if (size > 0) {
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);
139                 }
140         }
141         if (needFieldsAndMethods){
142                 createFields(binaryType.getFields());
143                 createMethods(binaryType.getMethods());
144         }
145 }
146 private void createFields(IBinaryField[] iFields) {
147         this.fields = NoFields;
148         if (iFields != null) {
149                 int size = iFields.length;
150                 if (size > 0) {
151                         this.fields = new FieldBinding[size];
152                         for (int i = 0; i < size; i++) {
153                                 IBinaryField field = iFields[i];
154                                 this.fields[i] =
155                                         new FieldBinding(
156                                                 field.getName(),
157                                                 environment.getTypeFromSignature(field.getTypeName(), 0, -1),
158                                                 field.getModifiers(),
159                                                 this,
160                                                 field.getConstant());
161                         }
162                 }
163         }
164 }
165 private MethodBinding createMethod(IBinaryMethod method) {
166         int modifiers = method.getModifiers() | AccUnresolved;
167
168         ReferenceBinding[] exceptions = NoExceptions;
169         char[][] exceptionTypes = method.getExceptionTypeNames();
170         if (exceptionTypes != null) {
171                 int size = exceptionTypes.length;
172                 if (size > 0) {
173                         exceptions = new ReferenceBinding[size];
174                         for (int i = 0; i < size; i++)
175                                 exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1);
176                 }
177         }
178
179         TypeBinding[] parameters = NoParameters;
180         char[] signature = method.getMethodDescriptor();   // of the form (I[Ljava/jang/String;)V
181         int numOfParams = 0;
182         char nextChar;
183         int index = 0;   // first character is always '(' so skip it
184         while ((nextChar = signature[++index]) != ')') {
185                 if (nextChar != '[') {
186                         numOfParams++;
187                         if (nextChar == 'L')
188                                 while ((nextChar = signature[++index]) != ';');
189                 }
190         }
191
192         // Ignore synthetic argument for member types.
193         int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
194         int size = numOfParams - startIndex;
195         if (size > 0) {
196                 parameters = new TypeBinding[size];
197                 index = 1;
198                 int end = 0;   // first character is always '(' so skip it
199                 for (int i = 0; i < numOfParams; i++) {
200                         while ((nextChar = signature[++end]) == '[');
201                         if (nextChar == 'L')
202                                 while ((nextChar = signature[++end]) != ';');
203
204                         if (i >= startIndex)   // skip the synthetic arg if necessary
205                                 parameters[i - startIndex] = environment.getTypeFromSignature(signature, index, end);
206                         index = end + 1;
207                 }
208         }
209
210         MethodBinding binding = null;
211         if (method.isConstructor())
212                 binding = new MethodBinding(modifiers, parameters, exceptions, this);
213         else
214                 binding = new MethodBinding(
215                         modifiers,
216                         method.getSelector(),
217                         environment.getTypeFromSignature(signature, index + 1, -1),   // index is currently pointing at the ')'
218                         parameters,
219                         exceptions,
220                         this);
221         return binding;
222 }
223 /**
224  * Create method bindings for binary type, filtering out <clinit> and synthetics
225  */
226 private void createMethods(IBinaryMethod[] iMethods) {
227         int total = 0, initialTotal = 0, iClinit = -1;
228         int[] toSkip = null;
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];
236 //                              toSkip[i] = -1;
237 //                              total--;
238 //                      } else 
239                         if (iClinit == -1) {
240                                 char[] methodName = method.getSelector();
241                                 if (methodName.length == 8 && methodName[0] == '<') {
242                                         // discard <clinit>
243                                         iClinit = i;
244                                         total--;
245                                 }
246                         }
247                 }
248         }
249         if (total == 0) {
250                 this.methods = NoMethods;
251                 return;
252         }
253
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]);
258         } else {
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]);
262         }
263         modifiers |= AccUnresolved; // until methods() is sent
264 }
265 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
266 *
267 * NOTE: enclosingType of a binary type is resolved when needed
268 */
269
270 public ReferenceBinding enclosingType() {
271         if (enclosingType == null)
272                 return null;
273         if (enclosingType instanceof UnresolvedReferenceBinding)
274                 enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
275         return enclosingType;
276 }
277 // NOTE: the type of each field of a binary type is resolved when needed
278
279 public FieldBinding[] fields() {
280         for (int i = fields.length; --i >= 0;)
281                 resolveTypeFor(fields[i]);
282         return fields;
283 }
284 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
285
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])
295                                         continue nextMethod;
296                         return method;
297                 }
298         }
299         return null;
300 }
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.
303
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])
317                                                 continue nextMethod;
318                                 return method;
319                         }
320                 }
321         }
322
323         if (foundNothing) {
324                 if (isInterface()) {
325                          if (superInterfaces.length == 1)
326                                 return superInterfaces[0].getExactMethod(selector, argumentTypes);
327                 } else if (superclass != null) {
328                         return superclass.getExactMethod(selector, argumentTypes);
329                 }
330         }
331         return null;
332 }
333 // NOTE: the type of a field of a binary type is resolved when needed
334
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]);
341         }
342         return null;
343 }
344 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
345
346 public MethodBinding[] getMethods(char[] selector) {
347         int count = 0;
348         int lastIndex = -1;
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);
354                         count++;
355                         lastIndex = m;
356                 }
357         }
358         if (count == 1)
359                 return new MethodBinding[] {methods[lastIndex]};
360         if (count > 0) {
361                 MethodBinding[] result = new MethodBinding[count];
362                 count = 0;
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;
367                 }
368                 return result;
369         }
370         return NoMethods;
371 }
372 // NOTE: member types of binary types are resolved when needed
373
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);
378         return memberTypes;
379 }
380 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
381
382 public MethodBinding[] methods() {
383         if ((modifiers & AccUnresolved) == 0)
384                 return methods;
385
386         for (int i = methods.length; --i >= 0;)
387                 resolveTypesFor(methods[i]);
388         modifiers ^= AccUnresolved;
389         return methods;
390 }
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);
398         }
399         return type;
400 }
401 private FieldBinding resolveTypeFor(FieldBinding field) {
402         field.type = resolveType(field.type);
403         return field;
404 }
405 private MethodBinding resolveTypesFor(MethodBinding method) {
406         if ((method.modifiers & AccUnresolved) == 0)
407                 return method;
408
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;
417         return method;
418 }
419 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
420 *
421 * NOTE: superclass of a binary type is resolved when needed
422 */
423
424 public ReferenceBinding superclass() {
425         if (superclass == null)
426                 return null;
427         if (superclass instanceof UnresolvedReferenceBinding)
428                 superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
429         return superclass;
430 }
431 // NOTE: superInterfaces of binary types are resolved when needed
432
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;
438 }
439 public String toString() {
440         String s = ""; //$NON-NLS-1$
441
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$
449
450         s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
451         s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
452
453         s += "\n\textends "; //$NON-NLS-1$
454         s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
455
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++) {
460                                 if (i  > 0)
461                                         s += ", "; //$NON-NLS-1$
462                                 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
463                         }
464                 }
465         } else {
466                 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
467         }
468
469         if (enclosingType != null) {
470                 s += "\n\tenclosing type : "; //$NON-NLS-1$
471                 s += enclosingType.debugName();
472         }
473
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$
479                 }
480         } else {
481                 s += "NULL FIELDS"; //$NON-NLS-1$
482         }
483
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$
489                 }
490         } else {
491                 s += "NULL METHODS"; //$NON-NLS-1$
492         }
493
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$
499                 }
500         } else {
501                 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
502         }
503
504         s += "\n\n\n"; //$NON-NLS-1$
505         return s;
506 }
507 }