added -J option to preserve unmodified files in preexisting jarfile
[org.ibex.tool.git] / 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 java.util.ArrayList;
14
15 import org.eclipse.jdt.core.compiler.CharOperation;
16 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
17 import org.eclipse.jdt.internal.compiler.env.IBinaryField;
18 import org.eclipse.jdt.internal.compiler.env.IBinaryMethod;
19 import org.eclipse.jdt.internal.compiler.env.IBinaryNestedType;
20 import org.eclipse.jdt.internal.compiler.env.IBinaryType;
21 import org.eclipse.jdt.internal.compiler.env.IGenericType;
22 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
23
24 /*
25 Not all fields defined by this type are initialized when it is created.
26 Some are initialized only when needed.
27
28 Accessors have been provided for some public fields so all TypeBindings have the same API...
29 but access public fields directly whenever possible.
30 Non-public fields have accessors which should be used everywhere you expect the field to be initialized.
31
32 null is NOT a valid value for a non-public field... it just means the field is not initialized.
33 */
34
35 public final class BinaryTypeBinding extends ReferenceBinding {
36
37 // all of these fields are ONLY guaranteed to be initialized if accessed using their public accessor method
38 private ReferenceBinding superclass;
39 private ReferenceBinding enclosingType;
40 private ReferenceBinding[] superInterfaces;
41 private FieldBinding[] fields;
42 private MethodBinding[] methods;
43 private ReferenceBinding[] memberTypes;
44 protected TypeVariableBinding[] typeVariables;
45
46 // For the link with the principle structure
47 private LookupEnvironment environment;
48
49 public static ReferenceBinding resolveType(ReferenceBinding type, LookupEnvironment environment, boolean convertGenericToRawType) {
50         if (type instanceof UnresolvedReferenceBinding)
51                 return ((UnresolvedReferenceBinding) type).resolve(environment, convertGenericToRawType);
52         if (type.isParameterizedType())
53                 return ((ParameterizedTypeBinding) type).resolve();
54         if (type.isWildcard())
55                 return ((WildcardBinding) type).resolve();
56
57         if (convertGenericToRawType && type.isGenericType()) // raw reference to generic ?
58             return environment.createRawType(type, type.enclosingType());
59         return type;
60 }
61 public static TypeBinding resolveType(TypeBinding type, LookupEnvironment environment, ParameterizedTypeBinding parameterizedType, int rank) {
62         switch (type.kind()) {
63                 
64                 case Binding.PARAMETERIZED_TYPE :
65                         return ((ParameterizedTypeBinding) type).resolve();
66                         
67                 case Binding.WILDCARD_TYPE :
68                         return ((WildcardBinding) type).resolve();
69                         
70                 case Binding.ARRAY_TYPE :
71                         resolveType(((ArrayBinding) type).leafComponentType, environment, parameterizedType, rank);
72                         break;
73                         
74                 case Binding.TYPE_PARAMETER :
75                         ((TypeVariableBinding) type).resolve(environment);
76                         break;
77                                                 
78                 case Binding.GENERIC_TYPE :
79                         if (parameterizedType == null) // raw reference to generic ?
80                             return environment.createRawType((ReferenceBinding) type, type.enclosingType());
81                         break;
82                         
83                 default:                        
84                         if (type instanceof UnresolvedReferenceBinding)
85                                 return ((UnresolvedReferenceBinding) type).resolve(environment, parameterizedType == null);
86         }
87         return type;
88 }
89 // resolve hierarchy types in 2 steps by first resolving any UnresolvedTypes
90 static ReferenceBinding resolveUnresolvedType(ReferenceBinding type, LookupEnvironment environment, boolean convertGenericToRawType) {
91         if (type instanceof UnresolvedReferenceBinding)
92                 return ((UnresolvedReferenceBinding) type).resolve(environment, convertGenericToRawType);
93
94         if (type.isParameterizedType())
95                 resolveUnresolvedType(((ParameterizedTypeBinding) type).type, environment, false); // still part of parameterized type ref
96         else if (type.isWildcard())
97                 resolveType(((WildcardBinding) type).genericType, environment, null, 0);
98         return type;
99 }
100
101
102 public BinaryTypeBinding(PackageBinding packageBinding, IBinaryType binaryType, LookupEnvironment environment) {
103         this.compoundName = CharOperation.splitOn('/', binaryType.getName());
104         computeId();
105
106         this.tagBits |= IsBinaryBinding;
107         this.environment = environment;
108         this.fPackage = packageBinding;
109         this.fileName = binaryType.getFileName();
110
111         char[] typeSignature = environment.options.sourceLevel >= ClassFileConstants.JDK1_5 ? binaryType.getGenericSignature() : null;
112         this.typeVariables = typeSignature != null && typeSignature.length > 0 && typeSignature[0] == '<'
113                 ? null // is initialized in cachePartsFrom (called from LookupEnvironment.createBinaryTypeFrom())... must set to null so isGenericType() answers true
114                 : NoTypeVariables;
115
116         // source name must be one name without "$".
117         char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
118         int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
119         if (start == 0) {
120                 this.sourceName = possibleSourceName;
121         } else {
122                 this.sourceName = new char[possibleSourceName.length - start];
123                 System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length);
124         }
125
126         this.modifiers = binaryType.getModifiers();
127         if (binaryType.getKind() == IGenericType.INTERFACE_DECL)
128                 this.modifiers |= AccInterface;
129                 
130         if (binaryType.isAnonymous()) {
131                 this.tagBits |= AnonymousTypeMask;
132         } else if (binaryType.isLocal()) {
133                 this.tagBits |= LocalTypeMask;
134         } else if (binaryType.isMember()) {
135                 this.tagBits |= MemberTypeMask;
136         }
137 }
138
139 public FieldBinding[] availableFields() {
140         FieldBinding[] availableFields = new FieldBinding[fields.length];
141         int count = 0;
142         
143         for (int i = 0; i < fields.length;i++) {
144                 try {
145                         availableFields[count] = resolveTypeFor(fields[i]);
146                         count++;
147                 } catch (AbortCompilation a){
148                         // silent abort
149                 }
150         }
151         
152         System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count);
153         return availableFields;
154 }
155
156 public MethodBinding[] availableMethods() {
157         if ((modifiers & AccUnresolved) == 0)
158                 return methods;
159                 
160         MethodBinding[] availableMethods = new MethodBinding[methods.length];
161         int count = 0;
162         
163         for (int i = 0; i < methods.length;i++) {
164                 try {
165                         availableMethods[count] = resolveTypesFor(methods[i]);
166                         count++;
167                 } catch (AbortCompilation a){
168                         // silent abort
169                 }
170         }
171         System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count);
172         return availableMethods;
173 }
174
175 public int kind() {
176         if (this.typeVariables != NoTypeVariables) return Binding.GENERIC_TYPE;
177         return Binding.TYPE;
178 }       
179
180 void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
181         // default initialization for super-interfaces early, in case some aborting compilation error occurs,
182         // and still want to use binaries passed that point (e.g. type hierarchy resolver, see bug 63748).
183         this.typeVariables = NoTypeVariables;
184         this.superInterfaces = NoSuperInterfaces;
185
186         // need enclosing type to access type variables
187         char[] enclosingTypeName = binaryType.getEnclosingTypeName();
188         if (enclosingTypeName != null) {
189                 // attempt to find the enclosing type if it exists in the cache (otherwise - resolve it when requested)
190                 this.enclosingType = environment.getTypeFromConstantPoolName(enclosingTypeName, 0, -1, true); // pretend parameterized to avoid raw
191                 this.tagBits |= MemberTypeMask;   // must be a member type not a top-level or local type
192                 this.tagBits |=         HasUnresolvedEnclosingType;
193                 if (this.enclosingType().isStrictfp())
194                         this.modifiers |= AccStrictfp;
195                 if (this.enclosingType().isDeprecated())
196                         this.modifiers |= AccDeprecatedImplicitly;
197         }
198
199         long sourceLevel = environment.options.sourceLevel;
200         char[] typeSignature = null;
201         if (sourceLevel >= ClassFileConstants.JDK1_5) {
202                 typeSignature = binaryType.getGenericSignature();
203                 this.tagBits |= binaryType.getTagBits();
204         }
205         if (typeSignature == null) {
206                 char[] superclassName = binaryType.getSuperclassName();
207                 if (superclassName != null) {
208                         // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
209                         this.superclass = environment.getTypeFromConstantPoolName(superclassName, 0, -1, false);
210                         this.tagBits |=         HasUnresolvedSuperclass;
211                 }
212
213                 this.superInterfaces = NoSuperInterfaces;
214                 char[][] interfaceNames = binaryType.getInterfaceNames();
215                 if (interfaceNames != null) {
216                         int size = interfaceNames.length;
217                         if (size > 0) {
218                                 this.superInterfaces = new ReferenceBinding[size];
219                                 for (int i = 0; i < size; i++)
220                                         // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
221                                         this.superInterfaces[i] = environment.getTypeFromConstantPoolName(interfaceNames[i], 0, -1, false);
222                                 this.tagBits |=         HasUnresolvedSuperinterfaces;
223                         }
224                 }
225         } else {
226                 // ClassSignature = ParameterPart(optional) super_TypeSignature interface_signature
227                 SignatureWrapper wrapper = new SignatureWrapper(typeSignature);
228                 if (wrapper.signature[wrapper.start] == '<') {
229                         // ParameterPart = '<' ParameterSignature(s) '>'
230                         wrapper.start++; // skip '<'
231                         this.typeVariables = createTypeVariables(wrapper, this);
232                         wrapper.start++; // skip '>'
233                         this.tagBits |=  HasUnresolvedTypeVariables;
234                         this.modifiers |= AccGenericSignature;
235                 }
236
237                 // attempt to find the superclass if it exists in the cache (otherwise - resolve it when requested)
238                 this.superclass = (ReferenceBinding) environment.getTypeFromTypeSignature(wrapper, NoTypeVariables, this);
239                 this.tagBits |=         HasUnresolvedSuperclass;
240
241                 this.superInterfaces = NoSuperInterfaces;
242                 if (!wrapper.atEnd()) {
243                         // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
244                         java.util.ArrayList types = new java.util.ArrayList(2);
245                         do {
246                                 types.add(environment.getTypeFromTypeSignature(wrapper, NoTypeVariables, this));
247                         } while (!wrapper.atEnd());
248                         this.superInterfaces = new ReferenceBinding[types.size()];
249                         types.toArray(this.superInterfaces);
250                         this.tagBits |=         HasUnresolvedSuperinterfaces;
251                 }
252         }
253
254         this.memberTypes = NoMemberTypes;
255         IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
256         if (memberTypeStructures != null) {
257                 int size = memberTypeStructures.length;
258                 if (size > 0) {
259                         this.memberTypes = new ReferenceBinding[size];
260                         for (int i = 0; i < size; i++)
261                                 // attempt to find each member type if it exists in the cache (otherwise - resolve it when requested)
262                                 this.memberTypes[i] = environment.getTypeFromConstantPoolName(memberTypeStructures[i].getName(), 0, -1, false);
263                         this.tagBits |=         HasUnresolvedMemberTypes;
264                 }
265         }
266
267         if (needFieldsAndMethods) {
268                 createFields(binaryType.getFields(), sourceLevel);
269                 createMethods(binaryType.getMethods(), sourceLevel);
270         } else { // protect against incorrect use of the needFieldsAndMethods flag, see 48459
271                 this.fields = NoFields;
272                 this.methods = NoMethods;
273         }
274 }
275 private void createFields(IBinaryField[] iFields, long sourceLevel) {
276         this.fields = NoFields;
277         if (iFields != null) {
278                 int size = iFields.length;
279                 if (size > 0) {
280                         this.fields = new FieldBinding[size];
281                         boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5;
282                         for (int i = 0; i < size; i++) {
283                                 IBinaryField binaryField = iFields[i];
284                                 char[] fieldSignature = use15specifics ? binaryField.getGenericSignature() : null;
285                                 TypeBinding type = fieldSignature == null
286                                         ? environment.getTypeFromSignature(binaryField.getTypeName(), 0, -1, false, this)
287                                         : environment.getTypeFromTypeSignature(new SignatureWrapper(fieldSignature), NoTypeVariables, this);
288                                 FieldBinding field =
289                                         new FieldBinding(
290                                                 binaryField.getName(),
291                                                 type,
292                                                 binaryField.getModifiers() | AccUnresolved,
293                                                 this,
294                                                 binaryField.getConstant());
295                                 field.id = i; // ordinal
296                                 if (use15specifics) {
297                                         field.tagBits |= binaryField.getTagBits();
298                                 }
299                                 this.fields[i] = field;
300
301                         }
302                 }
303         }
304 }
305 private MethodBinding createMethod(IBinaryMethod method, long sourceLevel) {
306         int methodModifiers = method.getModifiers() | AccUnresolved;
307         if (sourceLevel < ClassFileConstants.JDK1_5)
308                 methodModifiers &= ~AccVarargs; // vararg methods are not recognized until 1.5
309         ReferenceBinding[] exceptions = NoExceptions;
310         TypeBinding[] parameters = NoParameters;
311         TypeVariableBinding[] typeVars = NoTypeVariables;
312         TypeBinding returnType = null;
313
314         final boolean use15specifics = sourceLevel >= ClassFileConstants.JDK1_5;
315         char[] methodSignature = use15specifics ? method.getGenericSignature() : null;
316         if (methodSignature == null) { // no generics
317                 char[] methodDescriptor = method.getMethodDescriptor();   // of the form (I[Ljava/jang/String;)V
318                 int numOfParams = 0;
319                 char nextChar;
320                 int index = 0;   // first character is always '(' so skip it
321                 while ((nextChar = methodDescriptor[++index]) != ')') {
322                         if (nextChar != '[') {
323                                 numOfParams++;
324                                 if (nextChar == 'L')
325                                         while ((nextChar = methodDescriptor[++index]) != ';'){/*empty*/}
326                         }
327                 }
328
329                 // Ignore synthetic argument for member types.
330                 int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
331                 int size = numOfParams - startIndex;
332                 if (size > 0) {
333                         parameters = new TypeBinding[size];
334                         index = 1;
335                         int end = 0;   // first character is always '(' so skip it
336                         for (int i = 0; i < numOfParams; i++) {
337                                 while ((nextChar = methodDescriptor[++end]) == '['){/*empty*/}
338                                 if (nextChar == 'L')
339                                         while ((nextChar = methodDescriptor[++end]) != ';'){/*empty*/}
340         
341                                 if (i >= startIndex)   // skip the synthetic arg if necessary
342                                         parameters[i - startIndex] = environment.getTypeFromSignature(methodDescriptor, index, end, false, this);
343                                 index = end + 1;
344                         }
345                 }
346
347                 char[][] exceptionTypes = method.getExceptionTypeNames();
348                 if (exceptionTypes != null) {
349                         size = exceptionTypes.length;
350                         if (size > 0) {
351                                 exceptions = new ReferenceBinding[size];
352                                 for (int i = 0; i < size; i++)
353                                         exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1, false);
354                         }
355                 }
356
357                 if (!method.isConstructor())
358                         returnType = environment.getTypeFromSignature(methodDescriptor, index + 1, -1, false, this);   // index is currently pointing at the ')'
359         } else {
360                 // MethodTypeSignature = ParameterPart(optional) '(' TypeSignatures ')' return_typeSignature ['^' TypeSignature (optional)]
361                 SignatureWrapper wrapper = new SignatureWrapper(methodSignature);
362                 if (wrapper.signature[wrapper.start] == '<') {
363                         // <A::Ljava/lang/annotation/Annotation;>(Ljava/lang/Class<TA;>;)TA;
364                         // ParameterPart = '<' ParameterSignature(s) '>'
365                         wrapper.start++; // skip '<'
366                         typeVars = createTypeVariables(wrapper, this);
367                         wrapper.start++; // skip '>'
368                 }
369
370                 if (wrapper.signature[wrapper.start] == '(') {
371                         wrapper.start++; // skip '('
372                         if (wrapper.signature[wrapper.start] == ')') {
373                                 wrapper.start++; // skip ')'
374                         } else {
375                                 java.util.ArrayList types = new java.util.ArrayList(2);
376                                 int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
377                                 if (startIndex == 1)
378                                         environment.getTypeFromTypeSignature(wrapper, typeVars, this); // skip synthetic argument
379                                 while (wrapper.signature[wrapper.start] != ')') {
380                                         types.add(environment.getTypeFromTypeSignature(wrapper, typeVars, this));
381                                 }
382                                 wrapper.start++; // skip ')'
383                                 parameters = new TypeBinding[types.size()];
384                                 types.toArray(parameters);
385                         }
386                 }
387
388                 if (!method.isConstructor())
389                         returnType = environment.getTypeFromTypeSignature(wrapper, typeVars, this);
390
391                 if (!wrapper.atEnd() && wrapper.signature[wrapper.start] == '^') {
392                         // attempt to find each superinterface if it exists in the cache (otherwise - resolve it when requested)
393                         java.util.ArrayList types = new java.util.ArrayList(2);
394                         do {
395                                 wrapper.start++; // skip '^'
396                                 types.add(environment.getTypeFromTypeSignature(wrapper, typeVars, this));
397                         } while (!wrapper.atEnd() && wrapper.signature[wrapper.start] == '^');
398                         exceptions = new ReferenceBinding[types.size()];
399                         types.toArray(exceptions);
400                 } else { // get the exceptions the old way
401                         char[][] exceptionTypes = method.getExceptionTypeNames();
402                         if (exceptionTypes != null) {
403                                 int size = exceptionTypes.length;
404                                 if (size > 0) {
405                                         exceptions = new ReferenceBinding[size];
406                                         for (int i = 0; i < size; i++)
407                                                 exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1, false);
408                                 }
409                         }
410                 }
411         }
412
413         MethodBinding result = method.isConstructor()
414                 ? new MethodBinding(methodModifiers, parameters, exceptions, this)
415                 : new MethodBinding(methodModifiers, method.getSelector(), returnType, parameters, exceptions, this);
416         if (use15specifics) {
417                 result.tagBits |= method.getTagBits();
418         }
419         result.typeVariables = typeVars;
420         // fixup the declaring element of the type variable
421         for (int i = 0, length = typeVars.length; i < length; i++) {
422                 typeVars[i].declaringElement = result;
423         }
424         return result;
425 }
426 /**
427  * Create method bindings for binary type, filtering out <clinit> and synthetics
428  */
429 private void createMethods(IBinaryMethod[] iMethods, long sourceLevel) {
430         int total = 0, initialTotal = 0, iClinit = -1;
431         int[] toSkip = null;
432         if (iMethods != null) {
433                 total = initialTotal = iMethods.length;
434                 for (int i = total; --i >= 0;) {
435                         IBinaryMethod method = iMethods[i];
436                         if ((method.getModifiers() & AccSynthetic) != 0) {
437                                 // discard synthetics methods
438                                 if (toSkip == null) toSkip = new int[iMethods.length];
439                                 toSkip[i] = -1;
440                                 total--;
441                         } else if (iClinit == -1) {
442                                 char[] methodName = method.getSelector();
443                                 if (methodName.length == 8 && methodName[0] == '<') {
444                                         // discard <clinit>
445                                         iClinit = i;
446                                         total--;
447                                 }
448                         }
449                 }
450         }
451         if (total == 0) {
452                 this.methods = NoMethods;
453                 return;
454         }
455
456         this.methods = new MethodBinding[total];
457         if (total == initialTotal) {
458                 for (int i = 0; i < initialTotal; i++)
459                         this.methods[i] = createMethod(iMethods[i], sourceLevel);
460         } else {
461                 for (int i = 0, index = 0; i < initialTotal; i++)
462                         if (iClinit != i && (toSkip == null || toSkip[i] != -1))
463                                 this.methods[index++] = createMethod(iMethods[i], sourceLevel);
464         }
465         modifiers |= AccUnresolved; // until methods() is sent
466 }
467
468 private TypeVariableBinding[] createTypeVariables(SignatureWrapper wrapper, Binding declaringElement) {
469         // detect all type variables first
470         char[] typeSignature = wrapper.signature;
471         int depth = 0, length = typeSignature.length;
472         int rank = 0;
473         ArrayList variables = new ArrayList(1);
474         depth = 0;
475         boolean pendingVariable = true;
476         createVariables: {
477                 for (int i = 1; i < length; i++) {
478                         switch(typeSignature[i]) {
479                                 case '<' : 
480                                         depth++;
481                                         break;
482                                 case '>' : 
483                                         if (--depth < 0)
484                                                 break createVariables;
485                                         break;
486                                 case ';' :
487                                         if ((depth == 0) && (i +1 < length) && (typeSignature[i+1] != ':'))
488                                                 pendingVariable = true;
489                                         break;
490                                 default:
491                                         if (pendingVariable) {
492                                                 pendingVariable = false;
493                                                 int colon = CharOperation.indexOf(':', typeSignature, i);
494                                                 char[] variableName = CharOperation.subarray(typeSignature, i, colon);
495                                                 variables.add(new TypeVariableBinding(variableName, declaringElement, rank++));
496                                         }
497                         }
498                 }
499         }
500         // initialize type variable bounds - may refer to forward variables
501         TypeVariableBinding[] result;
502         variables.toArray(result = new TypeVariableBinding[rank]);
503         for (int i = 0; i < rank; i++) {
504                 initializeTypeVariable(result[i], result, wrapper);
505         }
506         return result;
507 }
508
509 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
510 *
511 * NOTE: enclosingType of a binary type is resolved when needed
512 */
513
514 public ReferenceBinding enclosingType() {
515         if ((this.tagBits & HasUnresolvedEnclosingType) == 0)
516                 return this.enclosingType;
517
518         this.enclosingType = resolveUnresolvedType(this.enclosingType, this.environment, false); // no raw conversion for now
519         this.tagBits &= ~HasUnresolvedEnclosingType;
520
521         // finish resolving the type
522         this.enclosingType = resolveType(this.enclosingType, this.environment, false);
523         return this.enclosingType;
524 }
525 // NOTE: the type of each field of a binary type is resolved when needed
526
527 public FieldBinding[] fields() {
528         for (int i = fields.length; --i >= 0;)
529                 resolveTypeFor(fields[i]);
530         return fields;
531 }
532 public long getAnnotationTagBits() {
533         return this.tagBits;
534 }
535 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
536 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
537         int argCount = argumentTypes.length;
538         nextMethod : for (int m = methods.length; --m >= 0;) {
539                 MethodBinding method = methods[m];
540                 if (method.selector == TypeConstants.INIT && method.parameters.length == argCount) {
541                         resolveTypesFor(method);
542                         TypeBinding[] toMatch = method.parameters;
543                         for (int p = 0; p < argCount; p++)
544                                 if (toMatch[p] != argumentTypes[p])
545                                         continue nextMethod;
546                         return method;
547                 }
548         }
549         return null;
550 }
551 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
552 // searches up the hierarchy as long as no potential (but not exact) match was found.
553
554 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {
555         // sender from refScope calls recordTypeReference(this)
556         int argCount = argumentTypes.length;
557         int selectorLength = selector.length;
558         boolean foundNothing = true;
559         nextMethod : for (int m = methods.length; --m >= 0;) {
560                 MethodBinding method = methods[m];
561                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
562                         foundNothing = false; // inner type lookups must know that a method with this name exists
563                         if (method.parameters.length == argCount) {
564                                 resolveTypesFor(method);
565                                 TypeBinding[] toMatch = method.parameters;
566                                 for (int p = 0; p < argCount; p++)
567                                         if (toMatch[p] != argumentTypes[p])
568                                                 continue nextMethod;
569                                 return method;
570                         }
571                 }
572         }
573
574         if (foundNothing) {
575                 if (isInterface()) {
576                          if (superInterfaces.length == 1) {
577                                 if (refScope != null)
578                                         refScope.recordTypeReference(superInterfaces[0]);
579                                 return superInterfaces[0].getExactMethod(selector, argumentTypes, refScope);
580                          }
581                 } else if (superclass != null) {
582                         if (refScope != null)
583                                 refScope.recordTypeReference(superclass);
584                         return superclass.getExactMethod(selector, argumentTypes, refScope);
585                 }
586         }
587         return null;
588 }
589 // NOTE: the type of a field of a binary type is resolved when needed
590
591 public FieldBinding getField(char[] fieldName, boolean needResolve) {
592         int fieldLength = fieldName.length;
593         for (int f = fields.length; --f >= 0;) {
594                 char[] name = fields[f].name;
595                 if (name.length == fieldLength && CharOperation.equals(name, fieldName))
596                         return needResolve ? resolveTypeFor(fields[f]) : fields[f];
597         }
598         return null;
599 }
600 /**
601  *  Rewrite of default getMemberType to avoid resolving eagerly all member types when one is requested
602  */
603 public ReferenceBinding getMemberType(char[] typeName) {
604         for (int i = this.memberTypes.length; --i >= 0;) {
605             ReferenceBinding memberType = this.memberTypes[i];
606             if (memberType instanceof UnresolvedReferenceBinding) {
607                         char[] name = memberType.sourceName; // source name is qualified with enclosing type name
608                         int prefixLength = this.compoundName[this.compoundName.length - 1].length + 1; // enclosing$
609                         if (name.length == (prefixLength + typeName.length)) // enclosing $ typeName
610                                 if (CharOperation.fragmentEquals(typeName, name, prefixLength, true)) // only check trailing portion
611                                         return this.memberTypes[i] = resolveType(memberType, this.environment, false); // no raw conversion for now
612             } else if (CharOperation.equals(typeName, memberType.sourceName)) {
613                 return memberType;
614             }
615         }
616         return null;
617 }
618 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
619
620 public MethodBinding[] getMethods(char[] selector) {
621         int count = 0;
622         int lastIndex = -1;
623         int selectorLength = selector.length;
624         for (int m = 0, length = methods.length; m < length; m++) {
625                 MethodBinding method = methods[m];
626                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
627                         resolveTypesFor(method);
628                         count++;
629                         lastIndex = m;
630                 }
631         }
632         if (count == 1)
633                 return new MethodBinding[] {methods[lastIndex]};
634         if (count > 0) {
635                 MethodBinding[] result = new MethodBinding[count];
636                 count = 0;
637                 for (int m = 0; m <= lastIndex; m++) {
638                         MethodBinding method = methods[m];
639                         if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector))
640                                 result[count++] = method;
641                 }
642                 return result;
643         }
644         return NoMethods;
645 }
646 public boolean hasMemberTypes() {
647     return this.memberTypes.length > 0;
648 }
649 // NOTE: member types of binary types are resolved when needed
650
651 public TypeVariableBinding getTypeVariable(char[] variableName) {
652         TypeVariableBinding variable = super.getTypeVariable(variableName);
653         variable.resolve(this.environment);
654         return variable;
655 }
656 private void initializeTypeVariable(TypeVariableBinding variable, TypeVariableBinding[] existingVariables, SignatureWrapper wrapper) {
657         // ParameterSignature = Identifier ':' TypeSignature
658         //   or Identifier ':' TypeSignature(optional) InterfaceBound(s)
659         // InterfaceBound = ':' TypeSignature
660         int colon = CharOperation.indexOf(':', wrapper.signature, wrapper.start);
661         wrapper.start = colon + 1; // skip name + ':'
662         ReferenceBinding type, firstBound = null;
663         if (wrapper.signature[wrapper.start] == ':') {
664                 type = environment.getType(JAVA_LANG_OBJECT);
665         } else {
666                 type = (ReferenceBinding) environment.getTypeFromTypeSignature(wrapper, existingVariables, this);
667                 firstBound = type;
668         }
669
670         // variable is visible to its bounds
671         variable.modifiers |= AccUnresolved;
672         variable.superclass = type;
673
674         ReferenceBinding[] bounds = null;
675         if (wrapper.signature[wrapper.start] == ':') {
676                 java.util.ArrayList types = new java.util.ArrayList(2);
677                 do {
678                         wrapper.start++; // skip ':'
679                         types.add(environment.getTypeFromTypeSignature(wrapper, existingVariables, this));
680                 } while (wrapper.signature[wrapper.start] == ':');
681                 bounds = new ReferenceBinding[types.size()];
682                 types.toArray(bounds);
683         }
684
685         variable.superInterfaces = bounds == null ? NoSuperInterfaces : bounds;
686         if (firstBound == null) {
687                 firstBound = variable.superInterfaces.length == 0 ? null : variable.superInterfaces[0];
688                 variable.modifiers |= AccInterface;
689         }
690         variable.firstBound = firstBound;
691 }
692 /**
693  * Returns true if a type is identical to another one,
694  * or for generic types, true if compared to its raw type.
695  */
696 public boolean isEquivalentTo(TypeBinding otherType) {
697         
698     if (this == otherType) return true;
699     if (otherType == null) return false;
700     switch(otherType.kind()) {
701
702         case Binding.WILDCARD_TYPE :
703                         return ((WildcardBinding) otherType).boundCheck(this);
704
705                 case Binding.RAW_TYPE :
706                         return otherType.erasure() == this;
707     }
708         return false;
709 }
710 public boolean isGenericType() {
711     return this.typeVariables != NoTypeVariables;
712 }
713 // NOTE: member types of binary types are resolved when needed
714
715 public ReferenceBinding[] memberTypes() {
716         if ((this.tagBits & HasUnresolvedMemberTypes) == 0)
717                 return this.memberTypes;
718
719         for (int i = this.memberTypes.length; --i >= 0;)
720                 this.memberTypes[i] = resolveUnresolvedType(this.memberTypes[i], this.environment, false); // no raw conversion for now
721         this.tagBits &= ~HasUnresolvedMemberTypes;
722
723         for (int i = this.memberTypes.length; --i >= 0;)
724                 this.memberTypes[i] = resolveType(this.memberTypes[i], this.environment, false); // no raw conversion for now
725         return this.memberTypes;
726 }
727 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
728
729 public MethodBinding[] methods() {
730         if ((modifiers & AccUnresolved) == 0)
731                 return methods;
732
733         for (int i = methods.length; --i >= 0;)
734                 resolveTypesFor(methods[i]);
735         modifiers &= ~AccUnresolved;
736         return methods;
737 }
738 private FieldBinding resolveTypeFor(FieldBinding field) {
739         if ((field.modifiers & AccUnresolved) == 0)
740                 return field;
741
742         field.type = resolveType(field.type, this.environment, null, 0);
743         field.modifiers &= ~AccUnresolved;
744         return field;
745 }
746 MethodBinding resolveTypesFor(MethodBinding method) {
747         if ((method.modifiers & AccUnresolved) == 0)
748                 return method;
749
750         if (!method.isConstructor())
751                 method.returnType = resolveType(method.returnType, this.environment, null, 0);
752         for (int i = method.parameters.length; --i >= 0;)
753                 method.parameters[i] = resolveType(method.parameters[i], this.environment, null, 0);
754         for (int i = method.thrownExceptions.length; --i >= 0;)
755                 method.thrownExceptions[i] = resolveType(method.thrownExceptions[i], this.environment, true);
756         for (int i = method.typeVariables.length; --i >= 0;)
757                 method.typeVariables[i].resolve(this.environment);
758         method.modifiers &= ~AccUnresolved;
759         return method;
760 }
761
762 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
763 *
764 * NOTE: superclass of a binary type is resolved when needed
765 */
766
767 public ReferenceBinding superclass() {
768         if ((this.tagBits & HasUnresolvedSuperclass) == 0)
769                 return this.superclass;
770
771         this.superclass = resolveUnresolvedType(this.superclass, this.environment, true);
772         this.tagBits &= ~HasUnresolvedSuperclass;
773
774         // finish resolving the type
775         this.superclass = resolveType(this.superclass, this.environment, true);
776         return this.superclass;
777 }
778 // NOTE: superInterfaces of binary types are resolved when needed
779
780 public ReferenceBinding[] superInterfaces() {
781         if ((this.tagBits & HasUnresolvedSuperinterfaces) == 0)
782                 return this.superInterfaces;
783
784         for (int i = this.superInterfaces.length; --i >= 0;)
785                 this.superInterfaces[i] = resolveUnresolvedType(this.superInterfaces[i], this.environment, true);
786         this.tagBits &= ~HasUnresolvedSuperinterfaces;
787
788         for (int i = this.superInterfaces.length; --i >= 0;)
789                 this.superInterfaces[i] = resolveType(this.superInterfaces[i], this.environment, true);
790         return this.superInterfaces;
791 }
792 public TypeVariableBinding[] typeVariables() {
793         if ((this.tagBits & HasUnresolvedTypeVariables) == 0)
794                 return this.typeVariables;
795
796         for (int i = this.typeVariables.length; --i >= 0;)
797                 this.typeVariables[i].resolve(this.environment);
798         this.tagBits &= ~HasUnresolvedTypeVariables;
799         return this.typeVariables;
800 }
801 public String toString() {
802         String s = ""; //$NON-NLS-1$
803
804         if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$
805         if (isPublic()) s += "public "; //$NON-NLS-1$
806         if (isProtected()) s += "protected "; //$NON-NLS-1$
807         if (isPrivate()) s += "private "; //$NON-NLS-1$
808         if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$
809         if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$
810         if (isFinal()) s += "final "; //$NON-NLS-1$
811
812         s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
813         s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
814
815         s += "\n\textends "; //$NON-NLS-1$
816         s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
817
818         if (superInterfaces != null) {
819                 if (superInterfaces != NoSuperInterfaces) {
820                         s += "\n\timplements : "; //$NON-NLS-1$
821                         for (int i = 0, length = superInterfaces.length; i < length; i++) {
822                                 if (i  > 0)
823                                         s += ", "; //$NON-NLS-1$
824                                 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
825                         }
826                 }
827         } else {
828                 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
829         }
830
831         if (enclosingType != null) {
832                 s += "\n\tenclosing type : "; //$NON-NLS-1$
833                 s += enclosingType.debugName();
834         }
835
836         if (fields != null) {
837                 if (fields != NoFields) {
838                         s += "\n/*   fields   */"; //$NON-NLS-1$
839                         for (int i = 0, length = fields.length; i < length; i++)
840                                 s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
841                 }
842         } else {
843                 s += "NULL FIELDS"; //$NON-NLS-1$
844         }
845
846         if (methods != null) {
847                 if (methods != NoMethods) {
848                         s += "\n/*   methods   */"; //$NON-NLS-1$
849                         for (int i = 0, length = methods.length; i < length; i++)
850                                 s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
851                 }
852         } else {
853                 s += "NULL METHODS"; //$NON-NLS-1$
854         }
855
856         if (memberTypes != null) {
857                 if (memberTypes != NoMemberTypes) {
858                         s += "\n/*   members   */"; //$NON-NLS-1$
859                         for (int i = 0, length = memberTypes.length; i < length; i++)
860                                 s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
861                 }
862         } else {
863                 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
864         }
865
866         s += "\n\n\n"; //$NON-NLS-1$
867         return s;
868 }
869 MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
870         return methods;
871 }
872 }