A massive organize imports and formatting of the sources using default Eclipse code...
[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.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;
20
21 /*
22  * Not all fields defined by this type are initialized when it is created. Some
23  * are initialized only when needed.
24  * 
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.
29  * 
30  * null is NOT a valid value for a non-public field... it just means the field
31  * is not initialized.
32  */
33
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;
38
39         private ReferenceBinding enclosingType;
40
41         private ReferenceBinding[] superInterfaces;
42
43         private FieldBinding[] fields;
44
45         private MethodBinding[] methods;
46
47         private ReferenceBinding[] memberTypes;
48
49         // For the link with the principle structure
50         private LookupEnvironment environment;
51
52         public BinaryTypeBinding(PackageBinding packageBinding,
53                         IBinaryType binaryType, LookupEnvironment environment) {
54                 this.compoundName = CharOperation.splitOn('/', binaryType.getName());
55                 // computeId();
56
57                 this.tagBits |= IsBinaryBinding;
58                 this.environment = environment;
59                 this.fPackage = packageBinding;
60                 this.fileName = binaryType.getFileName();
61
62                 // source name must be one name without "$".
63                 char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
64                 int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
65                 if (start == 0) {
66                         this.sourceName = possibleSourceName;
67                 } else {
68                         this.sourceName = new char[possibleSourceName.length - start];
69                         System.arraycopy(possibleSourceName, start, this.sourceName, 0,
70                                         this.sourceName.length);
71                 }
72
73                 this.modifiers = binaryType.getModifiers();
74                 if (binaryType.isInterface())
75                         this.modifiers |= AccInterface;
76         }
77
78         public FieldBinding[] availableFields() {
79                 FieldBinding[] availableFields = new FieldBinding[fields.length];
80                 int count = 0;
81
82                 for (int i = 0; i < fields.length; i++) {
83                         try {
84                                 availableFields[count] = resolveTypeFor(fields[i]);
85                                 count++;
86                         } catch (AbortCompilation a) {
87                         }
88                 }
89
90                 System.arraycopy(availableFields, 0,
91                                 availableFields = new FieldBinding[count], 0, count);
92                 return availableFields;
93         }
94
95         public MethodBinding[] availableMethods() {
96                 if ((modifiers & AccUnresolved) == 0)
97                         return methods;
98
99                 MethodBinding[] availableMethods = new MethodBinding[methods.length];
100                 int count = 0;
101
102                 for (int i = 0; i < methods.length; i++) {
103                         try {
104                                 availableMethods[count] = resolveTypesFor(methods[i]);
105                                 count++;
106                         } catch (AbortCompilation a) {
107                         }
108                 }
109                 System.arraycopy(availableMethods, 0,
110                                 availableMethods = new MethodBinding[count], 0, count);
111                 return availableMethods;
112         }
113
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);
121
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;
134                 }
135
136                 this.memberTypes = NoMemberTypes;
137                 IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
138                 if (memberTypeStructures != null) {
139                         int size = memberTypeStructures.length;
140                         if (size > 0) {
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);
148                         }
149                 }
150
151                 this.superInterfaces = NoSuperInterfaces;
152                 char[][] interfaceNames = binaryType.getInterfaceNames();
153                 if (interfaceNames != null) {
154                         int size = interfaceNames.length;
155                         if (size > 0) {
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,
162                                                                         -1);
163                         }
164                 }
165                 if (needFieldsAndMethods) {
166                         createFields(binaryType.getFields());
167                         createMethods(binaryType.getMethods());
168                 }
169         }
170
171         private void createFields(IBinaryField[] iFields) {
172                 this.fields = NoFields;
173                 if (iFields != null) {
174                         int size = iFields.length;
175                         if (size > 0) {
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());
183                                 }
184                         }
185                 }
186         }
187
188         private MethodBinding createMethod(IBinaryMethod method) {
189                 int modifiers = method.getModifiers() | AccUnresolved;
190
191                 ReferenceBinding[] exceptions = NoExceptions;
192                 char[][] exceptionTypes = method.getExceptionTypeNames();
193                 if (exceptionTypes != null) {
194                         int size = exceptionTypes.length;
195                         if (size > 0) {
196                                 exceptions = new ReferenceBinding[size];
197                                 for (int i = 0; i < size; i++)
198                                         exceptions[i] = environment.getTypeFromConstantPoolName(
199                                                         exceptionTypes[i], 0, -1);
200                         }
201                 }
202
203                 TypeBinding[] parameters = NoParameters;
204                 char[] signature = method.getMethodDescriptor(); // of the form
205                                                                                                                         // (I[Ljava/jang/String;)V
206                 int numOfParams = 0;
207                 char nextChar;
208                 int index = 0; // first character is always '(' so skip it
209                 while ((nextChar = signature[++index]) != ')') {
210                         if (nextChar != '[') {
211                                 numOfParams++;
212                                 if (nextChar == 'L')
213                                         while ((nextChar = signature[++index]) != ';')
214                                                 ;
215                         }
216                 }
217
218                 // Ignore synthetic argument for member types.
219                 int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1
220                                 : 0;
221                 int size = numOfParams - startIndex;
222                 if (size > 0) {
223                         parameters = new TypeBinding[size];
224                         index = 1;
225                         int end = 0; // first character is always '(' so skip it
226                         for (int i = 0; i < numOfParams; i++) {
227                                 while ((nextChar = signature[++end]) == '[')
228                                         ;
229                                 if (nextChar == 'L')
230                                         while ((nextChar = signature[++end]) != ';')
231                                                 ;
232
233                                 if (i >= startIndex) // skip the synthetic arg if necessary
234                                         parameters[i - startIndex] = environment
235                                                         .getTypeFromSignature(signature, index, end);
236                                 index = end + 1;
237                         }
238                 }
239
240                 MethodBinding binding = null;
241                 if (method.isConstructor())
242                         binding = new MethodBinding(modifiers, parameters, exceptions, this);
243                 else
244                         binding = new MethodBinding(modifiers, method.getSelector(),
245                                         environment.getTypeFromSignature(signature, index + 1, -1), // index
246                                                                                                                                                                 // is
247                                                                                                                                                                 // currently
248                                                                                                                                                                 // pointing
249                                                                                                                                                                 // at
250                                                                                                                                                                 // the
251                                                                                                                                                                 // ')'
252                                         parameters, exceptions, this);
253                 return binding;
254         }
255
256         /**
257          * Create method bindings for binary type, filtering out <clinit> and
258          * synthetics
259          */
260         private void createMethods(IBinaryMethod[] iMethods) {
261                 int total = 0, initialTotal = 0, iClinit = -1;
262                 int[] toSkip = null;
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];
270                                 // toSkip[i] = -1;
271                                 // total--;
272                                 // } else
273                                 if (iClinit == -1) {
274                                         char[] methodName = method.getSelector();
275                                         if (methodName.length == 8 && methodName[0] == '<') {
276                                                 // discard <clinit>
277                                                 iClinit = i;
278                                                 total--;
279                                         }
280                                 }
281                         }
282                 }
283                 if (total == 0) {
284                         this.methods = NoMethods;
285                         return;
286                 }
287
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]);
292                 } else {
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]);
296                 }
297                 modifiers |= AccUnresolved; // until methods() is sent
298         }
299
300         /*
301          * Answer the receiver's enclosing type... null if the receiver is a top
302          * level type.
303          * 
304          * NOTE: enclosingType of a binary type is resolved when needed
305          */
306
307         public ReferenceBinding enclosingType() {
308                 if (enclosingType == null)
309                         return null;
310                 if (enclosingType instanceof UnresolvedReferenceBinding)
311                         enclosingType = ((UnresolvedReferenceBinding) enclosingType)
312                                         .resolve(environment);
313                 return enclosingType;
314         }
315
316         // NOTE: the type of each field of a binary type is resolved when needed
317
318         public FieldBinding[] fields() {
319                 for (int i = fields.length; --i >= 0;)
320                         resolveTypeFor(fields[i]);
321                 return fields;
322         }
323
324         // NOTE: the return type, arg & exception types of each method of a binary
325         // type are resolved when needed
326
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])
337                                                 continue nextMethod;
338                                 return method;
339                         }
340                 }
341                 return null;
342         }
343
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
347         // was found.
348
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])
365                                                         continue nextMethod;
366                                         return method;
367                                 }
368                         }
369                 }
370
371                 if (foundNothing) {
372                         if (isInterface()) {
373                                 if (superInterfaces.length == 1)
374                                         return superInterfaces[0].getExactMethod(selector,
375                                                         argumentTypes);
376                         } else if (superclass != null) {
377                                 return superclass.getExactMethod(selector, argumentTypes);
378                         }
379                 }
380                 return null;
381         }
382
383         // NOTE: the type of a field of a binary type is resolved when needed
384
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]);
392                 }
393                 return null;
394         }
395
396         // NOTE: the return type, arg & exception types of each method of a binary
397         // type are resolved when needed
398
399         public MethodBinding[] getMethods(char[] selector) {
400                 int count = 0;
401                 int lastIndex = -1;
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);
408                                 count++;
409                                 lastIndex = m;
410                         }
411                 }
412                 if (count == 1)
413                         return new MethodBinding[] { methods[lastIndex] };
414                 if (count > 0) {
415                         MethodBinding[] result = new MethodBinding[count];
416                         count = 0;
417                         for (int m = 0; m <= lastIndex; m++) {
418                                 MethodBinding method = methods[m];
419                                 if (method.selector.length == selectorLength
420                                                 && CharOperation
421                                                                 .prefixEquals(method.selector, selector))
422                                         result[count++] = method;
423                         }
424                         return result;
425                 }
426                 return NoMethods;
427         }
428
429         // NOTE: member types of binary types are resolved when needed
430
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);
436                 return memberTypes;
437         }
438
439         // NOTE: the return type, arg & exception types of each method of a binary
440         // type are resolved when needed
441
442         public MethodBinding[] methods() {
443                 if ((modifiers & AccUnresolved) == 0)
444                         return methods;
445
446                 for (int i = methods.length; --i >= 0;)
447                         resolveTypesFor(methods[i]);
448                 modifiers ^= AccUnresolved;
449                 return methods;
450         }
451
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);
460                 }
461                 return type;
462         }
463
464         private FieldBinding resolveTypeFor(FieldBinding field) {
465                 field.type = resolveType(field.type);
466                 return field;
467         }
468
469         private MethodBinding resolveTypesFor(MethodBinding method) {
470                 if ((method.modifiers & AccUnresolved) == 0)
471                         return method;
472
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;
482                 return method;
483         }
484
485         /*
486          * Answer the receiver's superclass... null if the receiver is Object or an
487          * interface.
488          * 
489          * NOTE: superclass of a binary type is resolved when needed
490          */
491
492         public ReferenceBinding superclass() {
493                 if (superclass == null)
494                         return null;
495                 if (superclass instanceof UnresolvedReferenceBinding)
496                         superclass = ((UnresolvedReferenceBinding) superclass)
497                                         .resolve(environment);
498                 return superclass;
499         }
500
501         // NOTE: superInterfaces of binary types are resolved when needed
502
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;
509         }
510
511         public String toString() {
512                 String s = ""; //$NON-NLS-1$
513
514                 if (isDeprecated())
515                         s += "deprecated "; //$NON-NLS-1$
516                 if (isPublic())
517                         s += "public "; //$NON-NLS-1$
518                 if (isProtected())
519                         s += "protected "; //$NON-NLS-1$
520                 if (isPrivate())
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$
526                 if (isFinal())
527                         s += "final "; //$NON-NLS-1$
528
529                 s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
530                 s += (compoundName != null) ? CharOperation.toString(compoundName)
531                                 : "UNNAMED TYPE"; //$NON-NLS-1$
532
533                 s += "\n\textends "; //$NON-NLS-1$
534                 s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
535
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++) {
540                                         if (i > 0)
541                                                 s += ", "; //$NON-NLS-1$
542                                         s += (superInterfaces[i] != null) ? superInterfaces[i]
543                                                         .debugName() : "NULL TYPE"; //$NON-NLS-1$
544                                 }
545                         }
546                 } else {
547                         s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
548                 }
549
550                 if (enclosingType != null) {
551                         s += "\n\tenclosing type : "; //$NON-NLS-1$
552                         s += enclosingType.debugName();
553                 }
554
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$
560                         }
561                 } else {
562                         s += "NULL FIELDS"; //$NON-NLS-1$
563                 }
564
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$
570                         }
571                 } else {
572                         s += "NULL METHODS"; //$NON-NLS-1$
573                 }
574
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$
580                         }
581                 } else {
582                         s += "NULL MEMBER TYPES"; //$NON-NLS-1$
583                 }
584
585                 s += "\n\n\n"; //$NON-NLS-1$
586                 return s;
587         }
588 }