ee4fe85f18cd86131af7de656f56c26da0c1d977
[phpeclipse.git] /
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
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.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;
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 private void createMethods(IBinaryMethod[] iMethods) {
224         int total = 0;
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>
231                                 total--;
232                                 clinitIndex = i;
233                                 break;
234                         }
235                 }
236         }
237         if (total == 0) {
238                 this.methods = NoMethods;
239                 return;
240         }
241
242         this.methods = new MethodBinding[total];
243         int next = 0;
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
248 }
249 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
250 *
251 * NOTE: enclosingType of a binary type is resolved when needed
252 */
253
254 public ReferenceBinding enclosingType() {
255         if (enclosingType == null)
256                 return null;
257         if (enclosingType instanceof UnresolvedReferenceBinding)
258                 enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
259         return enclosingType;
260 }
261 // NOTE: the type of each field of a binary type is resolved when needed
262
263 public FieldBinding[] fields() {
264         for (int i = fields.length; --i >= 0;)
265                 resolveTypeFor(fields[i]);
266         return fields;
267 }
268 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
269
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])
279                                         continue nextMethod;
280                         return method;
281                 }
282         }
283         return null;
284 }
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.
287
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])
301                                                 continue nextMethod;
302                                 return method;
303                         }
304                 }
305         }
306
307         if (foundNothing) {
308                 if (isInterface()) {
309                          if (superInterfaces.length == 1)
310                                 return superInterfaces[0].getExactMethod(selector, argumentTypes);
311                 } else if (superclass != null) {
312                         return superclass.getExactMethod(selector, argumentTypes);
313                 }
314         }
315         return null;
316 }
317 // NOTE: the type of a field of a binary type is resolved when needed
318
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]);
325         }
326         return null;
327 }
328 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
329
330 public MethodBinding[] getMethods(char[] selector) {
331         int count = 0;
332         int lastIndex = -1;
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);
338                         count++;
339                         lastIndex = m;
340                 }
341         }
342         if (count == 1)
343                 return new MethodBinding[] {methods[lastIndex]};
344         if (count > 0) {
345                 MethodBinding[] result = new MethodBinding[count];
346                 count = 0;
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;
351                 }
352                 return result;
353         }
354         return NoMethods;
355 }
356 // NOTE: member types of binary types are resolved when needed
357
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);
362         return memberTypes;
363 }
364 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
365
366 public MethodBinding[] methods() {
367         if ((modifiers & AccUnresolved) == 0)
368                 return methods;
369
370         for (int i = methods.length; --i >= 0;)
371                 resolveTypesFor(methods[i]);
372         modifiers ^= AccUnresolved;
373         return methods;
374 }
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);
382         }
383         return type;
384 }
385 private FieldBinding resolveTypeFor(FieldBinding field) {
386         field.type = resolveType(field.type);
387         return field;
388 }
389 private MethodBinding resolveTypesFor(MethodBinding method) {
390         if ((method.modifiers & AccUnresolved) == 0)
391                 return method;
392
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;
401         return method;
402 }
403 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
404 *
405 * NOTE: superclass of a binary type is resolved when needed
406 */
407
408 public ReferenceBinding superclass() {
409         if (superclass == null)
410                 return null;
411         if (superclass instanceof UnresolvedReferenceBinding)
412                 superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
413         return superclass;
414 }
415 // NOTE: superInterfaces of binary types are resolved when needed
416
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;
422 }
423 public String toString() {
424         String s = ""; //$NON-NLS-1$
425
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$
433
434         s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
435         s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
436
437         s += "\n\textends "; //$NON-NLS-1$
438         s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
439
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++) {
444                                 if (i  > 0)
445                                         s += ", "; //$NON-NLS-1$
446                                 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
447                         }
448                 }
449         } else {
450                 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
451         }
452
453         if (enclosingType != null) {
454                 s += "\n\tenclosing type : "; //$NON-NLS-1$
455                 s += enclosingType.debugName();
456         }
457
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$
463                 }
464         } else {
465                 s += "NULL FIELDS"; //$NON-NLS-1$
466         }
467
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$
473                 }
474         } else {
475                 s += "NULL METHODS"; //$NON-NLS-1$
476         }
477
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$
483                 }
484         } else {
485                 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
486         }
487
488         s += "\n\n\n"; //$NON-NLS-1$
489         return s;
490 }
491 }