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