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