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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.lookup;
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;
22 Not all fields defined by this type are initialized when it is created.
23 Some are initialized only when needed.
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.
29 null is NOT a valid value for a non-public field... it just means the field is not initialized.
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;
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());
47 this.tagBits |= IsBinaryBinding;
48 this.environment = environment;
49 this.fPackage = packageBinding;
50 this.fileName = binaryType.getFileName();
52 // source name must be one name without "$".
53 char[] possibleSourceName = this.compoundName[this.compoundName.length - 1];
54 int start = CharOperation.lastIndexOf('$', possibleSourceName) + 1;
56 this.sourceName = possibleSourceName;
58 this.sourceName = new char[possibleSourceName.length - start];
59 System.arraycopy(possibleSourceName, start, this.sourceName, 0, this.sourceName.length);
62 this.modifiers = binaryType.getModifiers();
63 if (binaryType.isInterface())
64 this.modifiers |= AccInterface;
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;
75 public FieldBinding[] availableFields() {
76 FieldBinding[] availableFields = new FieldBinding[fields.length];
79 for (int i = 0; i < fields.length;i++) {
81 availableFields[count] = resolveTypeFor(fields[i]);
83 } catch (AbortCompilation a){
88 System.arraycopy(availableFields, 0, availableFields = new FieldBinding[count], 0, count);
89 return availableFields;
92 public MethodBinding[] availableMethods() {
93 if ((modifiers & AccUnresolved) == 0)
96 MethodBinding[] availableMethods = new MethodBinding[methods.length];
99 for (int i = 0; i < methods.length;i++) {
101 availableMethods[count] = resolveTypesFor(methods[i]);
103 } catch (AbortCompilation a){
107 System.arraycopy(availableMethods, 0, availableMethods = new MethodBinding[count], 0, count);
108 return availableMethods;
111 void cachePartsFrom(IBinaryType binaryType, boolean needFieldsAndMethods) {
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;
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);
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;
133 this.memberTypes = NoMemberTypes;
134 IBinaryNestedType[] memberTypeStructures = binaryType.getMemberTypes();
135 if (memberTypeStructures != null) {
136 int size = memberTypeStructures.length;
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);
145 char[][] interfaceNames = binaryType.getInterfaceNames();
146 if (interfaceNames != null) {
147 int size = interfaceNames.length;
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);
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;
163 private void createFields(IBinaryField[] iFields) {
164 this.fields = NoFields;
165 if (iFields != null) {
166 int size = iFields.length;
168 this.fields = new FieldBinding[size];
169 for (int i = 0; i < size; i++) {
170 IBinaryField field = iFields[i];
174 environment.getTypeFromSignature(field.getTypeName(), 0, -1),
175 field.getModifiers() | AccUnresolved,
177 field.getConstant());
182 private MethodBinding createMethod(IBinaryMethod method) {
183 int methodModifiers = method.getModifiers() | AccUnresolved;
185 ReferenceBinding[] exceptions = NoExceptions;
186 char[][] exceptionTypes = method.getExceptionTypeNames();
187 if (exceptionTypes != null) {
188 int size = exceptionTypes.length;
190 exceptions = new ReferenceBinding[size];
191 for (int i = 0; i < size; i++)
192 exceptions[i] = environment.getTypeFromConstantPoolName(exceptionTypes[i], 0, -1);
196 TypeBinding[] parameters = NoParameters;
197 char[] methodSignature = method.getMethodDescriptor(); // of the form (I[Ljava/jang/String;)V
200 int index = 0; // first character is always '(' so skip it
201 while ((nextChar = methodSignature[++index]) != ')') {
202 if (nextChar != '[') {
205 while ((nextChar = methodSignature[++index]) != ';'){/*empty*/}
209 // Ignore synthetic argument for member types.
210 int startIndex = (method.isConstructor() && isMemberType() && !isStatic()) ? 1 : 0;
211 int size = numOfParams - startIndex;
213 parameters = new TypeBinding[size];
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*/}
219 while ((nextChar = methodSignature[++end]) != ';'){/*empty*/}
221 if (i >= startIndex) // skip the synthetic arg if necessary
222 parameters[i - startIndex] = environment.getTypeFromSignature(methodSignature, index, end);
227 MethodBinding binding = null;
228 if (method.isConstructor())
229 binding = new MethodBinding(methodModifiers, parameters, exceptions, this);
231 binding = new MethodBinding(
233 method.getSelector(),
234 environment.getTypeFromSignature(methodSignature, index + 1, -1), // index is currently pointing at the ')'
241 * Create method bindings for binary type, filtering out <clinit> and synthetics
243 private void createMethods(IBinaryMethod[] iMethods) {
244 int total = 0, initialTotal = 0, iClinit = -1;
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];
255 } else if (iClinit == -1) {
256 char[] methodName = method.getSelector();
257 if (methodName.length == 8 && methodName[0] == '<') {
266 this.methods = NoMethods;
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]);
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]);
279 modifiers |= AccUnresolved; // until methods() is sent
281 /* Answer the receiver's enclosing type... null if the receiver is a top level type.
283 * NOTE: enclosingType of a binary type is resolved when needed
286 public ReferenceBinding enclosingType() {
287 if (enclosingType == null)
289 if (enclosingType instanceof UnresolvedReferenceBinding)
290 enclosingType = ((UnresolvedReferenceBinding) enclosingType).resolve(environment);
291 return enclosingType;
293 // NOTE: the type of each field of a binary type is resolved when needed
295 public FieldBinding[] fields() {
296 for (int i = fields.length; --i >= 0;)
297 resolveTypeFor(fields[i]);
300 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
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])
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.
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])
341 if (superInterfaces.length == 1)
342 return superInterfaces[0].getExactMethod(selector, argumentTypes);
343 } else if (superclass != null) {
344 return superclass.getExactMethod(selector, argumentTypes);
349 // NOTE: the type of a field of a binary type is resolved when needed
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];
361 * Rewrite of default getMemberType to avoid resolving eagerly all member types when one is requested
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)) {
378 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
380 public MethodBinding[] getMethods(char[] selector) {
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);
393 return new MethodBinding[] {methods[lastIndex]};
395 MethodBinding[] result = new MethodBinding[count];
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;
406 public boolean hasMemberTypes() {
407 return this.memberTypes.length > 0;
409 // NOTE: member types of binary types are resolved when needed
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);
417 // NOTE: the return type, arg & exception types of each method of a binary type are resolved when needed
419 public MethodBinding[] methods() {
420 if ((modifiers & AccUnresolved) == 0)
423 for (int i = methods.length; --i >= 0;)
424 resolveTypesFor(methods[i]);
425 modifiers ^= AccUnresolved;
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);
438 private FieldBinding resolveTypeFor(FieldBinding field) {
439 if ((field.modifiers & AccUnresolved) != 0) {
440 field.type = resolveType(field.type);
441 field.modifiers ^= AccUnresolved;
445 private MethodBinding resolveTypesFor(MethodBinding method) {
446 if ((method.modifiers & AccUnresolved) == 0)
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;
459 /* Answer the receiver's superclass... null if the receiver is Object or an interface.
461 * NOTE: superclass of a binary type is resolved when needed
464 public ReferenceBinding superclass() {
465 if (superclass == null)
467 if (superclass instanceof UnresolvedReferenceBinding)
468 superclass = ((UnresolvedReferenceBinding) superclass).resolve(environment);
471 // NOTE: superInterfaces of binary types are resolved when needed
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;
479 MethodBinding[] unResolvedMethods() { // for the MethodVerifier so it doesn't resolve types
482 public String toString() {
483 String s = ""; //$NON-NLS-1$
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$
493 s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
494 s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
496 s += "\n\textends "; //$NON-NLS-1$
497 s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
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++) {
504 s += ", "; //$NON-NLS-1$
505 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
509 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
512 if (enclosingType != null) {
513 s += "\n\tenclosing type : "; //$NON-NLS-1$
514 s += enclosingType.debugName();
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$
524 s += "NULL FIELDS"; //$NON-NLS-1$
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$
534 s += "NULL METHODS"; //$NON-NLS-1$
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$
544 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
547 s += "\n\n\n"; //$NON-NLS-1$