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
 
   9  *     IBM Corporation - initial API and implementation
 
  10  *******************************************************************************/
 
  11 package net.sourceforge.phpdt.internal.compiler.lookup;
 
  13 import java.util.Enumeration;
 
  14 import java.util.Hashtable;
 
  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;
 
  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;
 
  36         public ClassScope scope;
 
  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;
 
  44         Hashtable[] synthetics;
 
  46 protected SourceTypeBinding() {
 
  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;
 
  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,
 
  67         MethodBinding[] temp = new MethodBinding[methods.length + 1];
 
  68         System.arraycopy(methods, 0, temp, 0, methods.length);
 
  69         temp[methods.length] = defaultAbstract;
 
  72 public void addDefaultAbstractMethods() {
 
  73         if ((tagBits & KnowsDefaultAbstractMethods) != 0) return;
 
  75         tagBits |= KnowsDefaultAbstractMethods;
 
  77         if (isClass() && isAbstract()) {
 
  78 //              if (fPackage.environment.options.targetJDK >= CompilerOptions.JDK1_2) return; // no longer added for post 1.2 targets
 
  80                 ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
 
  82                 interfacesToVisit[lastPosition] = superInterfaces();
 
  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);
 
  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;
 
 107 /* Add a new synthetic field for <actualOuterLocalVariable>.
 
 108 *       Answer the new field or the existing field if one already existed.
 
 111 public FieldBinding addSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
 
 112         if (synthetics == null) {
 
 113                 synthetics = new Hashtable[4];
 
 115         if (synthetics[FIELD] == null) {
 
 116                 synthetics[FIELD] = new Hashtable(5);
 
 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, 
 
 126                         Constant.NotAConstant,
 
 127                         synthetics[FIELD].size());
 
 128                 synthetics[FIELD].put(actualOuterLocalVariable, synthField);
 
 131         // ensure there is not already such a field defined by the user
 
 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$
 
 151         } while (needRecheck);
 
 154 /* Add a new synthetic field for <enclosingType>.
 
 155 *       Answer the new field or the existing field if one already existed.
 
 158 public FieldBinding addSyntheticField(ReferenceBinding enclosingType) {
 
 160         if (synthetics == null) {
 
 161                 synthetics = new Hashtable[4];
 
 163         if (synthetics[FIELD] == null) {
 
 164                 synthetics[FIELD] = new Hashtable(5);
 
 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()),
 
 174                         AccDefault | AccFinal,// | AccSynthetic,
 
 176                         Constant.NotAConstant,
 
 177                         synthetics[FIELD].size());
 
 178                 synthetics[FIELD].put(enclosingType, synthField);
 
 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);
 
 194 /* Add a new synthetic field for a class literal access.
 
 195 *       Answer the new field or the existing field if one already existed.
 
 198 public FieldBinding addSyntheticField(TypeBinding targetType, BlockScope blockScope) {
 
 200         if (synthetics == null) {
 
 201                 synthetics = new Hashtable[4];
 
 203         if (synthetics[CLASS_LITERAL] == null) {
 
 204                 synthetics[CLASS_LITERAL] = new Hashtable(5);
 
 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,
 
 215                         Constant.NotAConstant,
 
 216                         synthetics[CLASS_LITERAL].size());
 
 217                 synthetics[CLASS_LITERAL].put(targetType, synthField);
 
 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);
 
 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.
 
 237 public FieldBinding addSyntheticField(AssertStatement assertStatement, BlockScope blockScope) {
 
 239         if (synthetics == null) {
 
 240                 synthetics = new Hashtable[4];
 
 242         if (synthetics[FIELD] == null) {
 
 243                 synthetics[FIELD] = new Hashtable(5);
 
 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$
 
 251                         AccDefault | AccStatic | AccFinal,//| AccSynthetic | AccFinal,
 
 253                         Constant.NotAConstant,
 
 254                         synthetics[FIELD].size());
 
 255                 synthetics[FIELD].put("assertionEmulation", synthField); //$NON-NLS-1$
 
 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
 
 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$
 
 277         } while (needRecheck);
 
 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.
 
 285 public SyntheticAccessMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) {
 
 287         if (synthetics == null) {
 
 288                 synthetics = new Hashtable[4];
 
 290         if (synthetics[METHOD] == null) {
 
 291                 synthetics[METHOD] = new Hashtable(5);
 
 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;         
 
 301                 if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) {
 
 302                         accessMethod = new SyntheticAccessMethodBinding(targetField, isReadAccess, this);
 
 303                         accessors[isReadAccess ? 0 : 1] = accessMethod;
 
 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.
 
 313 public SyntheticAccessMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) {
 
 315         if (synthetics == null) {
 
 316                 synthetics = new Hashtable[4];
 
 318         if (synthetics[METHOD] == null) {
 
 319                 synthetics[METHOD] = new Hashtable(5);
 
 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;                
 
 329                 if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) {
 
 330                         accessMethod = new SyntheticAccessMethodBinding(targetMethod, isSuperAccess, this);
 
 331                         accessors[isSuperAccess ? 0 : 1] = accessMethod;
 
 337 public FieldBinding[] availableFields() {
 
 340 public MethodBinding[] availableMethods() {
 
 343 void faultInTypesForFieldsAndMethods() {
 
 347         for (int i = 0, length = memberTypes.length; i < length; i++)
 
 348                 ((SourceTypeBinding) memberTypes[i]).faultInTypesForFieldsAndMethods();
 
 350 // NOTE: the type of each field of a source type is resolved when needed
 
 352 public FieldBinding[] fields() {
 
 354                 fields = new FieldBinding[0];
 
 358                 for (int f = 0, max = fields.length; f < max; f++) {
 
 359                         if (resolveTypeFor(fields[f]) == null) {
 
 365                         int newSize = fields.length - failed;
 
 367                                 return fields = NoFields;
 
 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];
 
 375         } catch(AbortCompilation e){
 
 376                 // ensure null fields are removed
 
 377                 FieldBinding[] newFields = null;
 
 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;
 
 387                 if (newFields != null){
 
 388                         System.arraycopy(newFields, 0, fields = new FieldBinding[count], 0, count);
 
 394 public MethodBinding[] getDefaultAbstractMethods() {
 
 396         for (int i = methods.length; --i >= 0;)
 
 397                 if (methods[i].isDefaultAbstract())
 
 399         if (count == 0) return NoMethods;
 
 401         MethodBinding[] result = new MethodBinding[count];
 
 403         for (int i = methods.length; --i >= 0;)
 
 404                 if (methods[i].isDefaultAbstract())
 
 405                         result[count++] = methods[i];
 
 408 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 
 410 public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {
 
 411         int argCount = argumentTypes.length;
 
 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])
 
 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])
 
 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.
 
 442 public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes) {
 
 443         int argCount = argumentTypes.length;
 
 444         int selectorLength = selector.length;
 
 445         boolean foundNothing = true;
 
 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])
 
 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])
 
 478                          if (superInterfaces.length == 1)
 
 479                                 return superInterfaces[0].getExactMethod(selector, argumentTypes);
 
 480                 } else if (superclass != null) {
 
 481                         return superclass.getExactMethod(selector, argumentTypes);
 
 486 // NOTE: the type of a field of a source type is resolved when needed
 
 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)
 
 496                         int newSize = fields.length - 1;
 
 500                                 FieldBinding[] newFields = new FieldBinding[newSize];
 
 501                                 System.arraycopy(fields, 0, newFields, 0, f);
 
 502                                 System.arraycopy(fields, f + 1, newFields, f, newSize - f);
 
 510 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 
 512 public MethodBinding[] getMethods(char[] selector) {
 
 513         // handle forward references to potential default abstract methods
 
 514         addDefaultAbstractMethods();
 
 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)) {
 
 529                         boolean foundProblem = false;
 
 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) {
 
 536                                                 methods[m] = null; // unable to resolve parameters
 
 538                                         } else if (method.returnType == null) {
 
 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;
 
 563                                                                         scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod());
 
 564                                                                         method2.sourceMethod().binding = null;
 
 570                                                 if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
 
 571                                                         method.sourceMethod().binding = null;
 
 579                                         int newSize = methods.length - failed;
 
 581                                                 return methods = NoMethods;
 
 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
 
 593                         return new MethodBinding[] {methods[lastIndex]};
 
 595                         MethodBinding[] result = new MethodBinding[count];
 
 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;
 
 604         } catch(AbortCompilation e){
 
 605                 // ensure null methods are removed
 
 606                 MethodBinding[] newMethods = null;
 
 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;
 
 616                 if (newMethods != null){
 
 617                         System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count);
 
 619                 modifiers ^= AccUnresolved;
 
 624 /* Answer the synthetic field for <actualOuterLocalVariable>
 
 625 *       or null if one does not exist.
 
 628 public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) {
 
 630         if (synthetics == null || synthetics[FIELD] == null) return null;
 
 631         return (FieldBinding) synthetics[FIELD].get(actualOuterLocalVariable);
 
 633 public ReferenceBinding[] memberTypes() {
 
 636 public FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) {
 
 638         if (synthetics == null) {
 
 639                 synthetics = new Hashtable[4];
 
 641         if (synthetics[CHANGED_DECLARING_CLASS] == null) {
 
 642                 synthetics[CHANGED_DECLARING_CLASS] = new Hashtable(5);
 
 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);
 
 650         FieldBinding updatedField = (FieldBinding) fieldMap.get(newDeclaringClass);
 
 651         if (updatedField == null){
 
 652                 updatedField = new FieldBinding(targetField, newDeclaringClass);
 
 653                 fieldMap.put(newDeclaringClass, updatedField);
 
 658 public MethodBinding getUpdatedMethodBinding(MethodBinding targetMethod, ReferenceBinding newDeclaringClass) {
 
 660         if (synthetics == null) {
 
 661                 synthetics = new Hashtable[4];
 
 663         if (synthetics[CHANGED_DECLARING_CLASS] == null) {
 
 664                 synthetics[CHANGED_DECLARING_CLASS] = new Hashtable(5);
 
 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);
 
 673         MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass);
 
 674         if (updatedMethod == null){
 
 675                 updatedMethod = new MethodBinding(targetMethod, newDeclaringClass);
 
 676                 methodMap.put(newDeclaringClass, updatedMethod);
 
 678         return updatedMethod;
 
 681 // NOTE: the return type, arg & exception types of each method of a source type are resolved when needed
 
 682 public MethodBinding[] methods() {
 
 684                 if ((modifiers & AccUnresolved) == 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
 
 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;
 
 710                                                         scope.problemReporter().duplicateMethodInType(this, method2.sourceMethod());
 
 711                                                         method2.sourceMethod().binding = null;
 
 717                                 if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions
 
 718                                         method.sourceMethod().binding = null;
 
 726                         int newSize = methods.length - failed;
 
 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;
 
 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;
 
 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;
 
 752                 if (newMethods != null){
 
 753                         System.arraycopy(newMethods, 0, methods = new MethodBinding[count], 0, count);
 
 755                 modifiers ^= AccUnresolved;
 
 758         modifiers ^= AccUnresolved;
 
 761 private FieldBinding resolveTypeFor(FieldBinding field) {
 
 762         if (field.type != null)
 
 765         FieldDeclaration[] fieldDecls = scope.referenceContext.fields;
 
 766         for (int f = 0, length = fieldDecls.length; f < length; f++) {
 
 767                 if (fieldDecls[f].binding != field)
 
 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;
 
 777                 if (field.type == VoidBinding) {
 
 778                         scope.problemReporter().variableTypeCannotBeVoid(fieldDecls[f]);
 
 779                         fieldDecls[f].binding = null;
 
 782                 if (field.type.isArrayType() && ((ArrayBinding) field.type).leafComponentType == VoidBinding) {
 
 783                         scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecls[f]);
 
 784                         fieldDecls[f].binding = null;
 
 789         return null; // should never reach this point
 
 791 private MethodBinding resolveTypesFor(MethodBinding method) {
 
 792         if ((method.modifiers & AccUnresolved) == 0)
 
 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();
 
 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);
 
 810                         if (throwable != resolvedExceptionType && !throwable.isSuperclassOf(resolvedExceptionType)) {
 
 811                                 methodDecl.scope.problemReporter().cannotThrowType(this, methodDecl, exceptionTypes[i], resolvedExceptionType);
 
 814                         method.thrownExceptions[count++] = resolvedExceptionType;
 
 817                         System.arraycopy(method.thrownExceptions, 0, method.thrownExceptions = new ReferenceBinding[count], 0, count);
 
 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;
 
 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;
 
 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;
 
 863         if (foundArgProblem) {
 
 864                 methodDecl.binding = null;
 
 867         if (foundReturnTypeProblem)
 
 868                 return method; // but its still unresolved with a null return type & is still connected to its method declaration
 
 870         method.modifiers ^= AccUnresolved;
 
 873 public final int sourceEnd() {
 
 874         return scope.referenceContext.sourceEnd;
 
 876 public final int sourceStart() {
 
 877         return scope.referenceContext.sourceStart;
 
 879 public ReferenceBinding superclass() {
 
 882 public ReferenceBinding[] superInterfaces() {
 
 883         return superInterfaces;
 
 885 public SyntheticAccessMethodBinding[] syntheticAccessMethods() {
 
 887         if (synthetics == null || synthetics[METHOD] == null || synthetics[METHOD].size() == 0) return null;
 
 889         // difficult to compute size up front because of the embedded arrays so assume there is only 1
 
 891         SyntheticAccessMethodBinding[] bindings = new SyntheticAccessMethodBinding[1];
 
 892         Enumeration fieldsOrMethods = synthetics[METHOD].keys();
 
 893         while (fieldsOrMethods.hasMoreElements()) {
 
 895                 Object fieldOrMethod = fieldsOrMethods.nextElement();
 
 897                 if (fieldOrMethod instanceof MethodBinding) {
 
 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
 
 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
 
 925         // sort them in according to their own indexes
 
 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;
 
 932         return sortedBindings;
 
 935  * Answer the collection of synthetic fields to append into the classfile
 
 937 public FieldBinding[] syntheticFields() {
 
 939         if (synthetics == null) return null;
 
 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];
 
 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;
 
 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;
 
 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$
 
 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$
 
 976         s += isInterface() ? "interface " : "class "; //$NON-NLS-1$ //$NON-NLS-2$
 
 977         s += (compoundName != null) ? CharOperation.toString(compoundName) : "UNNAMED TYPE"; //$NON-NLS-1$
 
 979         s += "\n\textends "; //$NON-NLS-1$
 
 980         s += (superclass != null) ? superclass.debugName() : "NULL TYPE"; //$NON-NLS-1$
 
 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++) {
 
 987                                         s += ", "; //$NON-NLS-1$
 
 988                                 s += (superInterfaces[i] != null) ? superInterfaces[i].debugName() : "NULL TYPE"; //$NON-NLS-1$
 
 992                 s += "NULL SUPERINTERFACES"; //$NON-NLS-1$
 
 995         if (enclosingType() != null) {
 
 996                 s += "\n\tenclosing type : "; //$NON-NLS-1$
 
 997                 s += enclosingType().debugName();
 
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$
 
1007                 s += "NULL FIELDS"; //$NON-NLS-1$
 
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$
 
1017                 s += "NULL METHODS"; //$NON-NLS-1$
 
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$
 
1027                 s += "NULL MEMBER TYPES"; //$NON-NLS-1$
 
1030         s += "\n\n\n"; //$NON-NLS-1$
 
1033 void verifyMethods(MethodVerifier verifier) {
 
1034         verifier.verify(this);
 
1036         for (int i = memberTypes.length; --i >= 0;)
 
1037                  ((SourceTypeBinding) memberTypes[i]).verifyMethods(verifier);
 
1040 /* Answer the synthetic field for <targetEnclosingType>
 
1041 *       or null if one does not exist.
 
1044 public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) {
 
1046         if (synthetics == null || synthetics[FIELD] == null) return null;
 
1047         FieldBinding field = (FieldBinding) synthetics[FIELD].get(targetEnclosingType);
 
1048         if (field != null) return field;
 
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))