Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / lookup / BinaryTypeBinding.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.lookup;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
15 import org.eclipse.jdt.internal.compiler.env.IBinaryField;
16 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
17 import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
18 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
19 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
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         if (binaryType.isAnonymous()) {
67                 this.tagBits |= AnonymousTypeMask;
68         } else if (binaryType.isLocal()) {
69                 this.tagBits |= LocalTypeMask;
70         } else if (binaryType.isMember()) {
71                 this.tagBits |= MemberTypeMask;
72         }
73 }
74
75 public FieldBinding[] availableFields() {
76         FieldBinding[] availableFields = new FieldBinding[fields.length];
77         int count = 0;
78         
79         for (int i = 0; i < fields.length;i++) {
80                 try {
81                         availableFields[count] = resolveTypeFor(fields[i]);
82                         count++;
83                 } catch (AbortCompilation a){
84                         // silent abort
85                 }
86         }
87         
88         System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count);
89         return availableFields;
90 }
91
92 public MethodBinding[] availableMethods() {
93         if ((modifiers & AccUnresolved) == 0)
94                 return methods;
95                 
96         MethodBinding[] availableMethods = new MethodBinding[methods.length];
97         int count = 0;
98         
99         for (int i = 0; i < methods.length;i++) {
100                 try {
101                         availableMethods[count] = resolveTypesFor(methods[i]);
102                         count++;
103                 } catch (AbortCompilation a){
104                         // silent abort
105                 }
106         }
107         System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count);
108         return availableMethods;
109 }
110
111 void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
112         
113         // default initialization for super-interfaces early, in case some aborting compilation error occurs,
114         // and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748).
115         this.superInterfaces = NoSuperInterfaces;
116         
117         char[] superclassName = binaryType.getSuperclassName();
118         if (superclassName != null)
119                 // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
120                 this.superclass = environment.getTypeFromConstantPoolName(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 (otherwise - resolve it when requested)
125                 this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1);
126                 this.tagBits |= MemberTypeMask;   // must be a member type not a top-level or local type
127                 if (this.enclosingType().isStrictfp())
128                         this.modifiers |= AccStrictfp;
129                 if (this.enclosingType().isDeprecated())
130                         this.modifiers |= AccDeprecatedImplicitly;
131         }
132
133         this.memberTypes = NoMemberTypes;
134         IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
135         if (memberTypeStructures != null) {
136                 int size = memberTypeStructures.length;
137                 if (size > 0) {
138                         this.memberTypes = new ReferenceBinding[size];
139                         for (int i = 0; i < size; i++)
140                                 // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested)
141                                 this.memberTypes[i] = environment.getTypeFromConstantPoolName(memberTypeStructures[i].getName(), 0, -1);
142                 }
143         }
144
145         char[][] interfaceNames = binaryType.getInterfaceNames();
146         if (interfaceNames != null) {
147                 int size = interfaceNames.length;
148                 if (size > 0) {
149                         this.superInterfaces = new ReferenceBinding[size];
150                         for (int i = 0; i < size; i++)
151                                 // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
152                                 this.superInterfaces[i] = environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1);
153                 }
154         }
155         if (needFieldsAndMethods) {
156                 createFields(binaryType.getFields());
157                 createMethods(binaryType.getMethods());
158         } else { // protect against incorrect use of the needFieldsAndMethods flag, see 48459
159                 this.fields = NoFields;
160                 this.methods = NoMethods;
161         }
162 }
163 private void createFields(IBinaryField[] iFields) {
164         this.fields = NoFields;
165         if (iFields != null) {
166                 int size = iFields.length;
167                 if (size > 0) {
168                         this.fields = new FieldBinding[size];
169                         for (int i = 0; i < size; i++) {
170                                 IBinaryField field = iFields[i];
171                                 this.fields[i] =
172                                         new FieldBinding(
173                                                 field.getName(),
174                                                 environment.getTypeFromSignature(field.getTypeName(), 0, -1),
175                                                 field.getModifiers() | AccUnresolved,
176                                                 this,
177                                                 field.getConstant());
178                         }
179                 }
180         }
181 }
182 private MethodBinding createMethod(IBinaryMethod method) {
183         int methodModifiers = method.getModifiers() | AccUnresolved;
184
185         ReferenceBinding[] exceptions = NoExceptions;
186         char[][] exceptionTypes = method.getExceptionTypeNames();
187         if (exceptionTypes != null) {
188                 int size = exceptionTypes.length;
189                 if (size > 0) {
190                         exceptions = new ReferenceBinding[size];
191                         for (int i = 0; i < size; i++)
192                                 exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1);
193                 }
194         }
195
196         TypeBinding[] parameters = NoParameters;
197         char[] methodSignature = method.getMethodDescriptor();   // of the form (I[Ljava/jang/String;)V
198         int numOfParams = 0;
199         char nextChar;
200         int index = 0;   // first character is always '(' so skip it
201         while ((nextChar = methodSignature[++index]) != ')') {
202                 if (nextChar != '[') {
203                         numOfParams++;
204                         if (nextChar == 'L')
205                                 while ((nextChar = methodSignature[++index]) != ';'){/*empty*/}
206                 }
207         }
208
209         // Ignore synthetic argument for member types.
210         int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
211         int size = numOfParams - startIndex;
212         if (size > 0) {
213                 parameters = new TypeBinding[size];
214                 index = 1;
215                 int end = 0;   // first character is always '(' so skip it
216                 for (int i = 0; i < numOfParams; i++) {
217                         while ((nextChar = methodSignature[++end]) == '['){/*empty*/}
218                         if (nextChar == 'L')
219                                 while ((nextChar = methodSignature[++end]) != ';'){/*empty*/}
220
221                         if (i >= startIndex)   // skip the synthetic arg if necessary
222                                 parameters[i - startIndex] = environment.getTypeFromSignature(methodSignature, index, end);
223                         index = end + 1;
224                 }
225         }
226
227         MethodBinding binding = null;
228         if (method.isConstructor())
229                 binding = new MethodBinding(methodModifiers, parameters, exceptions, this);
230         else
231                 binding = new MethodBinding(
232                         methodModifiers,
233                         method.getSelector(),
234                         environment.getTypeFromSignature(methodSignature, index + 1, -1),   // index is currently pointing at the ')'
235                         parameters,
236                         exceptions,
237                         this);
238         return binding;
239 }
240 /**
241  * Create method bindings for binary type, filtering out <clinit> and synthetics
242  */
243 private void createMethods(IBinaryMethod[] iMethods) {
244         int total = 0, initialTotal = 0, iClinit = -1;
245         int[] toSkip = null;
246         if (iMethods != null) {
247                 total = initialTotal = iMethods.length;
248                 for (int i = total; --i >= 0;) {
249                         IBinaryMethod method = iMethods[i];
250                         if ((method.getModifiers() & AccSynthetic) != 0) {
251                                 // discard synthetics methods
252                                 if (toSkip == null) toSkip = new int[iMethods.length];
253                                 toSkip[i] = -1;
254                                 total--;
255                         } else if (iClinit == -1) {
256                                 char[] methodName = method.getSelector();
257                                 if (methodName.length == 8 && methodName[0] == '<') {
258                                         // discard <clinit>
259                                         iClinit = i;
260                                         total--;
261                                 }
262                         }
263                 }
264         }
265         if (total == 0) {
266                 this.methods = NoMethods;
267                 return;
268         }
269
270         this.methods = new MethodBinding[total];
271         if (total == initialTotal) {
272                 for (int i = 0; i < initialTotal; i++)
273                         this.methods[i] = createMethod(iMethods[i]);
274         } else {
275                 for (int i = 0, index = 0; i < initialTotal; i++)
276                         if (iClinit != i && (toSkip == null || toSkip[i] != -1))
277                                 this.methods[index++] = createMethod(iMethods[i]);
278         }
279         modifiers |= AccUnresolved; // until methods() is sent
280 }
281 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
282 *
283 * NOTE: enclosingType of a binary type is resolved when needed
284 */
285
286 public ReferenceBinding enclosingType() {
287         if (enclosingType == null)
288                 return null;
289         if (enclosingType instanceof UnresolvedReferenceBinding)
290                 enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
291         return enclosingType;
292 }
293 // NOTE: the type of each field of a binary type is resolved when needed
294
295 public FieldBinding[] fields() {
296         for (int i = fields.length; --i >= 0;)
297                 resolveTypeFor(fields[i]);
298         return fields;
299 }
300 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
301
302 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
303         int argCount = argumentTypes.length;
304         nextMethod : for (int m = methods.length; --m >= 0;) {
305                 MethodBinding method = methods[m];
306                 if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) {
307                         resolveTypesFor(method);
308                         TypeBinding[] toMatch = method.parameters;
309                         for (int p = 0; p < argCount; p++)
310                                 if (toMatch[p] != argumentTypes[p])
311                                         continue nextMethod;
312                         return method;
313                 }
314         }
315         return null;
316 }
317 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
318 // searches up the hierarchy as long as no potential (but not exact) match was found.
319
320 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) {
321         int argCount = argumentTypes.length;
322         int selectorLength = selector.length;
323         boolean foundNothing = true;
324         nextMethod : for (int m = methods.length; --m >= 0;) {
325                 MethodBinding method = methods[m];
326                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
327                         foundNothing = false; // inner type lookups must know that a method with this name exists
328                         if (method.parameters.length == argCount) {
329                                 resolveTypesFor(method);
330                                 TypeBinding[] toMatch = method.parameters;
331                                 for (int p = 0; p < argCount; p++)
332                                         if (toMatch[p] != argumentTypes[p])
333                                                 continue nextMethod;
334                                 return method;
335                         }
336                 }
337         }
338
339         if (foundNothing) {
340                 if (isInterface()) {
341                          if (superInterfaces.length == 1)
342                                 return superInterfaces[0].getExactMethod(selector, argumentTypes);
343                 } else if (superclass != null) {
344                         return superclass.getExactMethod(selector, argumentTypes);
345                 }
346         }
347         return null;
348 }
349 // NOTE: the type of a field of a binary type is resolved when needed
350
351 public FieldBinding getField(char[] fieldName, boolean needResolve) {
352         int fieldLength = fieldName.length;
353         for (int f = fields.length; --f >= 0;) {
354                 char[] name = fields[f].name;
355                 if (name.length == fieldLength && CharOperation.equals(name, fieldName))
356                         return needResolve ? resolveTypeFor(fields[f]) : fields[f];
357         }
358         return null;
359 }
360 /**
361  *  Rewrite of default getMemberType to avoid resolving eagerly all member types when one is requested
362  */
363 public ReferenceBinding getMemberType(char[] typeName) {
364         for (int i = this.memberTypes.length; --i >= 0;) {
365             ReferenceBinding memberType = this.memberTypes[i];
366             if (memberType instanceof UnresolvedReferenceBinding) {
367                         char[] name = memberType.sourceName; // source name is qualified with enclosing type name
368                         int prefixLength = this.compoundName[this.compoundName.length - 1].length + 1; // enclosing$
369                         if (name.length == (prefixLength + typeName.length)) // enclosing $ typeName
370                                 if (CharOperation.fragmentEquals(typeName, name, prefixLength, true)) // only check trailing portion
371                                         return this.memberTypes[i] = ((UnresolvedReferenceBinding) memberType).resolve(environment);
372             } else if (CharOperation.equals(typeName, memberType.sourceName)) {
373                 return memberType;
374             }
375         }
376         return null;
377 }
378 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
379
380 public MethodBinding[] getMethods(char[] selector) {
381         int count = 0;
382         int lastIndex = -1;
383         int selectorLength = selector.length;
384         for (int m = 0, length = methods.length; m < length; m++) {
385                 MethodBinding method = methods[m];
386                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
387                         resolveTypesFor(method);
388                         count++;
389                         lastIndex = m;
390                 }
391         }
392         if (count == 1)
393                 return new MethodBinding[] {methods[lastIndex]};
394         if (count > 0) {
395                 MethodBinding[] result = new MethodBinding[count];
396                 count = 0;
397                 for (int m = 0; m <= lastIndex; m++) {
398                         MethodBinding method = methods[m];
399                         if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector))
400                                 result[count++] = method;
401                 }
402                 return result;
403         }
404         return NoMethods;
405 }
406 public boolean hasMemberTypes() {
407     return this.memberTypes.length > 0;
408 }
409 // NOTE: member types of binary types are resolved when needed
410
411 public ReferenceBinding[] memberTypes() {
412         for (int i = memberTypes.length; --i >= 0;)
413                 if (memberTypes[i] instanceof UnresolvedReferenceBinding)
414                         memberTypes[i] = ((UnresolvedReferenceBinding) memberTypes[i]).resolve(environment);
415         return memberTypes;
416 }
417 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
418
419 public MethodBinding[] methods() {
420         if ((modifiers & AccUnresolved) == 0)
421                 return methods;
422
423         for (int i = methods.length; --i >= 0;)
424                 resolveTypesFor(methods[i]);
425         modifiers ^= AccUnresolved;
426         return methods;
427 }
428 TypeBinding resolveType(TypeBinding type) {
429         if (type instanceof UnresolvedReferenceBinding)
430                 return ((UnresolvedReferenceBinding) type).resolve(environment);
431         if (type instanceof ArrayBinding) {
432                 ArrayBinding array = (ArrayBinding) type;
433                 if (array.leafComponentType instanceof UnresolvedReferenceBinding)
434                         array.leafComponentType = ((UnresolvedReferenceBinding) array.leafComponentType).resolve(environment);
435         }
436         return type;
437 }
438 private FieldBinding resolveTypeFor(FieldBinding field) {
439         if ((field.modifiers & AccUnresolved) != 0) {
440                 field.type = resolveType(field.type);
441                 field.modifiers ^= AccUnresolved;
442         }
443         return field;
444 }
445 private MethodBinding resolveTypesFor(MethodBinding method) {
446         if ((method.modifiers & AccUnresolved) == 0)
447                 return method;
448
449         if (!method.isConstructor())
450                 method.returnType = resolveType(method.returnType);
451         for (int i = method.parameters.length; --i >= 0;)
452                 method.parameters[i] = resolveType(method.parameters[i]);
453         for (int i = method.thrownExceptions.length; --i >= 0;)
454                 if (method.thrownExceptions[i] instanceof UnresolvedReferenceBinding)
455                         method.thrownExceptions[i] = ((UnresolvedReferenceBinding) method.thrownExceptions[i]).resolve(environment);
456         method.modifiers ^= AccUnresolved;
457         return method;
458 }
459 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
460 *
461 * NOTE: superclass of a binary type is resolved when needed
462 */
463
464 public ReferenceBinding superclass() {
465         if (superclass == null)
466                 return null;
467         if (superclass instanceof UnresolvedReferenceBinding)
468                 superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
469         return superclass;
470 }
471 // NOTE: superInterfaces of binary types are resolved when needed
472
473 public ReferenceBinding[] superInterfaces() {
474         for (int i = superInterfaces.length; --i >= 0;)
475                 if (superInterfaces[i] instanceof UnresolvedReferenceBinding)
476                         superInterfaces[i] = ((UnresolvedReferenceBinding) superInterfaces[i]).resolve(environment);
477         return superInterfaces;
478 }
479 MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
480         return methods;
481 }
482 public String toString() {
483         String s = ""; //$NON-NLS-1$
484
485         if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$
486         if (isPublic()) s += "public "; //$NON-NLS-1$
487         if (isProtected()) s += "protected "; //$NON-NLS-1$
488         if (isPrivate()) s += "private "; //$NON-NLS-1$
489         if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$
490         if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$
491         if (isFinal()) s += "final "; //$NON-NLS-1$
492
493         s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
494         s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
495
496         s += "\n\textends "; //$NON-NLS-1$
497         s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
498
499         if (superInterfaces != null) {
500                 if (superInterfaces != NoSuperInterfaces) {
501                         s += "\n\timplements : "; //$NON-NLS-1$
502                         for (int i = 0, length = superInterfaces.length; i < length; i++) {
503                                 if (i  > 0)
504                                         s += ", "; //$NON-NLS-1$
505                                 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
506                         }
507                 }
508         } else {
509                 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
510         }
511
512         if (enclosingType != null) {
513                 s += "\n\tenclosing type : "; //$NON-NLS-1$
514                 s += enclosingType.debugName();
515         }
516
517         if (fields != null) {
518                 if (fields != NoFields) {
519                         s += "\n/*   fields   */"; //$NON-NLS-1$
520                         for (int i = 0, length = fields.length; i < length; i++)
521                                 s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
522                 }
523         } else {
524                 s += "NULL FIELDS"; //$NON-NLS-1$
525         }
526
527         if (methods != null) {
528                 if (methods != NoMethods) {
529                         s += "\n/*   methods   */"; //$NON-NLS-1$
530                         for (int i = 0, length = methods.length; i < length; i++)
531                                 s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
532                 }
533         } else {
534                 s += "NULL METHODS"; //$NON-NLS-1$
535         }
536
537         if (memberTypes != null) {
538                 if (memberTypes != NoMemberTypes) {
539                         s += "\n/*   members   */"; //$NON-NLS-1$
540                         for (int i = 0, length = memberTypes.length; i < length; i++)
541                                 s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
542                 }
543         } else {
544                 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
545         }
546
547         s += "\n\n\n"; //$NON-NLS-1$
548         return s;
549 }
550 }