KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > lookup > SourceTypeBinding


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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.HashMap JavaDoc;
14 import java.util.Hashtable JavaDoc;
15 import java.util.Iterator JavaDoc;
16
17 import org.eclipse.jdt.core.compiler.CharOperation;
18 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
19 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
20 import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;
21 import org.eclipse.jdt.internal.compiler.ast.Argument;
22 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
23 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
24 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
25 import org.eclipse.jdt.internal.compiler.ast.TypeParameter;
26 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
27 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
28 import org.eclipse.jdt.internal.compiler.impl.Constant;
29 import org.eclipse.jdt.internal.compiler.util.Util;
30 import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;
31
32 public class SourceTypeBinding extends ReferenceBinding {
33     public ReferenceBinding superclass;
34     public ReferenceBinding[] superInterfaces;
35     private FieldBinding[] fields;
36     private MethodBinding[] methods;
37     public ReferenceBinding[] memberTypes;
38     public TypeVariableBinding[] typeVariables;
39
40     public ClassScope scope;
41
42     // Synthetics are separated into 5 categories: methods, super methods, fields, class literals, changed declaring type bindings and bridge methods
43
public final static int METHOD_EMUL = 0;
44     public final static int FIELD_EMUL = 1;
45     public final static int CLASS_LITERAL_EMUL = 2;
46     public final static int RECEIVER_TYPE_EMUL = 3;
47     HashMap JavaDoc[] synthetics;
48     char[] genericReferenceTypeSignature;
49
50     private SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder
51

52 public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) {
53     this.compoundName = compoundName;
54     this.fPackage = fPackage;
55     this.fileName = scope.referenceCompilationUnit().getFileName();
56     this.modifiers = scope.referenceContext.modifiers;
57     this.sourceName = scope.referenceContext.name;
58     this.scope = scope;
59
60     // expect the fields & methods to be initialized correctly later
61
this.fields = Binding.NO_FIELDS;
62     this.methods = Binding.NO_METHODS;
63
64     computeId();
65 }
66
67 private void addDefaultAbstractMethods() {
68     if ((this.tagBits & TagBits.KnowsDefaultAbstractMethods) != 0) return;
69
70     this.tagBits |= TagBits.KnowsDefaultAbstractMethods;
71     if (isClass() && isAbstract()) {
72         if (this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_2)
73             return; // no longer added for post 1.2 targets
74

75         ReferenceBinding[] itsInterfaces = superInterfaces();
76         if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
77             MethodBinding[] defaultAbstracts = null;
78             int defaultAbstractsCount = 0;
79             ReferenceBinding[] interfacesToVisit = itsInterfaces;
80             int nextPosition = interfacesToVisit.length;
81             for (int i = 0; i < nextPosition; i++) {
82                 ReferenceBinding superType = interfacesToVisit[i];
83                 if (superType.isValidBinding()) {
84                     MethodBinding[] superMethods = superType.methods();
85                     nextAbstractMethod: for (int m = superMethods.length; --m >= 0;) {
86                         MethodBinding method = superMethods[m];
87                         // explicitly implemented ?
88
if (implementsMethod(method))
89                             continue nextAbstractMethod;
90                         if (defaultAbstractsCount == 0) {
91                             defaultAbstracts = new MethodBinding[5];
92                         } else {
93                             // already added as default abstract ?
94
for (int k = 0; k < defaultAbstractsCount; k++) {
95                                 MethodBinding alreadyAdded = defaultAbstracts[k];
96                                 if (CharOperation.equals(alreadyAdded.selector, method.selector) && alreadyAdded.areParametersEqual(method))
97                                     continue nextAbstractMethod;
98                             }
99                         }
100                         MethodBinding defaultAbstract = new MethodBinding(
101                                 method.modifiers | ExtraCompilerModifiers.AccDefaultAbstract,
102                                 method.selector,
103                                 method.returnType,
104                                 method.parameters,
105                                 method.thrownExceptions,
106                                 this);
107                         if (defaultAbstractsCount == defaultAbstracts.length)
108                             System.arraycopy(defaultAbstracts, 0, defaultAbstracts = new MethodBinding[2 * defaultAbstractsCount], 0, defaultAbstractsCount);
109                         defaultAbstracts[defaultAbstractsCount++] = defaultAbstract;
110                     }
111
112                     if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {
113                         int itsLength = itsInterfaces.length;
114                         if (nextPosition + itsLength >= interfacesToVisit.length)
115                             System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);
116                         nextInterface : for (int a = 0; a < itsLength; a++) {
117                             ReferenceBinding next = itsInterfaces[a];
118                             for (int b = 0; b < nextPosition; b++)
119                                 if (next == interfacesToVisit[b]) continue nextInterface;
120                             interfacesToVisit[nextPosition++] = next;
121                         }
122                     }
123                 }
124             }
125             if (defaultAbstractsCount > 0) {
126                 int length = this.methods.length;
127                 System.arraycopy(this.methods, 0, this.methods = new MethodBinding[length + defaultAbstractsCount], 0, length);
128                 System.arraycopy(defaultAbstracts, 0, this.methods, length, defaultAbstractsCount);
129                 // re-sort methods
130
length = length + defaultAbstractsCount;
131                 if (length > 1)
132                     ReferenceBinding.sortMethods(this.methods, 0, length);
133                 // this.tagBits |= TagBits.AreMethodsSorted; -- already set in #methods()
134
}
135         }
136     }
137 }
138 /* Add a new synthetic field for <actualOuterLocalVariable>.
139 * Answer the new field or the existing field if one already existed.
140 */

141 public FieldBinding addSyntheticFieldForInnerclass(LocalVariableBinding actualOuterLocalVariable) {
142     if (this.synthetics == null)
143         this.synthetics = new HashMap JavaDoc[4];
144     if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
145         this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap JavaDoc(5);
146     
147     FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable);
148     if (synthField == null) {
149         synthField = new SyntheticFieldBinding(
150             CharOperation.concat(TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX, actualOuterLocalVariable.name),
151             actualOuterLocalVariable.type,
152             ClassFileConstants.AccPrivate | ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic,
153             this,
154             Constant.NotAConstant,
155             this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
156         this.synthetics[SourceTypeBinding.FIELD_EMUL].put(actualOuterLocalVariable, synthField);
157     }
158
159     // ensure there is not already such a field defined by the user
160
boolean needRecheck;
161     int index = 1;
162     do {
163         needRecheck = false;
164         FieldBinding existingField;
165         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
166             TypeDeclaration typeDecl = this.scope.referenceContext;
167             for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
168                 FieldDeclaration fieldDecl = typeDecl.fields[i];
169                 if (fieldDecl.binding == existingField) {
170                     synthField.name = CharOperation.concat(
171                         TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX,
172                         actualOuterLocalVariable.name,
173                         ("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
174
needRecheck = true;
175                     break;
176                 }
177             }
178         }
179     } while (needRecheck);
180     return synthField;
181 }
182 /* Add a new synthetic field for <enclosingType>.
183 * Answer the new field or the existing field if one already existed.
184 */

185 public FieldBinding addSyntheticFieldForInnerclass(ReferenceBinding enclosingType) {
186     if (this.synthetics == null)
187         this.synthetics = new HashMap JavaDoc[4];
188     if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
189         this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap JavaDoc(5);
190
191     FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(enclosingType);
192     if (synthField == null) {
193         synthField = new SyntheticFieldBinding(
194             CharOperation.concat(
195                 TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX,
196                 String.valueOf(enclosingType.depth()).toCharArray()),
197             enclosingType,
198             ClassFileConstants.AccDefault | ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic,
199             this,
200             Constant.NotAConstant,
201             this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
202         this.synthetics[SourceTypeBinding.FIELD_EMUL].put(enclosingType, synthField);
203     }
204     // ensure there is not already such a field defined by the user
205
boolean needRecheck;
206     do {
207         needRecheck = false;
208         FieldBinding existingField;
209         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
210             TypeDeclaration typeDecl = this.scope.referenceContext;
211             for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
212                 FieldDeclaration fieldDecl = typeDecl.fields[i];
213                 if (fieldDecl.binding == existingField) {
214                     if (this.scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5) {
215                         synthField.name = CharOperation.concat(
216                             synthField.name,
217                             "$".toCharArray()); //$NON-NLS-1$
218
needRecheck = true;
219                     } else {
220                         this.scope.problemReporter().duplicateFieldInType(this, fieldDecl);
221                     }
222                     break;
223                 }
224             }
225         }
226     } while (needRecheck);
227     return synthField;
228 }
229 /* Add a new synthetic field for a class literal access.
230 * Answer the new field or the existing field if one already existed.
231 */

232 public FieldBinding addSyntheticFieldForClassLiteral(TypeBinding targetType, BlockScope blockScope) {
233     if (this.synthetics == null)
234         this.synthetics = new HashMap JavaDoc[4];
235     if (this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] == null)
236         this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] = new HashMap JavaDoc(5);
237
238     // use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class.
239
FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].get(targetType);
240     if (synthField == null) {
241         synthField = new SyntheticFieldBinding(
242             CharOperation.concat(
243                 TypeConstants.SYNTHETIC_CLASS,
244                 String.valueOf(this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size()).toCharArray()),
245             blockScope.getJavaLangClass(),
246             ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic,
247             this,
248             Constant.NotAConstant,
249             this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size());
250         this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].put(targetType, synthField);
251     }
252     // ensure there is not already such a field defined by the user
253
FieldBinding existingField;
254     if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
255         TypeDeclaration typeDecl = blockScope.referenceType();
256         for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
257             FieldDeclaration fieldDecl = typeDecl.fields[i];
258             if (fieldDecl.binding == existingField) {
259                 blockScope.problemReporter().duplicateFieldInType(this, fieldDecl);
260                 break;
261             }
262         }
263     }
264     return synthField;
265 }
266 /* Add a new synthetic field for the emulation of the assert statement.
267 * Answer the new field or the existing field if one already existed.
268 */

269 public FieldBinding addSyntheticFieldForAssert(BlockScope blockScope) {
270     if (this.synthetics == null)
271         this.synthetics = new HashMap JavaDoc[4];
272     if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
273         this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap JavaDoc(5);
274
275     FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get("assertionEmulation"); //$NON-NLS-1$
276
if (synthField == null) {
277         synthField = new SyntheticFieldBinding(
278             TypeConstants.SYNTHETIC_ASSERT_DISABLED,
279             TypeBinding.BOOLEAN,
280             ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic | ClassFileConstants.AccFinal,
281             this,
282             Constant.NotAConstant,
283             this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
284         this.synthetics[SourceTypeBinding.FIELD_EMUL].put("assertionEmulation", synthField); //$NON-NLS-1$
285
}
286     // ensure there is not already such a field defined by the user
287
// ensure there is not already such a field defined by the user
288
boolean needRecheck;
289     int index = 0;
290     do {
291         needRecheck = false;
292         FieldBinding existingField;
293         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
294             TypeDeclaration typeDecl = this.scope.referenceContext;
295             for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
296                 FieldDeclaration fieldDecl = typeDecl.fields[i];
297                 if (fieldDecl.binding == existingField) {
298                     synthField.name = CharOperation.concat(
299                         TypeConstants.SYNTHETIC_ASSERT_DISABLED,
300                         ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
301
needRecheck = true;
302                     break;
303                 }
304             }
305         }
306     } while (needRecheck);
307     return synthField;
308 }
309 /* Add a new synthetic field for recording all enum constant values
310 * Answer the new field or the existing field if one already existed.
311 */

312 public FieldBinding addSyntheticFieldForEnumValues() {
313     if (this.synthetics == null)
314         this.synthetics = new HashMap JavaDoc[4];
315     if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
316         this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap JavaDoc(5);
317
318     FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get("enumConstantValues"); //$NON-NLS-1$
319
if (synthField == null) {
320         synthField = new SyntheticFieldBinding(
321             TypeConstants.SYNTHETIC_ENUM_VALUES,
322             this.scope.createArrayType(this,1),
323             ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic | ClassFileConstants.AccFinal,
324             this,
325             Constant.NotAConstant,
326             this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
327         this.synthetics[SourceTypeBinding.FIELD_EMUL].put("enumConstantValues", synthField); //$NON-NLS-1$
328
}
329     // ensure there is not already such a field defined by the user
330
// ensure there is not already such a field defined by the user
331
boolean needRecheck;
332     int index = 0;
333     do {
334         needRecheck = false;
335         FieldBinding existingField;
336         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
337             TypeDeclaration typeDecl = this.scope.referenceContext;
338             for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
339                 FieldDeclaration fieldDecl = typeDecl.fields[i];
340                 if (fieldDecl.binding == existingField) {
341                     synthField.name = CharOperation.concat(
342                         TypeConstants.SYNTHETIC_ENUM_VALUES,
343                         ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
344
needRecheck = true;
345                     break;
346                 }
347             }
348         }
349     } while (needRecheck);
350     return synthField;
351 }
352 /* Add a new synthetic access method for read/write access to <targetField>.
353     Answer the new method or the existing method if one already existed.
354 */

355 public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) {
356     if (this.synthetics == null)
357         this.synthetics = new HashMap JavaDoc[4];
358     if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
359         this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap JavaDoc(5);
360
361     SyntheticMethodBinding accessMethod = null;
362     SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(targetField);
363     if (accessors == null) {
364         accessMethod = new SyntheticMethodBinding(targetField, isReadAccess, this);
365         this.synthetics[SourceTypeBinding.METHOD_EMUL].put(targetField, accessors = new SyntheticMethodBinding[2]);
366         accessors[isReadAccess ? 0 : 1] = accessMethod;
367     } else {
368         if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) {
369             accessMethod = new SyntheticMethodBinding(targetField, isReadAccess, this);
370             accessors[isReadAccess ? 0 : 1] = accessMethod;
371         }
372     }
373     return accessMethod;
374 }
375 /* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.
376  * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
377 */

378 public SyntheticMethodBinding addSyntheticEnumMethod(char[] selector) {
379     if (this.synthetics == null)
380         this.synthetics = new HashMap JavaDoc[4];
381     if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
382         this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap JavaDoc(5);
383
384     SyntheticMethodBinding accessMethod = null;
385     SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(selector);
386     if (accessors == null) {
387         accessMethod = new SyntheticMethodBinding(this, selector);
388         this.synthetics[SourceTypeBinding.METHOD_EMUL].put(selector, accessors = new SyntheticMethodBinding[2]);
389         accessors[0] = accessMethod;
390     } else {
391         if ((accessMethod = accessors[0]) == null) {
392             accessMethod = new SyntheticMethodBinding(this, selector);
393             accessors[0] = accessMethod;
394         }
395     }
396     return accessMethod;
397 }
398 /*
399  * Add a synthetic field to handle the cache of the switch translation table for the corresponding enum type
400  */

401 public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, String JavaDoc key) {
402     if (this.synthetics == null)
403         this.synthetics = new HashMap JavaDoc[4];
404     if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)
405         this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap JavaDoc(5);
406
407     SyntheticFieldBinding synthField = (SyntheticFieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(key);
408     if (synthField == null) {
409         synthField = new SyntheticFieldBinding(
410             fieldName,
411             this.scope.createArrayType(TypeBinding.INT,1),
412             ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic,
413             this,
414             Constant.NotAConstant,
415             this.synthetics[SourceTypeBinding.FIELD_EMUL].size());
416         this.synthetics[SourceTypeBinding.FIELD_EMUL].put(key, synthField);
417     }
418     // ensure there is not already such a field defined by the user
419
boolean needRecheck;
420     int index = 0;
421     do {
422         needRecheck = false;
423         FieldBinding existingField;
424         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
425             TypeDeclaration typeDecl = this.scope.referenceContext;
426             for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
427                 FieldDeclaration fieldDecl = typeDecl.fields[i];
428                 if (fieldDecl.binding == existingField) {
429                     synthField.name = CharOperation.concat(
430                         fieldName,
431                         ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
432
needRecheck = true;
433                     break;
434                 }
435             }
436         }
437     } while (needRecheck);
438     return synthField;
439 }
440 /* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.
441  * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF
442 */

443 public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBinding) {
444     if (this.synthetics == null)
445         this.synthetics = new HashMap JavaDoc[4];
446     if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
447         this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap JavaDoc(5);
448
449     SyntheticMethodBinding accessMethod = null;
450     char[] selector = CharOperation.concat(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, enumBinding.constantPoolName());
451     CharOperation.replace(selector, '/', '$');
452     final String JavaDoc key = new String JavaDoc(selector);
453     SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(key);
454     // first add the corresponding synthetic field
455
if (accessors == null) {
456         // then create the synthetic method
457
final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);
458         accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);
459         this.synthetics[SourceTypeBinding.METHOD_EMUL].put(key, accessors = new SyntheticMethodBinding[2]);
460         accessors[0] = accessMethod;
461     } else {
462         if ((accessMethod = accessors[0]) == null) {
463             final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);
464             accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);
465             accessors[0] = accessMethod;
466         }
467     }
468     return accessMethod;
469 }
470 /* Add a new synthetic access method for access to <targetMethod>.
471  * Must distinguish access method used for super access from others (need to use invokespecial bytecode)
472     Answer the new method or the existing method if one already existed.
473 */

474 public SyntheticMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) {
475     if (this.synthetics == null)
476         this.synthetics = new HashMap JavaDoc[4];
477     if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)
478         this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap JavaDoc(5);
479
480     SyntheticMethodBinding accessMethod = null;
481     SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(targetMethod);
482     if (accessors == null) {
483         accessMethod = new SyntheticMethodBinding(targetMethod, isSuperAccess, this);
484         this.synthetics[SourceTypeBinding.METHOD_EMUL].put(targetMethod, accessors = new SyntheticMethodBinding[2]);
485         accessors[isSuperAccess ? 0 : 1] = accessMethod;
486     } else {
487         if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) {
488             accessMethod = new SyntheticMethodBinding(targetMethod, isSuperAccess, this);
489             accessors[isSuperAccess ? 0 : 1] = accessMethod;
490         }
491     }
492     return accessMethod;
493 }
494 /*
495  * Record the fact that bridge methods need to be generated to override certain inherited methods
496  */

497 public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge, MethodBinding targetMethod) {
498     if (isInterface()) return null; // only classes & enums get bridge methods
499
// targetMethod may be inherited
500
if (inheritedMethodToBridge.returnType.erasure() == targetMethod.returnType.erasure()
501         && inheritedMethodToBridge.areParameterErasuresEqual(targetMethod)) {
502             return null; // do not need bridge method
503
}
504     if (this.synthetics == null)
505         this.synthetics = new HashMap JavaDoc[4];
506     if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) {
507         this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap JavaDoc(5);
508     } else {
509         // check to see if there is another equivalent inheritedMethod already added
510
Iterator JavaDoc synthMethods = this.synthetics[SourceTypeBinding.METHOD_EMUL].keySet().iterator();
511         while (synthMethods.hasNext()) {
512             Object JavaDoc synthetic = synthMethods.next();
513             if (synthetic instanceof MethodBinding) {
514                 MethodBinding method = (MethodBinding) synthetic;
515                 if (CharOperation.equals(inheritedMethodToBridge.selector, method.selector)
516                     && inheritedMethodToBridge.returnType.erasure() == method.returnType.erasure()
517                     && inheritedMethodToBridge.areParameterErasuresEqual(method)) {
518                         return null;
519                 }
520             }
521         }
522     }
523
524     SyntheticMethodBinding accessMethod = null;
525     SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);
526     if (accessors == null) {
527         accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, targetMethod, this);
528         this.synthetics[SourceTypeBinding.METHOD_EMUL].put(inheritedMethodToBridge, accessors = new SyntheticMethodBinding[2]);
529         accessors[1] = accessMethod;
530     } else {
531         if ((accessMethod = accessors[1]) == null) {
532             accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, targetMethod, this);
533             accessors[1] = accessMethod;
534         }
535     }
536     return accessMethod;
537 }
538 public int kind() {
539     if (this.typeVariables != Binding.NO_TYPE_VARIABLES) return Binding.GENERIC_TYPE;
540     return Binding.TYPE;
541 }
542 public char[] computeUniqueKey(boolean isLeaf) {
543     char[] uniqueKey = super.computeUniqueKey(isLeaf);
544     if (uniqueKey.length == 2) return uniqueKey; // problem type's unique key is "L;"
545
if (Util.isClassFileName(this.fileName)) return uniqueKey; // no need to insert compilation unit name for a .class file
546

547     // insert compilation unit name if the type name is not the main type name
548
int end = CharOperation.lastIndexOf('.', this.fileName);
549     if (end != -1) {
550         int start = CharOperation.lastIndexOf('/', this.fileName) + 1;
551         char[] mainTypeName = CharOperation.subarray(this.fileName, start, end);
552         start = CharOperation.lastIndexOf('/', uniqueKey) + 1;
553         if (start == 0)
554             start = 1; // start after L
555
end = CharOperation.indexOf('$', uniqueKey, start);
556         if (end == -1)
557             end = CharOperation.indexOf('<', uniqueKey, start);
558         if (end == -1)
559             end = CharOperation.indexOf(';', uniqueKey, start);
560         char[] topLevelType = CharOperation.subarray(uniqueKey, start, end);
561         if (!CharOperation.equals(topLevelType, mainTypeName)) {
562             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
563             buffer.append(uniqueKey, 0, start);
564             buffer.append(mainTypeName);
565             buffer.append('~');
566             buffer.append(topLevelType);
567             buffer.append(uniqueKey, end, uniqueKey.length - end);
568             int length = buffer.length();
569             uniqueKey = new char[length];
570             buffer.getChars(0, length, uniqueKey, 0);
571             return uniqueKey;
572         }
573     }
574     return uniqueKey;
575 }
576 void faultInTypesForFieldsAndMethods() {
577     // check @Deprecated annotation
578
getAnnotationTagBits(); // marks as deprecated by side effect
579
ReferenceBinding enclosingType = this.enclosingType();
580     if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !this.isDeprecated())
581         this.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;
582     fields();
583     methods();
584
585     for (int i = 0, length = this.memberTypes.length; i < length; i++)
586         ((SourceTypeBinding) this.memberTypes[i]).faultInTypesForFieldsAndMethods();
587 }
588 // NOTE: the type of each field of a source type is resolved when needed
589
public FieldBinding[] fields() {
590     if ((this.tagBits & TagBits.AreFieldsComplete) != 0)
591         return this.fields;
592
593     int failed = 0;
594     FieldBinding[] resolvedFields = this.fields;
595     try {
596         // lazily sort fields
597
if ((this.tagBits & TagBits.AreFieldsSorted) == 0) {
598             int length = this.fields.length;
599             if (length > 1)
600                 ReferenceBinding.sortFields(this.fields, 0, length);
601             this.tagBits |= TagBits.AreFieldsSorted;
602         }
603         for (int i = 0, length = this.fields.length; i < length; i++) {
604             if (resolveTypeFor(this.fields[i]) == null) {
605                 // do not alter original field array until resolution is over, due to reentrance (143259)
606
if (resolvedFields == this.fields) {
607                     System.arraycopy(this.fields, 0, resolvedFields = new FieldBinding[length], 0, length);
608                 }
609                 resolvedFields[i] = null;
610                 failed++;
611             }
612         }
613     } finally {
614         if (failed > 0) {
615             // ensure fields are consistent reqardless of the error
616
int newSize = resolvedFields.length - failed;
617             if (newSize == 0)
618                 return this.fields = Binding.NO_FIELDS;
619
620             FieldBinding[] newFields = new FieldBinding[newSize];
621             for (int i = 0, j = 0, length = resolvedFields.length; i < length; i++) {
622                 if (resolvedFields[i] != null)
623                     newFields[j++] = resolvedFields[i];
624             }
625             this.fields = newFields;
626         }
627     }
628     this.tagBits |= TagBits.AreFieldsComplete;
629     return this.fields;
630 }
631 /**
632  * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#genericTypeSignature()
633  */

634 public char[] genericTypeSignature() {
635     if (this.genericReferenceTypeSignature == null)
636         this.genericReferenceTypeSignature = computeGenericTypeSignature(this.typeVariables);
637     return this.genericReferenceTypeSignature;
638 }
639 /**
640  * <param1 ... paramN>superclass superinterface1 ... superinterfaceN
641  * <T:LY<TT;>;U:Ljava/lang/Object;V::Ljava/lang/Runnable;:Ljava/lang/Cloneable;:Ljava/util/Map;>Ljava/lang/Exception;Ljava/lang/Runnable;
642  */

643 public char[] genericSignature() {
644     StringBuffer JavaDoc sig = null;
645     if (this.typeVariables != Binding.NO_TYPE_VARIABLES) {
646         sig = new StringBuffer JavaDoc(10);
647         sig.append('<');
648         for (int i = 0, length = this.typeVariables.length; i < length; i++)
649             sig.append(this.typeVariables[i].genericSignature());
650         sig.append('>');
651     } else {