Makefile fixup
[org.ibex.tool.git] / repo / org.ibex.tool / src / org / eclipse / jdt / internal / compiler / lookup / SourceTypeBinding.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.Enumeration;
14 import java.util.Hashtable;
15
16 import org.eclipse.jdt.core.compiler.CharOperation;
17 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
18 import org.eclipse.jdt.internal.compiler.ast.Argument;
19 import org.eclipse.jdt.internal.compiler.ast.AssertStatement;
20 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
21 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
22 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
23 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
24 import org.eclipse.jdt.internal.compiler.ast.TypeReference;
25 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
26 import org.eclipse.jdt.internal.compiler.impl.Constant;
27 import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
28
29 public class SourceTypeBinding extends ReferenceBinding {
30         public ReferenceBinding superclass;
31         public ReferenceBinding[] superInterfaces;
32         public FieldBinding[] fields;
33         public MethodBinding[] methods;
34         public ReferenceBinding[] memberTypes;
35
36         public ClassScope scope;
37
38         // Synthetics are separated into 4 categories: methods, super methods, fields, class literals and changed declaring type bindings
39         public final static int METHOD_EMUL = 0;
40         public final static int FIELD_EMUL = 1;
41         public final static int CLASS_LITERAL_EMUL = 2;
42         public final static int RECEIVER_TYPE_EMUL = 3;
43         
44         Hashtable[] synthetics;
45         
46 public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) {
47         this.compoundName = compoundName;
48         this.fPackage = fPackage;
49         this.fileName = scope.referenceCompilationUnit().getFileName();
50         this.modifiers = scope.referenceContext.modifiers;
51         this.sourceName = scope.referenceContext.name;
52         this.scope = scope;
53
54         // expect the fields & methods to be initialized correctly later
55         this.fields = NoFields;
56         this.methods = NoMethods;
57
58         computeId();
59 }
60 private void addDefaultAbstractMethod(MethodBinding abstractMethod) {
61         MethodBinding defaultAbstract = new MethodBinding(
62                 abstractMethod.modifiers | AccDefaultAbstract,
63                 abstractMethod.selector,
64                 abstractMethod.returnType,
65                 abstractMethod.parameters,
66                 abstractMethod.thrownExceptions,
67                 this);
68
69         MethodBinding[] temp = new MethodBinding[methods.length + 1];
70         System.arraycopy(methods, 0, temp, 0, methods.length);
71         temp[methods.length] = defaultAbstract;
72         methods = temp;
73 }
74 public void addDefaultAbstractMethods() {
75         if ((tagBits & KnowsDefaultAbstractMethods) != 0) return;
76
77         tagBits |= KnowsDefaultAbstractMethods;
78
79         if (isClass() && isAbstract()) {
80                 if (fPackage.environment.options.targetJDK >= ClassFileConstants.JDK1_2) return; // no longer added for post 1.2 targets
81
82                 ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
83                 int lastPosition = 0;
84                 interfacesToVisit[lastPosition] = superInterfaces();
85
86                 for (int i = 0; i <= lastPosition; i++) {
87                         ReferenceBinding[] interfaces = interfacesToVisit[i];
88                         for (int j = 0, length = interfaces.length; j < length; j++) {
89                                 ReferenceBinding superType = interfaces[j];
90                                 if (superType.isValidBinding()) {
91                                         MethodBinding[] superMethods = superType.methods();
92                                         for (int m = superMethods.length; --m >= 0;) {
93                                                 MethodBinding method = superMethods[m];
94                                                 if (!implementsMethod(method))
95                                                         addDefaultAbstractMethod(method);
96                                         }
97
98                                         ReferenceBinding[] itsInterfaces = superType.superInterfaces();
99                                         if (itsInterfaces != NoSuperInterfaces) {
100                                                 if (++lastPosition == interfacesToVisit.length)
101                                                         System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
102                                                 interfacesToVisit[lastPosition] = itsInterfaces;
103                                         }
104                                 }
105                         }
106                 }
107         }
108 }
109 /* Add a new synthetic field for <actualOuterLocalVariable>.
110 *       Answer the new field or the existing field if one already existed.
111 */
112
113 public FieldBinding addSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
114         if (synthetics == null) {
115                 synthetics = new Hashtable[4];
116         }
117         if (synthetics[FIELD_EMUL] == null) {
118                 synthetics[FIELD_EMUL] = new Hashtable(5);
119         }
120         
121         FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get(actualOuterLocalVariable);
122         if (synthField == null) {
123                 synthField = new SyntheticFieldBinding(
124                         CharOperation.concat(SyntheticArgumentBinding.OuterLocalPrefix, actualOuterLocalVariable.name), 
125                         actualOuterLocalVariable.type, 
126                         AccPrivate | AccFinal | AccSynthetic, 
127                         this, 
128                         Constant.NotAConstant,
129                         synthetics[FIELD_EMUL].size());
130                 synthetics[FIELD_EMUL].put(actualOuterLocalVariable, synthField);
131         }
132
133         // ensure there is not already such a field defined by the user
134         boolean needRecheck;
135         int index = 1;
136         do {
137                 needRecheck = false;
138                 FieldBinding existingField;
139                 if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
140                         TypeDeclaration typeDecl = scope.referenceContext;
141                         for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
142                                 FieldDeclaration fieldDecl = typeDecl.fields[i];
143                                 if (fieldDecl.binding == existingField) {
144                                         synthField.name = CharOperation.concat(
145                                                 SyntheticArgumentBinding.OuterLocalPrefix,
146                                                 actualOuterLocalVariable.name,
147                                                 ("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
148                                         needRecheck = true;
149                                         break;
150                                 }
151                         }
152                 }
153         } while (needRecheck);
154         return synthField;
155 }
156 /* Add a new synthetic field for <enclosingType>.
157 *       Answer the new field or the existing field if one already existed.
158 */
159
160 public FieldBinding addSyntheticField(ReferenceBinding enclosingType) {
161
162         if (synthetics == null) {
163                 synthetics = new Hashtable[4];
164         }
165         if (synthetics[FIELD_EMUL] == null) {
166                 synthetics[FIELD_EMUL] = new Hashtable(5);
167         }
168
169         FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get(enclosingType);
170         if (synthField == null) {
171                 synthField = new SyntheticFieldBinding(
172                         CharOperation.concat(
173                                 SyntheticArgumentBinding.EnclosingInstancePrefix,
174                                 String.valueOf(enclosingType.depth()).toCharArray()),
175                         enclosingType,
176                         AccDefault | AccFinal | AccSynthetic,
177                         this,
178                         Constant.NotAConstant,
179                         synthetics[FIELD_EMUL].size());
180                 synthetics[FIELD_EMUL].put(enclosingType, synthField);
181         }
182         // ensure there is not already such a field defined by the user
183         FieldBinding existingField;
184         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
185                 TypeDeclaration typeDecl = scope.referenceContext;
186                 for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
187                         FieldDeclaration fieldDecl = typeDecl.fields[i];
188                         if (fieldDecl.binding == existingField) {
189                                 scope.problemReporter().duplicateFieldInType(this, fieldDecl);
190                                 break;
191                         }
192                 }
193         }               
194         return synthField;
195 }
196 /* Add a new synthetic field for a class literal access.
197 *       Answer the new field or the existing field if one already existed.
198 */
199
200 public FieldBinding addSyntheticField(TypeBinding targetType, BlockScope blockScope) {
201
202         if (synthetics == null) {
203                 synthetics = new Hashtable[4];
204         }
205         if (synthetics[CLASS_LITERAL_EMUL] == null) {
206                 synthetics[CLASS_LITERAL_EMUL] = new Hashtable(5);
207         }
208
209         // use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class.
210         FieldBinding synthField = (FieldBinding) synthetics[CLASS_LITERAL_EMUL].get(targetType);
211         if (synthField == null) {
212                 synthField = new SyntheticFieldBinding(
213                         ("class$" + synthetics[CLASS_LITERAL_EMUL].size()).toCharArray(), //$NON-NLS-1$
214                         blockScope.getJavaLangClass(),
215                         AccDefault | AccStatic | AccSynthetic,
216                         this,
217                         Constant.NotAConstant,
218                         synthetics[CLASS_LITERAL_EMUL].size());
219                 synthetics[CLASS_LITERAL_EMUL].put(targetType, synthField);
220         }
221         // ensure there is not already such a field defined by the user
222         FieldBinding existingField;
223         if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
224                 TypeDeclaration typeDecl = blockScope.referenceType();
225                 for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
226                         FieldDeclaration fieldDecl = typeDecl.fields[i];
227                         if (fieldDecl.binding == existingField) {
228                                 blockScope.problemReporter().duplicateFieldInType(this, fieldDecl);
229                                 break;
230                         }
231                 }
232         }               
233         return synthField;
234 }
235
236 /* Add a new synthetic field for the emulation of the assert statement.
237 *       Answer the new field or the existing field if one already existed.
238 */
239 public FieldBinding addSyntheticField(AssertStatement assertStatement, BlockScope blockScope) {
240
241         if (synthetics == null) {
242                 synthetics = new Hashtable[4];
243         }
244         if (synthetics[FIELD_EMUL] == null) {
245                 synthetics[FIELD_EMUL] = new Hashtable(5);
246         }
247
248         FieldBinding synthField = (FieldBinding) synthetics[FIELD_EMUL].get("assertionEmulation"); //$NON-NLS-1$
249         if (synthField == null) {
250                 synthField = new SyntheticFieldBinding(
251                         "$assertionsDisabled".toCharArray(), //$NON-NLS-1$
252                         BooleanBinding,
253                         AccDefault | AccStatic | AccSynthetic | AccFinal,
254                         this,
255                         Constant.NotAConstant,
256                         synthetics[FIELD_EMUL].size());
257                 synthetics[FIELD_EMUL].put("assertionEmulation", synthField); //$NON-NLS-1$
258         }
259         // ensure there is not already such a field defined by the user
260         // ensure there is not already such a field defined by the user
261         boolean needRecheck;
262         int index = 0;
263         do {
264                 needRecheck = false;
265                 FieldBinding existingField;
266                 if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {
267                         TypeDeclaration typeDecl = scope.referenceContext;
268                         for (int i = 0, max = typeDecl.fields.length; i < max; i++) {
269                                 FieldDeclaration fieldDecl = typeDecl.fields[i];
270                                 if (fieldDecl.binding == existingField) {
271                                         synthField.name = CharOperation.concat(
272                                                 "$assertionsDisabled".toCharArray(), //$NON-NLS-1$
273                                                 ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$
274                                         needRecheck = true;
275                                         break;
276                                 }
277                         }
278                 }
279         } while (needRecheck);
280         return synthField;
281 }
282
283 /* Add a new synthetic access method for read/write access to <targetField>.
284         Answer the new method or the existing method if one already existed.
285 */
286
287 public SyntheticAccessMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) {
288
289         if (synthetics == null) {
290                 synthetics = new Hashtable[4];
291         }
292         if (synthetics[METHOD_EMUL] == null) {
293                 synthetics[METHOD_EMUL] = new Hashtable(5);
294         }
295
296         SyntheticAccessMethodBinding accessMethod = null;
297         SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(targetField);
298         if (accessors == null) {
299                 accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this);
300                 synthetics[METHOD_EMUL].put(targetField, accessors = new SyntheticAccessMethodBinding[2]);
301                 accessors[isReadAccess ? 0 : 1] = accessMethod;         
302         } else {
303                 if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) {
304                         accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this);
305                         accessors[isReadAccess ? 0 : 1] = accessMethod;
306                 }
307         }
308         return accessMethod;
309 }
310 /* Add a new synthetic access method for access to <targetMethod>.
311  * Must distinguish access method used for super access from others (need to use invokespecial bytecode)
312         Answer the new method or the existing method if one already existed.
313 */
314
315 public SyntheticAccessMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) {
316
317         if (synthetics == null) {
318                 synthetics = new Hashtable[4];
319         }
320         if (synthetics[METHOD_EMUL] == null) {
321                 synthetics[METHOD_EMUL] = new Hashtable(5);
322         }
323
324         SyntheticAccessMethodBinding accessMethod = null;
325         SyntheticAccessMethodBinding[] accessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(targetMethod);
326         if (accessors == null) {
327                 accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this);
328                 synthetics[METHOD_EMUL].put(targetMethod, accessors = new SyntheticAccessMethodBinding[2]);
329                 accessors[isSuperAccess ? 0 : 1] = accessMethod;                
330         } else {
331                 if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) {
332                         accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this);
333                         accessors[isSuperAccess ? 0 : 1] = accessMethod;
334                 }
335         }
336         return accessMethod;
337 }
338
339 public FieldBinding[] availableFields() {
340         return fields();
341 }
342 public MethodBinding[] availableMethods() {
343         return methods();
344 }
345 void faultInTypesForFieldsAndMethods() {
346         fields();
347         methods();
348
349         for (int i = 0, length = memberTypes.length; i < length; i++)
350                 ((SourceTypeBinding) memberTypes[i]).faultInTypesForFieldsAndMethods();
351 }
352 // NOTE: the type of each field of a source type is resolved when needed
353
354 public FieldBinding[] fields() {
355         
356         try {
357                 int failed = 0;
358                 for (int f = 0, max = fields.length; f < max; f++) {
359                         if (resolveTypeFor(fields[f]) == null) {
360                                 fields[f] = null;
361                                 failed++;
362                         }
363                 }
364                 if (failed > 0) {
365                         int newSize = fields.length - failed;
366                         if (newSize == 0)
367                                 return fields = NoFields;
368         
369                         FieldBinding[] newFields = new FieldBinding[newSize];
370                         for (int i = 0, n = 0, max = fields.length; i < max; i++)
371                                 if (fields[i] != null)
372                                         newFields[n++] = fields[i];
373                         fields = newFields;
374                 }
375         } catch(AbortCompilation e){
376                 // ensure null fields are removed
377                 FieldBinding[] newFields = null;
378                 int count = 0;
379                 for (int i = 0, max = fields.length; i < max; i++){
380                         FieldBinding field = fields[i];
381                         if (field == null && newFields == null){
382                                 System.arraycopy(fields, 0, newFields = new FieldBinding[max], 0, i);
383                         } else if (newFields != null && field != null) {
384                                 newFields[count++] = field;
385                         }
386                 }
387                 if (newFields != null){
388                         System.arraycopy(newFields, 0, fields = new FieldBinding[count], 0, count);
389                 }                       
390                 throw e;
391         }
392         return fields;
393 }
394 public MethodBinding[] getDefaultAbstractMethods() {
395         int count = 0;
396         for (int i = methods.length; --i >= 0;)
397                 if (methods[i].isDefaultAbstract())
398                         count++;
399         if (count == 0) return NoMethods;
400
401         MethodBinding[] result = new MethodBinding[count];
402         count = 0;
403         for (int i = methods.length; --i >= 0;)
404                 if (methods[i].isDefaultAbstract())
405                         result[count++] = methods[i];
406         return result;
407 }
408 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
409
410 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
411         int argCount = argumentTypes.length;
412
413         if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods
414                 nextMethod : for (int m = methods.length; --m >= 0;) {
415                         MethodBinding method = methods[m];
416                         if (method.selector == ConstructorDeclaration.ConstantPoolName && method.parameters.length == argCount) {
417                                 TypeBinding[] toMatch = method.parameters;
418                                 for (int p = 0; p < argCount; p++)
419                                         if (toMatch[p] != argumentTypes[p])
420                                                 continue nextMethod;
421                                 return method;
422                         }
423                 }
424         } else {
425                 MethodBinding[] constructors = getMethods(ConstructorDeclaration.ConstantPoolName); // takes care of duplicates & default abstract methods
426                 nextConstructor : for (int c = constructors.length; --c >= 0;) {
427                         MethodBinding constructor = constructors[c];
428                         TypeBinding[] toMatch = constructor.parameters;
429                         if (toMatch.length == argCount) {
430                                 for (int p = 0; p < argCount; p++)
431                                         if (toMatch[p] != argumentTypes[p])
432                                                 continue nextConstructor;
433                                 return constructor;
434                         }
435                 }
436         }
437         return null;
438 }
439 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
440 // searches up the hierarchy as long as no potential (but not exact) match was found.
441
442 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) {
443         int argCount = argumentTypes.length;
444         int selectorLength = selector.length;
445         boolean foundNothing = true;
446
447         if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods
448                 nextMethod : for (int m = methods.length; --m >= 0;) {
449                         MethodBinding method = methods[m];
450                         if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
451                                 foundNothing = false; // inner type lookups must know that a method with this name exists
452                                 if (method.parameters.length == argCount) {
453                                         TypeBinding[] toMatch = method.parameters;
454                                         for (int p = 0; p < argCount; p++)
455                                                 if (toMatch[p] != argumentTypes[p])
456                                                         continue nextMethod;
457                                         return method;
458                                 }
459                         }
460                 }
461         } else {
462                 MethodBinding[] matchingMethods = getMethods(selector); // takes care of duplicates & default abstract methods
463                 foundNothing = matchingMethods == NoMethods;
464                 nextMethod : for (int m = matchingMethods.length; --m >= 0;) {
465                         MethodBinding method = matchingMethods[m];
466                         TypeBinding[] toMatch = method.parameters;
467                         if (toMatch.length == argCount) {
468                                 for (int p = 0; p < argCount; p++)
469                                         if (toMatch[p] != argumentTypes[p])
470                                                 continue nextMethod;
471                                 return method;
472                         }
473                 }
474         }
475
476         if (foundNothing) {
477                 if (isInterface()) {
478                          if (superInterfaces.length == 1)
479                                 return superInterfaces[0].getExactMethod(selector, argumentTypes);
480                 } else if (superclass != null) {
481                         return superclass.getExactMethod(selector, argumentTypes);
482                 }
483         }
484         return null;
485 }
486 // NOTE: the type of a field of a source type is resolved when needed
487
488 public FieldBinding getField(char[] fieldName, boolean needResolve) {
489         // always resolve anyway on source types
490         int fieldLength = fieldName.length;
491         for (int f = fields.length; --f >= 0;) {
492                 FieldBinding field = fields[f];
493                 if (field.name.length == fieldLength && CharOperation.equals(field.name, fieldName)) {
494                         if (resolveTypeFor(field) != null)
495                                 return field;
496
497                         int newSize = fields.length - 1;
498                         if (newSize == 0) {
499                                 fields = NoFields;
500                         } else {
501                                 FieldBinding[] newFields = new FieldBinding[newSize];
502                                 System.arraycopy(fields, 0, newFields, 0, f);
503                                 System.arraycopy(fields, f + 1, newFields, f, newSize - f);
504                                 fields = newFields;
505                         }
506                         return null;
507                 }
508         }
509         return null;
510 }
511 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
512
513 public MethodBinding[] getMethods(char[] selector) {
514         // handle forward references to potential default abstract methods
515         addDefaultAbstractMethods();
516
517         try{
518                 int count = 0;
519                 int lastIndex = -1;
520                 int selectorLength = selector.length;
521                 if ((modifiers & AccUnresolved) == 0) { // have resolved all arg types & return type of the methods
522                         for (int m = 0, length = methods.length; m < length; m++) {
523                                 MethodBinding method = methods[m];
524                                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
525                                         count++;
526                                         lastIndex = m;
527                                 }
528                         }
529                 } else {
530                         boolean foundProblem = false;
531                         int failed = 0;
532                         for (int m = 0, length = methods.length; m < length; m++) {
533                                 MethodBinding method = methods[m];
534                                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
535                                         if (resolveTypesFor(method) == null) {
536                                                 foundProblem = true;
537                                                 methods[m] = null; // unable to resolve parameters
538                                                 failed++;
539                                         } else if (method.returnType == null) {
540                                                 foundProblem = true;
541                                         } else {
542                                                 count++;
543                                                 lastIndex = m;
544                                         }
545                                 }
546                         }
547         
548                         if (foundProblem || count > 1) {
549                                 for (int m = methods.length; --m >= 0;) {
550                                         MethodBinding method = methods[m];
551                                         if (method != null && method.selector.length == selectorLength && CharOperation.equals(method.selector, selector)) {
552                                                 AbstractMethodDeclaration methodDecl = null;
553                                                 for (int i = 0; i < m; i++) {
554                                                         MethodBinding method2 = methods[i];
555                                                         if (method2 != null && CharOperation.equals(method.selector, method2.selector)) {
556                                                                 if (method.areParametersEqual(method2)) {
557                                                                         if (methodDecl == null) {
558                                                                                 methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost
559                                                                                 scope.problemReporter().duplicateMethodInType(this, methodDecl);
560                                                                                 methodDecl.binding = null;
561                                                                                 methods[m] = null;
562                                                                                 failed++;
563                                                                         }
564                                                                         scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod());
565                                                                         method2.sourceMethod().binding = null;
566                                                                         methods[i] = null;
567                                                                         failed++;
568                                                                 }
569                                                         }
570                                                 }
571                                                 if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
572                                                         method.sourceMethod().binding = null;
573                                                         methods[m] = null;
574                                                         failed++;
575                                                 }
576                                         }
577                                 }
578         
579                                 if (failed > 0) {
580                                         int newSize = methods.length - failed;
581                                         if (newSize == 0)
582                                                 return methods = NoMethods;
583         
584                                         MethodBinding[] newMethods = new MethodBinding[newSize];
585                                         for (int i = 0, n = 0, max = methods.length; i < max; i++)
586                                                 if (methods[i] != null)
587                                                         newMethods[n++] = methods[i];
588                                         methods = newMethods;
589                                         return getMethods(selector); // try again now that the problem methods have been removed
590                                 }
591                         }
592                 }
593                 if (count == 1)
594                         return new MethodBinding[] {methods[lastIndex]};
595                 if (count > 1) {
596                         MethodBinding[] result = new MethodBinding[count];
597                         count = 0;
598                         for (int m = 0; m <= lastIndex; m++) {
599                                 MethodBinding method = methods[m];
600                                 if (method.selector.length == selectorLength && CharOperation.equals(method.selector, selector))
601                                         result[count++] = method;
602                         }
603                         return result;
604                 }
605         } catch(AbortCompilation e){
606                 // ensure null methods are removed
607                 MethodBinding[] newMethods = null;
608                 int count = 0;
609                 for (int i = 0, max = methods.length; i < max; i++){
610                         MethodBinding method = methods[i];
611                         if (method == null && newMethods == null){
612                                 System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i);
613                         } else if (newMethods != null && method != null) {
614                                 newMethods[count++] = method;
615                         }
616                 }
617                 if (newMethods != null){
618                         System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count);
619                 }                       
620                 modifiers ^= AccUnresolved;
621                 throw e;
622         }               
623         return NoMethods;
624 }
625 /* Answer the synthetic field for <actualOuterLocalVariable>
626 *       or null if one does not exist.
627 */
628
629 public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
630         
631         if (synthetics == null || synthetics[FIELD_EMUL] == null) return null;
632         return (FieldBinding) synthetics[FIELD_EMUL].get(actualOuterLocalVariable);
633 }
634 public ReferenceBinding[] memberTypes() {
635         return this.memberTypes;
636 }
637 public FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) {
638
639         if (this.synthetics == null) {
640                 this.synthetics = new Hashtable[4];
641         }
642         if (this.synthetics[RECEIVER_TYPE_EMUL] == null) {
643                 this.synthetics[RECEIVER_TYPE_EMUL] = new Hashtable(5);
644         }
645
646         Hashtable fieldMap = (Hashtable) this.synthetics[RECEIVER_TYPE_EMUL].get(targetField);
647         if (fieldMap == null) {
648                 fieldMap = new Hashtable(5);
649                 this.synthetics[RECEIVER_TYPE_EMUL].put(targetField, fieldMap);
650         }
651         FieldBinding updatedField = (FieldBinding) fieldMap.get(newDeclaringClass);
652         if (updatedField == null){
653                 updatedField = new FieldBinding(targetField, newDeclaringClass);
654                 fieldMap.put(newDeclaringClass, updatedField);
655         }
656         return updatedField;
657 }
658
659 public MethodBinding getUpdatedMethodBinding(MethodBinding targetMethod, ReferenceBinding newDeclaringClass) {
660
661         if (this.synthetics == null) {
662                 this.synthetics = new Hashtable[4];
663         }
664         if (this.synthetics[RECEIVER_TYPE_EMUL] == null) {
665                 this.synthetics[RECEIVER_TYPE_EMUL] = new Hashtable(5);
666         }
667
668
669         Hashtable methodMap = (Hashtable) synthetics[RECEIVER_TYPE_EMUL].get(targetMethod);
670         if (methodMap == null) {
671                 methodMap = new Hashtable(5);
672                 this.synthetics[RECEIVER_TYPE_EMUL].put(targetMethod, methodMap);
673         }
674         MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass);
675         if (updatedMethod == null){
676                 updatedMethod = new MethodBinding(targetMethod, newDeclaringClass);
677                 methodMap.put(newDeclaringClass, updatedMethod);
678         }
679         return updatedMethod;
680 }
681 public boolean hasMemberTypes() {
682     return this.memberTypes.length > 0;
683 }
684 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
685 public MethodBinding[] methods() {
686         try {
687                 if ((modifiers & AccUnresolved) == 0)
688                         return methods;
689         
690                 int failed = 0;
691                 for (int m = 0, max = methods.length; m < max; m++) {
692                         if (resolveTypesFor(methods[m]) == null) {
693                                 methods[m] = null; // unable to resolve parameters
694                                 failed++;
695                         }
696                 }
697         
698                 for (int m = methods.length; --m >= 0;) {
699                         MethodBinding method = methods[m];
700                         if (method != null) {
701                                 AbstractMethodDeclaration methodDecl = null;
702                                 for (int i = 0; i < m; i++) {
703                                         MethodBinding method2 = methods[i];
704                                         if (method2 != null && CharOperation.equals(method.selector, method2.selector)) {
705                                                 if (method.areParametersEqual(method2)) {
706                                                         if (methodDecl == null) {
707                                                                 methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost
708                                                                 scope.problemReporter().duplicateMethodInType(this, methodDecl);
709                                                                 methodDecl.binding = null;
710                                                                 methods[m] = null;
711                                                                 failed++;
712                                                         }
713                                                         scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod());
714                                                         method2.sourceMethod().binding = null;
715                                                         methods[i] = null;
716                                                         failed++;
717                                                 }
718                                         }
719                                 }
720                                 if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
721                                         method.sourceMethod().binding = null;
722                                         methods[m] = null;
723                                         failed++;
724                                 }
725                         }
726                 }
727         
728                 if (failed > 0) {
729                         int newSize = methods.length - failed;
730                         if (newSize == 0) {
731                                 methods = NoMethods;
732                         } else {
733                                 MethodBinding[] newMethods = new MethodBinding[newSize];
734                                 for (int m = 0, n = 0, max = methods.length; m < max; m++)
735                                         if (methods[m] != null)
736                                                 newMethods[n++] = methods[m];
737                                 methods = newMethods;
738                         }
739                 }
740         
741                 // handle forward references to potential default abstract methods
742                 addDefaultAbstractMethods();
743         } catch(AbortCompilation e){
744                 // ensure null methods are removed
745                 MethodBinding[] newMethods = null;
746                 int count = 0;
747                 for (int i = 0, max = methods.length; i < max; i++){
748                         MethodBinding method = methods[i];
749                         if (method == null && newMethods == null){
750                                 System.arraycopy(methods, 0, newMethods = new MethodBinding[max], 0, i);
751                         } else if (newMethods != null && method != null) {
752                                 newMethods[count++] = method;
753                         }
754                 }
755                 if (newMethods != null){
756                         System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count);
757                 }                       
758                 modifiers ^= AccUnresolved;
759                 throw e;
760         }               
761         modifiers ^= AccUnresolved;
762         return methods;
763 }
764 private FieldBinding resolveTypeFor(FieldBinding field) {
765         if ((field.modifiers & AccUnresolved) == 0)
766                 return field;
767
768         FieldDeclaration[] fieldDecls = scope.referenceContext.fields;
769         for (int f = 0, length = fieldDecls.length; f < length; f++) {
770                 if (fieldDecls[f].binding != field)
771                         continue;
772
773                 field.type = fieldDecls[f].getTypeBinding(scope);
774                 field.modifiers ^= AccUnresolved;
775                 if (!field.type.isValidBinding()) {
776                         scope.problemReporter().fieldTypeProblem(this, fieldDecls[f], field.type);
777                         //scope.problemReporter().invalidType(fieldDecls[f].type, field.type);
778                         fieldDecls[f].binding = null;
779                         return null;
780                 }
781                 if (field.type == VoidBinding) {
782                         scope.problemReporter().variableTypeCannotBeVoid(fieldDecls[f]);
783                         fieldDecls[f].binding = null;
784                         return null;
785                 }
786                 if (field.type.isArrayType() && ((ArrayBinding) field.type).leafComponentType == VoidBinding) {
787                         scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecls[f]);
788                         fieldDecls[f].binding = null;
789                         return null;
790                 }
791                 return field;
792         }
793         return null; // should never reach this point
794 }
795 private MethodBinding resolveTypesFor(MethodBinding method) {
796         if ((method.modifiers & AccUnresolved) == 0)
797                 return method;
798
799         AbstractMethodDeclaration methodDecl = method.sourceMethod();
800         TypeReference[] exceptionTypes = methodDecl.thrownExceptions;
801         if (exceptionTypes != null) {
802                 int size = exceptionTypes.length;
803                 method.thrownExceptions = new ReferenceBinding[size];
804                 ReferenceBinding throwable = scope.getJavaLangThrowable();
805                 int count = 0;
806                 ReferenceBinding resolvedExceptionType;
807                 for (int i = 0; i < size; i++) {
808                         resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].getTypeBinding(scope);
809                         if (!resolvedExceptionType.isValidBinding()) {
810                                 methodDecl.scope.problemReporter().exceptionTypeProblem(this, methodDecl, exceptionTypes[i], resolvedExceptionType);
811                                 //methodDecl.scope.problemReporter().invalidType(exceptionTypes[i], resolvedExceptionType);
812                                 continue;
813                         }
814                         if (throwable != resolvedExceptionType && !throwable.isSuperclassOf(resolvedExceptionType)) {
815                                 methodDecl.scope.problemReporter().cannotThrowType(this, methodDecl, exceptionTypes[i], resolvedExceptionType);
816                                 continue;
817                         }
818                         method.thrownExceptions[count++] = resolvedExceptionType;
819                 }
820                 if (count < size)
821                         System.arraycopy(method.thrownExceptions, 0, method.thrownExceptions = new ReferenceBinding[count], 0, count);
822         }
823
824         boolean foundArgProblem = false;
825         Argument[] arguments = methodDecl.arguments;
826         if (arguments != null) {
827                 int size = arguments.length;
828                 method.parameters = new TypeBinding[size];
829                 for (int i = 0; i < size; i++) {
830                         Argument arg = arguments[i];
831                         method.parameters[i] = arg.type.getTypeBinding(scope);
832                         if (!method.parameters[i].isValidBinding()) {
833                                 methodDecl.scope.problemReporter().argumentTypeProblem(this, methodDecl, arg, method.parameters[i]);
834                                 //methodDecl.scope.problemReporter().invalidType(arg, method.parameters[i]);
835                                 foundArgProblem = true;
836                         } else if (method.parameters[i] == VoidBinding) {
837                                 methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(this, methodDecl, arg);
838                                 foundArgProblem = true;
839                         } else if (method.parameters[i].isArrayType() && ((ArrayBinding) method.parameters[i]).leafComponentType == VoidBinding) {
840                                 methodDecl.scope.problemReporter().argumentTypeCannotBeVoidArray(this, methodDecl, arg);
841                                 foundArgProblem = true;
842                         }
843                 }
844         }
845
846         boolean foundReturnTypeProblem = false;
847         if (!method.isConstructor()) {
848                 TypeReference returnType = ((MethodDeclaration) methodDecl).returnType;
849                 if (returnType == null) {
850                         methodDecl.scope.problemReporter().missingReturnType(methodDecl);
851                         method.returnType = null;
852                         foundReturnTypeProblem = true;
853                 } else {
854                         method.returnType = returnType.getTypeBinding(scope);
855                         if (!method.returnType.isValidBinding()) {
856                                 methodDecl.scope.problemReporter().returnTypeProblem(this, (MethodDeclaration) methodDecl, method.returnType);
857                                 //methodDecl.scope.problemReporter().invalidType(returnType, method.returnType);
858                                 method.returnType = null;
859                                 foundReturnTypeProblem = true;
860                         } else if (method.returnType.isArrayType() && ((ArrayBinding) method.returnType).leafComponentType == VoidBinding) {
861                                 methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray(this, (MethodDeclaration) methodDecl);
862                                 method.returnType = null;
863                                 foundReturnTypeProblem = true;
864                         }
865                 }
866         }
867         if (foundArgProblem) {
868                 methodDecl.binding = null;
869                 return null;
870         }
871         if (foundReturnTypeProblem)
872                 return method; // but its still unresolved with a null return type & is still connected to its method declaration
873
874         method.modifiers ^= AccUnresolved;
875         return method;
876 }
877 public final int sourceEnd() {
878         return scope.referenceContext.sourceEnd;
879 }
880 public final int sourceStart() {
881         return scope.referenceContext.sourceStart;
882 }
883 public ReferenceBinding superclass() {
884         return superclass;
885 }
886 public ReferenceBinding[] superInterfaces() {
887         return superInterfaces;
888 }
889 public SyntheticAccessMethodBinding[] syntheticAccessMethods() {
890         
891         if (synthetics == null || synthetics[METHOD_EMUL] == null || synthetics[METHOD_EMUL].size() == 0) return null;
892
893         // difficult to compute size up front because of the embedded arrays so assume there is only 1
894         int index = 0;
895         SyntheticAccessMethodBinding[] bindings = new SyntheticAccessMethodBinding[1];
896         Enumeration fieldsOrMethods = synthetics[METHOD_EMUL].keys();
897         while (fieldsOrMethods.hasMoreElements()) {
898
899                 Object fieldOrMethod = fieldsOrMethods.nextElement();
900
901                 if (fieldOrMethod instanceof MethodBinding) {
902
903                         SyntheticAccessMethodBinding[] methodAccessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(fieldOrMethod);
904                         int numberOfAccessors = 0;
905                         if (methodAccessors[0] != null) numberOfAccessors++;
906                         if (methodAccessors[1] != null) numberOfAccessors++;
907                         if (index + numberOfAccessors > bindings.length)
908                                 System.arraycopy(bindings, 0, (bindings = new SyntheticAccessMethodBinding[index + numberOfAccessors]), 0, index);
909                         if (methodAccessors[0] != null) 
910                                 bindings[index++] = methodAccessors[0]; // super access 
911                         if (methodAccessors[1] != null) 
912                                 bindings[index++] = methodAccessors[1]; // normal access
913
914                 } else {
915
916                         SyntheticAccessMethodBinding[] fieldAccessors = (SyntheticAccessMethodBinding[]) synthetics[METHOD_EMUL].get(fieldOrMethod);
917                         int numberOfAccessors = 0;
918                         if (fieldAccessors[0] != null) numberOfAccessors++;
919                         if (fieldAccessors[1] != null) numberOfAccessors++;
920                         if (index + numberOfAccessors > bindings.length)
921                                 System.arraycopy(bindings, 0, (bindings = new SyntheticAccessMethodBinding[index + numberOfAccessors]), 0, index);
922                         if (fieldAccessors[0] != null) 
923                                 bindings[index++] = fieldAccessors[0]; // read access
924                         if (fieldAccessors[1] != null) 
925                                 bindings[index++] = fieldAccessors[1]; // write access
926                 }
927         }
928
929         // sort them in according to their own indexes
930         int length;
931         SyntheticAccessMethodBinding[] sortedBindings = new SyntheticAccessMethodBinding[length = bindings.length];
932         for (int i = 0; i < length; i++){
933                 SyntheticAccessMethodBinding binding = bindings[i];
934                 sortedBindings[binding.index] = binding;
935         }
936         return sortedBindings;
937 }
938 /**
939  * Answer the collection of synthetic fields to append into the classfile
940  */
941 public FieldBinding[] syntheticFields() {
942         
943         if (synthetics == null) return null;
944
945         int fieldSize = synthetics[FIELD_EMUL] == null ? 0 : synthetics[FIELD_EMUL].size();
946         int literalSize = synthetics[CLASS_LITERAL_EMUL] == null ? 0 :synthetics[CLASS_LITERAL_EMUL].size();
947         int totalSize = fieldSize + literalSize;
948         if (totalSize == 0) return null;
949         FieldBinding[] bindings = new FieldBinding[totalSize];
950
951         // add innerclass synthetics
952         if (synthetics[FIELD_EMUL] != null){
953                 Enumeration elements = synthetics[FIELD_EMUL].elements();
954                 for (int i = 0; i < fieldSize; i++) {
955                         SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement();
956                         bindings[synthBinding.index] = synthBinding;
957                 }
958         }
959         // add class literal synthetics
960         if (synthetics[CLASS_LITERAL_EMUL] != null){
961                 Enumeration elements = synthetics[CLASS_LITERAL_EMUL].elements();
962                 for (int i = 0; i < literalSize; i++) {
963                         SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.nextElement();
964                         bindings[fieldSize+synthBinding.index] = synthBinding;
965                 }
966         }
967         return bindings;
968 }
969 public String toString() {
970         String s = "(id="+(id == NoId ? "NoId" : (""+id) ) +")\n"; //$NON-NLS-3$ //$NON-NLS-2$ //$NON-NLS-4$ //$NON-NLS-1$
971
972         if (isDeprecated()) s += "deprecated "; //$NON-NLS-1$
973         if (isPublic()) s += "public "; //$NON-NLS-1$
974         if (isProtected()) s += "protected "; //$NON-NLS-1$
975         if (isPrivate()) s += "private "; //$NON-NLS-1$
976         if (isAbstract() && isClass()) s += "abstract "; //$NON-NLS-1$
977         if (isStatic() && isNestedType()) s += "static "; //$NON-NLS-1$
978         if (isFinal()) s += "final "; //$NON-NLS-1$
979
980         s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
981         s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
982
983         s += "\n\textends "; //$NON-NLS-1$
984         s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
985
986         if (superInterfaces != null) {
987                 if (superInterfaces != NoSuperInterfaces) {
988                         s += "\n\timplements : "; //$NON-NLS-1$
989                         for (int i = 0, length = superInterfaces.length; i < length; i++) {
990                                 if (i  > 0)
991                                         s += ", "; //$NON-NLS-1$
992                                 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
993                         }
994                 }
995         } else {
996                 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
997         }
998
999         if (enclosingType() != null) {
1000                 s += "\n\tenclosing type : "; //$NON-NLS-1$
1001                 s += enclosingType().debugName();
1002         }
1003
1004         if (fields != null) {
1005                 if (fields != NoFields) {
1006                         s += "\n/*   fields   */"; //$NON-NLS-1$
1007                         for (int i = 0, length = fields.length; i < length; i++)
1008                                 s += (fields[i] != null) ? "\n" + fields[i].toString() : "\nNULL FIELD"; //$NON-NLS-1$ //$NON-NLS-2$
1009                 }
1010         } else {
1011                 s += "NULL FIELDS"; //$NON-NLS-1$
1012         }
1013
1014         if (methods != null) {
1015                 if (methods != NoMethods) {
1016                         s += "\n/*   methods   */"; //$NON-NLS-1$
1017                         for (int i = 0, length = methods.length; i < length; i++)
1018                                 s += (methods[i] != null) ? "\n" + methods[i].toString() : "\nNULL METHOD"; //$NON-NLS-1$ //$NON-NLS-2$
1019                 }
1020         } else {
1021                 s += "NULL METHODS"; //$NON-NLS-1$
1022         }
1023
1024         if (memberTypes != null) {
1025                 if (memberTypes != NoMemberTypes) {
1026                         s += "\n/*   members   */"; //$NON-NLS-1$
1027                         for (int i = 0, length = memberTypes.length; i < length; i++)
1028                                 s += (memberTypes[i] != null) ? "\n" + memberTypes[i].toString() : "\nNULL TYPE"; //$NON-NLS-1$ //$NON-NLS-2$
1029                 }
1030         } else {
1031                 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
1032         }
1033
1034         s += "\n\n\n"; //$NON-NLS-1$
1035         return s;
1036 }
1037 void verifyMethods(MethodVerifier verifier) {
1038         verifier.verify(this);
1039
1040         for (int i = memberTypes.length; --i >= 0;)
1041                  ((SourceTypeBinding) memberTypes[i]).verifyMethods(verifier);
1042 }
1043
1044 /* Answer the synthetic field for <targetEnclosingType>
1045 *       or null if one does not exist.
1046 */
1047
1048 public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) {
1049
1050         if (synthetics == null || synthetics[FIELD_EMUL] == null) return null;
1051         FieldBinding field = (FieldBinding) synthetics[FIELD_EMUL].get(targetEnclosingType);
1052         if (field != null) return field;
1053
1054         // type compatibility : to handle cases such as
1055         // class T { class M{}}
1056         // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N().
1057         if (!onlyExactMatch){
1058                 Enumeration accessFields = synthetics[FIELD_EMUL].elements();
1059                 while (accessFields.hasMoreElements()) {
1060                         field = (FieldBinding) accessFields.nextElement();
1061                         if (CharOperation.prefixEquals(SyntheticArgumentBinding.EnclosingInstancePrefix, field.name)
1062                                 && targetEnclosingType.isSuperclassOf((ReferenceBinding) field.type))
1063                                         return field;
1064                 }
1065         }
1066         return null;
1067 }
1068 }