Tweaks to make JDT use less memory.

- Changed options to not build javadoc, suppress warnings, etc.
- Shadowing SourceTypeBinding to use our lightweight HashMap.
- Jsni collection was pinning entire compilation unit source.

Review by: spoon

git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@5162 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
index 10a7660..a26150b 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JdtCompiler.java
@@ -25,6 +25,7 @@
 import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
 import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
 import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
 import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
@@ -194,32 +195,21 @@
   }
 
   public static CompilerOptions getCompilerOptions() {
-    Map<String, String> settings = new HashMap<String, String>();
-    settings.put(CompilerOptions.OPTION_LineNumberAttribute,
-        CompilerOptions.GENERATE);
-    settings.put(CompilerOptions.OPTION_SourceFileAttribute,
-        CompilerOptions.GENERATE);
-    /*
-     * Tricks like "boolean stopHere = true;" depend on this setting to work in
-     * hosted mode. In web mode, our compiler should optimize them out once we
-     * do real data flow.
-     */
-    settings.put(CompilerOptions.OPTION_PreserveUnusedLocal,
-        CompilerOptions.PRESERVE);
-    settings.put(CompilerOptions.OPTION_ReportDeprecation,
-        CompilerOptions.IGNORE);
-    settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
-        CompilerOptions.GENERATE);
+    CompilerOptions options = new CompilerOptions();
+    options.complianceLevel = options.sourceLevel = options.targetJDK = ClassFileConstants.JDK1_6;
 
-    /*
-     * Wish we could target 1.5 class file, but this isn't allowed. :(
-     */
-    settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_1_6);
-    settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_1_6);
-    settings.put(CompilerOptions.OPTION_TargetPlatform,
-        CompilerOptions.VERSION_1_6);
+    // Generate debug info for debugging the output.
+    options.produceDebugAttributes = ClassFileConstants.ATTR_VARS
+        | ClassFileConstants.ATTR_LINES | ClassFileConstants.ATTR_SOURCE;
+    // Tricks like "boolean stopHere = true;" depend on this setting.
+    options.preserveAllLocalVariables = true;
 
-    return new CompilerOptions(settings);
+    // Turn off all warnings, saves some memory / speed.
+    options.reportUnusedDeclaredThrownExceptionIncludeDocCommentReference = false;
+    options.reportUnusedDeclaredThrownExceptionExemptExceptionAndThrowable = false;
+    options.warningThreshold = 0;
+    options.inlineJsrBytecode = true;
+    return options;
   }
 
   /**
@@ -232,8 +222,6 @@
    */
   private final Map<String, String> binaryTypesRefs = new HashMap<String, String>();
 
-  private final CompilerImpl compiler = new CompilerImpl();
-
   private final Set<String> notPackages = new HashSet<String>();
 
   private final Set<String> packages = new HashSet<String>();
@@ -262,7 +250,7 @@
     }
 
     PerfLogger.start("JdtCompiler.compile");
-    compiler.compile(icus.toArray(new ICompilationUnit[icus.size()]));
+    new CompilerImpl().compile(icus.toArray(new ICompilationUnit[icus.size()]));
     PerfLogger.end();
     return true;
   }
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
index b514a13..40b03cb 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniCollector.java
@@ -63,10 +63,10 @@
     private final String location;
     private final String name;
     private final String[] paramNames;
-    private final String source;
     private final JsProgram program;
+    private char[] source;
 
-    private JsniMethodImpl(String name, String source, String[] paramNames,
+    private JsniMethodImpl(String name, char[] source, String[] paramNames,
         int line, String location, JsProgram program) {
       this.name = name;
       this.source = source;
@@ -79,8 +79,9 @@
     @Override
     public JsFunction function(TreeLogger logger) {
       if (func == null) {
-        func = parseAsAnonymousFunction(logger, program, source, paramNames,
-            location, line);
+        func = parseAsAnonymousFunction(logger, program,
+            String.valueOf(source), paramNames, location, line);
+        source = null;
       }
       return func;
     }
@@ -111,11 +112,6 @@
     }
 
     @Override
-    public String source() {
-      return source;
-    }
-
-    @Override
     public String toString() {
       StringBuffer sb = new StringBuffer();
       sb.append("function ");
@@ -130,8 +126,8 @@
         }
         sb.append(paramName);
       }
-      sb.append("} {\n");
-      sb.append(source);
+      sb.append(") {\n");
+      sb.append("  [...]");
       sb.append("}\n");
       return sb.toString();
     }
@@ -183,8 +179,8 @@
         String jsniSignature = getJsniSignature(enclosingType, method);
         String[] paramNames = getParamNames(method);
 
-        jsniMethods.add(new JsniMethodImpl(jsniSignature, js, paramNames,
-            startLine, loc, program));
+        jsniMethods.add(new JsniMethodImpl(jsniSignature, js.toCharArray(),
+            paramNames, startLine, loc, program));
       }
     }
     return jsniMethods;
diff --git a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
index 6e51146..075e0f5 100644
--- a/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
+++ b/dev/core/src/com/google/gwt/dev/javac/JsniMethod.java
@@ -53,9 +53,4 @@
    * Gets the JsProgram in which {@link #function(TreeLogger)} is located.
    */
   public abstract JsProgram program();
-
-  /**
-   * The script body.
-   */
-  public abstract String source();
 }
diff --git a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
index de70859..5c60f50 100644
--- a/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
+++ b/dev/core/src/com/google/gwt/dev/jdt/AbstractCompiler.java
@@ -49,7 +49,6 @@
 
 import java.net.URL;
 import java.util.Comparator;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
@@ -89,7 +88,7 @@
     }
 
     @Override
-    public void process(CompilationUnitDeclaration cud, int index) {
+    public void process(CompilationUnitDeclaration unit, int index) {
 
       long processBeginNanos = System.nanoTime();
 
@@ -97,46 +96,66 @@
       // with the modification that cud.generateCode is conditionally called
       // based on doGenerateBytes
       {
-        this.parser.getMethodBodies(cud);
+        this.lookupEnvironment.unitBeingCompleted = unit;
+        long parseStart = System.currentTimeMillis();
+
+        this.parser.getMethodBodies(unit);
+
+        long resolveStart = System.currentTimeMillis();
+        this.stats.parseTime += resolveStart - parseStart;
 
         // fault in fields & methods
-        if (cud.scope != null) {
-          cud.scope.faultInTypes();
+        if (unit.scope != null) {
+          unit.scope.faultInTypes();
         }
 
         // verify inherited methods
-        if (cud.scope != null) {
-          cud.scope.verifyMethods(lookupEnvironment.methodVerifier());
+        if (unit.scope != null) {
+          unit.scope.verifyMethods(lookupEnvironment.methodVerifier());
         }
 
         // type checking
-        cud.resolve();
+        unit.resolve();
+
+        long analyzeStart = System.currentTimeMillis();
+        this.stats.resolveTime += analyzeStart - resolveStart;
 
         // flow analysis
-        cud.analyseCode();
+        unit.analyseCode();
+
+        long generateStart = System.currentTimeMillis();
+        this.stats.analyzeTime += generateStart - analyzeStart;
 
         // code generation
+        // code generation
         if (doGenerateBytes) {
-          cud.generateCode();
+          unit.generateCode();
         }
 
         // reference info
-        if (options.produceReferenceInfo && cud.scope != null) {
-          cud.scope.storeDependencyInfo();
+        if (options.produceReferenceInfo && unit.scope != null) {
+          unit.scope.storeDependencyInfo();
         }
 
+        // finalize problems (suppressWarnings)
+        unit.finalizeProblems();
+
+        this.stats.generateTime += System.currentTimeMillis() - generateStart;
+
         // refresh the total number of units known at this stage
-        cud.compilationResult.totalUnitsKnown = totalUnits;
+        unit.compilationResult.totalUnitsKnown = totalUnits;
+
+        this.lookupEnvironment.unitBeingCompleted = null;
       }
 
-      ICompilationUnit cu = cud.compilationResult.compilationUnit;
+      ICompilationUnit cu = unit.compilationResult.compilationUnit;
       String loc = String.valueOf(cu.getFileName());
       TreeLogger logger = threadLogger.branch(TreeLogger.SPAM,
           "Scanning for additional dependencies: " + loc, null);
 
       // Examine the cud for magic types.
       //
-      String[] typeNames = doFindAdditionalTypesUsingJsni(logger, cud);
+      String[] typeNames = doFindAdditionalTypesUsingJsni(logger, unit);
 
       // Accept each new compilation unit.
       //
@@ -148,7 +167,7 @@
         resolvePossiblyNestedType(typeName);
       }
 
-      typeNames = doFindAdditionalTypesUsingRebinds(logger, cud);
+      typeNames = doFindAdditionalTypesUsingRebinds(logger, unit);
 
       // Accept each new compilation unit, and check for instantiability
       //
@@ -164,12 +183,12 @@
         resolvePossiblyNestedType(typeName);
       }
 
-      doCompilationUnitDeclarationValidation(cud, logger);
+      doCompilationUnitDeclarationValidation(unit, logger);
 
       // Optionally remember this cud.
       //
       if (cuds != null) {
-        cuds.add(cud);
+        cuds.add(unit);
       }
 
       jdtProcessNanos += System.nanoTime() - processBeginNanos;
@@ -286,13 +305,7 @@
     }
 
     public NameEnvironmentAnswer findType(char[][] compoundTypeName) {
-
-      // Cache the answers to findType to prevent the creation of more
-      // CompilationUnitDeclarations than needed.
       String qname = CharOperation.toString(compoundTypeName);
-      if (nameEnvironmentAnswerForTypeName.containsKey(qname)) {
-        return (nameEnvironmentAnswerForTypeName.get(qname));
-      }
       TreeLogger logger = threadLogger.branch(TreeLogger.SPAM,
           "Compiler is asking about '" + qname + "'", null);
 
@@ -308,19 +321,13 @@
       int pos = qname.indexOf('$');
       if (pos >= 0) {
         qname = qname.substring(0, pos);
-        // Recheck the cache for the outer type.
-        if (nameEnvironmentAnswerForTypeName.containsKey(qname)) {
-          return (nameEnvironmentAnswerForTypeName.get(qname));
-        }
       }
       CompilationUnit unit = findCompilationUnit(qname);
       if (unit != null) {
         logger.log(TreeLogger.SPAM, "Found type in compilation unit: "
             + unit.getDisplayLocation());
         ICompilationUnit icu = new CompilationUnitAdapter(unit);
-        NameEnvironmentAnswer out = new NameEnvironmentAnswer(icu, null);
-        nameEnvironmentAnswerForTypeName.put(qname, out);
-        return out;
+        return new NameEnvironmentAnswer(icu, null);
       } else {
         ClassLoader classLoader = getClassLoader();
         URL resourceURL = classLoader.getResource(className.replace('.', '/')
@@ -337,9 +344,7 @@
             ClassFileReader cfr;
             try {
               cfr = new ClassFileReader(classBytes, null);
-              NameEnvironmentAnswer out = new NameEnvironmentAnswer(cfr, null);
-              nameEnvironmentAnswerForTypeName.put(qname, out);
-              return out;
+              return new NameEnvironmentAnswer(cfr, null);
             } catch (ClassFormatException e) {
               // Ignored.
             }
@@ -423,6 +428,15 @@
     }
   };
 
+  public static CompilerOptions getCompilerOptions() {
+    CompilerOptions options = JdtCompiler.getCompilerOptions();
+
+    // Turn off all debugging for web mode.
+    options.produceDebugAttributes = 0;
+    options.preserveAllLocalVariables = false;
+    return options;
+  }
+
   protected final CompilationState compilationState;
 
   protected final ThreadLocalTreeLoggerProxy threadLogger = new ThreadLocalTreeLoggerProxy();
@@ -433,8 +447,6 @@
 
   private final Set<String> knownPackages = new HashSet<String>();
 
-  private final Map<String, NameEnvironmentAnswer> nameEnvironmentAnswerForTypeName = new HashMap<String, NameEnvironmentAnswer>();
-
   private final Set<String> packages = new HashSet<String>();
 
   protected AbstractCompiler(CompilationState compilationState,
@@ -447,7 +459,7 @@
     IErrorHandlingPolicy pol = DefaultErrorHandlingPolicies.proceedWithAllProblems();
     IProblemFactory probFact = new DefaultProblemFactory(Locale.getDefault());
     ICompilerRequestor req = new ICompilerRequestorImpl();
-    CompilerOptions options = JdtCompiler.getCompilerOptions();
+    CompilerOptions options = getCompilerOptions();
 
     // This is only needed by TypeOracleBuilder to parse metadata.
     options.docCommentSupport = false;
diff --git a/dev/core/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java b/dev/core/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
new file mode 100644
index 0000000..8a19cba
--- /dev/null
+++ b/dev/core/src/org/eclipse/jdt/internal/compiler/lookup/SourceTypeBinding.java
@@ -0,0 +1,1672 @@
+/*******************************************************************************

+ * Copyright (c) 2000, 2008 IBM Corporation and others.

+ * All rights reserved. This program and the accompanying materials

+ * are made available under the terms of the Eclipse Public License v1.0

+ * which accompanies this distribution, and is available at

+ * http://www.eclipse.org/legal/epl-v10.html

+ *

+ * Contributors:

+ *     IBM Corporation - initial API and implementation

+ *******************************************************************************/

+package org.eclipse.jdt.internal.compiler.lookup;

+

+import com.google.gwt.dev.util.collect.HashMap;

+

+import org.eclipse.jdt.core.compiler.CharOperation;

+import org.eclipse.jdt.internal.compiler.ast.ASTNode;

+import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;

+import org.eclipse.jdt.internal.compiler.ast.AbstractVariableDeclaration;

+import org.eclipse.jdt.internal.compiler.ast.Argument;

+import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;

+import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;

+import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;

+import org.eclipse.jdt.internal.compiler.ast.TypeParameter;

+import org.eclipse.jdt.internal.compiler.ast.TypeReference;

+import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;

+import org.eclipse.jdt.internal.compiler.impl.Constant;

+import org.eclipse.jdt.internal.compiler.util.SimpleLookupTable;

+import org.eclipse.jdt.internal.compiler.util.Util;

+

+import java.util.Hashtable;

+import java.util.Iterator;

+

+public class SourceTypeBinding extends ReferenceBinding {

+  public ReferenceBinding superclass;

+  public ReferenceBinding[] superInterfaces;

+  private FieldBinding[] fields;

+  private MethodBinding[] methods;

+  public ReferenceBinding[] memberTypes;

+  public TypeVariableBinding[] typeVariables;

+

+  public ClassScope scope;

+

+  // Synthetics are separated into 5 categories: methods, super methods, fields, class literals, changed declaring type bindings and bridge methods

+  // if a new category is added, also increment MAX_SYNTHETICS

+  private final static int METHOD_EMUL = 0;

+  private final static int FIELD_EMUL = 1;

+  private final static int CLASS_LITERAL_EMUL = 2;

+  private final static int RECEIVER_TYPE_EMUL = 3;

+  

+  private final static int MAX_SYNTHETICS = 4;

+

+  HashMap[] synthetics;

+  char[] genericReferenceTypeSignature;

+

+  private SimpleLookupTable storedAnnotations = null; // keys are this ReferenceBinding & its fields and methods, value is an AnnotationHolder

+

+public SourceTypeBinding(char[][] compoundName, PackageBinding fPackage, ClassScope scope) {

+  this.compoundName = compoundName;

+  this.fPackage = fPackage;

+  this.fileName = scope.referenceCompilationUnit().getFileName();

+  this.modifiers = scope.referenceContext.modifiers;

+  this.sourceName = scope.referenceContext.name;

+  this.scope = scope;

+

+  // expect the fields & methods to be initialized correctly later

+  this.fields = Binding.UNINITIALIZED_FIELDS;

+  this.methods = Binding.UNINITIALIZED_METHODS;

+

+  computeId();

+}

+

+private void addDefaultAbstractMethods() {

+  if ((this.tagBits & TagBits.KnowsDefaultAbstractMethods) != 0) return;

+

+  this.tagBits |= TagBits.KnowsDefaultAbstractMethods;

+  if (isClass() && isAbstract()) {

+    if (this.scope.compilerOptions().targetJDK >= ClassFileConstants.JDK1_2)

+      return; // no longer added for post 1.2 targets

+

+    ReferenceBinding[] itsInterfaces = superInterfaces();

+    if (itsInterfaces != Binding.NO_SUPERINTERFACES) {

+      MethodBinding[] defaultAbstracts = null;

+      int defaultAbstractsCount = 0;

+      ReferenceBinding[] interfacesToVisit = itsInterfaces;

+      int nextPosition = interfacesToVisit.length;

+      for (int i = 0; i < nextPosition; i++) {

+        ReferenceBinding superType = interfacesToVisit[i];

+        if (superType.isValidBinding()) {

+          MethodBinding[] superMethods = superType.methods();

+          nextAbstractMethod: for (int m = superMethods.length; --m >= 0;) {

+            MethodBinding method = superMethods[m];

+            // explicitly implemented ?

+            if (implementsMethod(method))

+              continue nextAbstractMethod;

+            if (defaultAbstractsCount == 0) {

+              defaultAbstracts = new MethodBinding[5];

+            } else {

+              // already added as default abstract ?

+              for (int k = 0; k < defaultAbstractsCount; k++) {

+                MethodBinding alreadyAdded = defaultAbstracts[k];

+                if (CharOperation.equals(alreadyAdded.selector, method.selector) && alreadyAdded.areParametersEqual(method))

+                  continue nextAbstractMethod;

+              }

+            }

+            MethodBinding defaultAbstract = new MethodBinding(

+                method.modifiers | ExtraCompilerModifiers.AccDefaultAbstract | ClassFileConstants.AccSynthetic,

+                method.selector,

+                method.returnType,

+                method.parameters,

+                method.thrownExceptions,

+                this);

+            if (defaultAbstractsCount == defaultAbstracts.length)

+              System.arraycopy(defaultAbstracts, 0, defaultAbstracts = new MethodBinding[2 * defaultAbstractsCount], 0, defaultAbstractsCount);

+            defaultAbstracts[defaultAbstractsCount++] = defaultAbstract;

+          }

+

+          if ((itsInterfaces = superType.superInterfaces()) != Binding.NO_SUPERINTERFACES) {

+            int itsLength = itsInterfaces.length;

+            if (nextPosition + itsLength >= interfacesToVisit.length)

+              System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[nextPosition + itsLength + 5], 0, nextPosition);

+            nextInterface : for (int a = 0; a < itsLength; a++) {

+              ReferenceBinding next = itsInterfaces[a];

+              for (int b = 0; b < nextPosition; b++)

+                if (next == interfacesToVisit[b]) continue nextInterface;

+              interfacesToVisit[nextPosition++] = next;

+            }

+          }

+        }

+      }

+      if (defaultAbstractsCount > 0) {

+        int length = this.methods.length;

+        System.arraycopy(this.methods, 0, this.methods = new MethodBinding[length + defaultAbstractsCount], 0, length);

+        System.arraycopy(defaultAbstracts, 0, this.methods, length, defaultAbstractsCount);

+        // re-sort methods

+        length = length + defaultAbstractsCount;

+        if (length > 1)

+          ReferenceBinding.sortMethods(this.methods, 0, length);

+        // this.tagBits |= TagBits.AreMethodsSorted; -- already set in #methods()

+      }

+    }

+  }

+}

+/* Add a new synthetic field for <actualOuterLocalVariable>.

+* Answer the new field or the existing field if one already existed.

+*/

+public FieldBinding addSyntheticFieldForInnerclass(LocalVariableBinding actualOuterLocalVariable) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap();

+  

+  FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable);

+  if (synthField == null) {

+    synthField = new SyntheticFieldBinding(

+      CharOperation.concat(TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX, actualOuterLocalVariable.name), 

+      actualOuterLocalVariable.type, 

+      ClassFileConstants.AccPrivate | ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic, 

+      this, 

+      Constant.NotAConstant,

+      this.synthetics[SourceTypeBinding.FIELD_EMUL].size());

+    this.synthetics[SourceTypeBinding.FIELD_EMUL].put(actualOuterLocalVariable, synthField);

+  }

+

+  // ensure there is not already such a field defined by the user

+  boolean needRecheck;

+  int index = 1;

+  do {

+    needRecheck = false;

+    FieldBinding existingField;

+    if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {

+      TypeDeclaration typeDecl = this.scope.referenceContext;

+      for (int i = 0, max = typeDecl.fields.length; i < max; i++) {

+        FieldDeclaration fieldDecl = typeDecl.fields[i];

+        if (fieldDecl.binding == existingField) {

+          synthField.name = CharOperation.concat(

+            TypeConstants.SYNTHETIC_OUTER_LOCAL_PREFIX,

+            actualOuterLocalVariable.name,

+            ("$" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$

+          needRecheck = true;

+          break;

+        }

+      }

+    }

+  } while (needRecheck);

+  return synthField;

+}

+/* Add a new synthetic field for <enclosingType>.

+* Answer the new field or the existing field if one already existed.

+*/

+public FieldBinding addSyntheticFieldForInnerclass(ReferenceBinding enclosingType) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap();

+

+  FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(enclosingType);

+  if (synthField == null) {

+    synthField = new SyntheticFieldBinding(

+      CharOperation.concat(

+        TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX,

+        String.valueOf(enclosingType.depth()).toCharArray()),

+      enclosingType,

+      ClassFileConstants.AccDefault | ClassFileConstants.AccFinal | ClassFileConstants.AccSynthetic,

+      this,

+      Constant.NotAConstant,

+      this.synthetics[SourceTypeBinding.FIELD_EMUL].size());

+    this.synthetics[SourceTypeBinding.FIELD_EMUL].put(enclosingType, synthField);

+  }

+  // ensure there is not already such a field defined by the user

+  boolean needRecheck;

+  do {

+    needRecheck = false;

+    FieldBinding existingField;

+    if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {

+      TypeDeclaration typeDecl = this.scope.referenceContext;

+      for (int i = 0, max = typeDecl.fields.length; i < max; i++) {

+        FieldDeclaration fieldDecl = typeDecl.fields[i];

+        if (fieldDecl.binding == existingField) {

+          if (this.scope.compilerOptions().complianceLevel >= ClassFileConstants.JDK1_5) {

+            synthField.name = CharOperation.concat(

+              synthField.name,

+              "$".toCharArray()); //$NON-NLS-1$

+            needRecheck = true;

+          } else {

+            this.scope.problemReporter().duplicateFieldInType(this, fieldDecl);

+          }

+          break;

+        }

+      }

+    }

+  } while (needRecheck);

+  return synthField;

+}

+/* Add a new synthetic field for a class literal access.

+* Answer the new field or the existing field if one already existed.

+*/

+public FieldBinding addSyntheticFieldForClassLiteral(TypeBinding targetType, BlockScope blockScope) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] == null)

+    this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] = new HashMap();

+

+  // use a different table than FIELDS, given there might be a collision between emulation of X.this$0 and X.class.

+  FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].get(targetType);

+  if (synthField == null) {

+    synthField = new SyntheticFieldBinding(

+      CharOperation.concat(

+        TypeConstants.SYNTHETIC_CLASS,

+        String.valueOf(this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size()).toCharArray()),

+      blockScope.getJavaLangClass(),

+      ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic,

+      this,

+      Constant.NotAConstant,

+      this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size());

+    this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].put(targetType, synthField);

+  }

+  // ensure there is not already such a field defined by the user

+  FieldBinding existingField;

+  if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {

+    TypeDeclaration typeDecl = blockScope.referenceType();

+    for (int i = 0, max = typeDecl.fields.length; i < max; i++) {

+      FieldDeclaration fieldDecl = typeDecl.fields[i];

+      if (fieldDecl.binding == existingField) {

+        blockScope.problemReporter().duplicateFieldInType(this, fieldDecl);

+        break;

+      }

+    }

+  }   

+  return synthField;

+}

+/* Add a new synthetic field for the emulation of the assert statement.

+* Answer the new field or the existing field if one already existed.

+*/

+public FieldBinding addSyntheticFieldForAssert(BlockScope blockScope) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap();

+

+  FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get("assertionEmulation"); //$NON-NLS-1$

+  if (synthField == null) {

+    synthField = new SyntheticFieldBinding(

+      TypeConstants.SYNTHETIC_ASSERT_DISABLED,

+      TypeBinding.BOOLEAN,

+      ClassFileConstants.AccDefault | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic | ClassFileConstants.AccFinal,

+      this,

+      Constant.NotAConstant,

+      this.synthetics[SourceTypeBinding.FIELD_EMUL].size());

+    this.synthetics[SourceTypeBinding.FIELD_EMUL].put("assertionEmulation", synthField); //$NON-NLS-1$

+  }

+  // ensure there is not already such a field defined by the user

+  // ensure there is not already such a field defined by the user

+  boolean needRecheck;

+  int index = 0;

+  do {

+    needRecheck = false;

+    FieldBinding existingField;

+    if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {

+      TypeDeclaration typeDecl = this.scope.referenceContext;

+      for (int i = 0, max = typeDecl.fields.length; i < max; i++) {

+        FieldDeclaration fieldDecl = typeDecl.fields[i];

+        if (fieldDecl.binding == existingField) {

+          synthField.name = CharOperation.concat(

+            TypeConstants.SYNTHETIC_ASSERT_DISABLED,

+            ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$

+          needRecheck = true;

+          break;

+        }

+      }

+    }

+  } while (needRecheck);

+  return synthField;

+}

+/* Add a new synthetic field for recording all enum constant values

+* Answer the new field or the existing field if one already existed.

+*/

+public FieldBinding addSyntheticFieldForEnumValues() {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap();

+

+  FieldBinding synthField = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get("enumConstantValues"); //$NON-NLS-1$

+  if (synthField == null) {

+    synthField = new SyntheticFieldBinding(

+      TypeConstants.SYNTHETIC_ENUM_VALUES,

+      this.scope.createArrayType(this,1),

+      ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic | ClassFileConstants.AccFinal,

+      this,

+      Constant.NotAConstant,

+      this.synthetics[SourceTypeBinding.FIELD_EMUL].size());

+    this.synthetics[SourceTypeBinding.FIELD_EMUL].put("enumConstantValues", synthField); //$NON-NLS-1$

+  }

+  // ensure there is not already such a field defined by the user

+  // ensure there is not already such a field defined by the user

+  boolean needRecheck;

+  int index = 0;

+  do {

+    needRecheck = false;

+    FieldBinding existingField;

+    if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {

+      TypeDeclaration typeDecl = this.scope.referenceContext;

+      for (int i = 0, max = typeDecl.fields.length; i < max; i++) {

+        FieldDeclaration fieldDecl = typeDecl.fields[i];

+        if (fieldDecl.binding == existingField) {

+          synthField.name = CharOperation.concat(

+            TypeConstants.SYNTHETIC_ENUM_VALUES,

+            ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$

+          needRecheck = true;

+          break;

+        }

+      }

+    }

+  } while (needRecheck);

+  return synthField;

+}

+/* Add a new synthetic access method for read/write access to <targetField>.

+  Answer the new method or the existing method if one already existed.

+*/

+public SyntheticMethodBinding addSyntheticMethod(FieldBinding targetField, boolean isReadAccess) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap();

+

+  SyntheticMethodBinding accessMethod = null;

+  SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(targetField);

+  if (accessors == null) {

+    accessMethod = new SyntheticMethodBinding(targetField, isReadAccess, this);

+    this.synthetics[SourceTypeBinding.METHOD_EMUL].put(targetField, accessors = new SyntheticMethodBinding[2]);

+    accessors[isReadAccess ? 0 : 1] = accessMethod;   

+  } else {

+    if ((accessMethod = accessors[isReadAccess ? 0 : 1]) == null) {

+      accessMethod = new SyntheticMethodBinding(targetField, isReadAccess, this);

+      accessors[isReadAccess ? 0 : 1] = accessMethod;

+    }

+  }

+  return accessMethod;

+}

+/* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.

+ * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF

+*/

+public SyntheticMethodBinding addSyntheticEnumMethod(char[] selector) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap();

+

+  SyntheticMethodBinding accessMethod = null;

+  SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(selector);

+  if (accessors == null) {

+    accessMethod = new SyntheticMethodBinding(this, selector);

+    this.synthetics[SourceTypeBinding.METHOD_EMUL].put(selector, accessors = new SyntheticMethodBinding[2]);

+    accessors[0] = accessMethod;    

+  } else {

+    if ((accessMethod = accessors[0]) == null) {

+      accessMethod = new SyntheticMethodBinding(this, selector);

+      accessors[0] = accessMethod;

+    }

+  }

+  return accessMethod;

+}

+/*

+ * Add a synthetic field to handle the cache of the switch translation table for the corresponding enum type 

+ */

+public SyntheticFieldBinding addSyntheticFieldForSwitchEnum(char[] fieldName, String key) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.FIELD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.FIELD_EMUL] = new HashMap();

+

+  SyntheticFieldBinding synthField = (SyntheticFieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(key);

+  if (synthField == null) {

+    synthField = new SyntheticFieldBinding(

+      fieldName,

+      this.scope.createArrayType(TypeBinding.INT,1),

+      ClassFileConstants.AccPrivate | ClassFileConstants.AccStatic | ClassFileConstants.AccSynthetic,

+      this,

+      Constant.NotAConstant,

+      this.synthetics[SourceTypeBinding.FIELD_EMUL].size());

+    this.synthetics[SourceTypeBinding.FIELD_EMUL].put(key, synthField);

+  }

+  // ensure there is not already such a field defined by the user

+  boolean needRecheck;

+  int index = 0;

+  do {

+    needRecheck = false;

+    FieldBinding existingField;

+    if ((existingField = this.getField(synthField.name, true /*resolve*/)) != null) {

+      TypeDeclaration typeDecl = this.scope.referenceContext;

+      for (int i = 0, max = typeDecl.fields.length; i < max; i++) {

+        FieldDeclaration fieldDecl = typeDecl.fields[i];

+        if (fieldDecl.binding == existingField) {

+          synthField.name = CharOperation.concat(

+            fieldName,

+            ("_" + String.valueOf(index++)).toCharArray()); //$NON-NLS-1$

+          needRecheck = true;

+          break;

+        }

+      }

+    }

+  } while (needRecheck);

+  return synthField;

+}

+/* Add a new synthetic method the enum type. Selector can either be 'values' or 'valueOf'.

+ * char[] constants from TypeConstants must be used: TypeConstants.VALUES/VALUEOF

+*/

+public SyntheticMethodBinding addSyntheticMethodForSwitchEnum(TypeBinding enumBinding) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap();

+

+  SyntheticMethodBinding accessMethod = null;

+  char[] selector = CharOperation.concat(TypeConstants.SYNTHETIC_SWITCH_ENUM_TABLE, enumBinding.constantPoolName());

+  CharOperation.replace(selector, '/', '$');

+  final String key = new String(selector);

+  SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(key);

+  // first add the corresponding synthetic field

+  if (accessors == null) {

+    // then create the synthetic method

+    final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);

+    accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);

+    this.synthetics[SourceTypeBinding.METHOD_EMUL].put(key, accessors = new SyntheticMethodBinding[2]);

+    accessors[0] = accessMethod;

+  } else {

+    if ((accessMethod = accessors[0]) == null) {

+      final SyntheticFieldBinding fieldBinding = this.addSyntheticFieldForSwitchEnum(selector, key);

+      accessMethod = new SyntheticMethodBinding(fieldBinding, this, enumBinding, selector);

+      accessors[0] = accessMethod;

+    }

+  }

+  return accessMethod;

+}

+/* Add a new synthetic access method for access to <targetMethod>.

+ * Must distinguish access method used for super access from others (need to use invokespecial bytecode)

+  Answer the new method or the existing method if one already existed.

+*/

+public SyntheticMethodBinding addSyntheticMethod(MethodBinding targetMethod, boolean isSuperAccess) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null)

+    this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap();

+

+  SyntheticMethodBinding accessMethod = null;

+  SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(targetMethod);

+  if (accessors == null) {

+    accessMethod = new SyntheticMethodBinding(targetMethod, isSuperAccess, this);

+    this.synthetics[SourceTypeBinding.METHOD_EMUL].put(targetMethod, accessors = new SyntheticMethodBinding[2]);

+    accessors[isSuperAccess ? 0 : 1] = accessMethod;    

+  } else {

+    if ((accessMethod = accessors[isSuperAccess ? 0 : 1]) == null) {

+      accessMethod = new SyntheticMethodBinding(targetMethod, isSuperAccess, this);

+      accessors[isSuperAccess ? 0 : 1] = accessMethod;

+    }

+  }

+  return accessMethod;

+}

+/* 

+ * Record the fact that bridge methods need to be generated to override certain inherited methods

+ */

+public SyntheticMethodBinding addSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge, MethodBinding targetMethod) {

+  if (isInterface()) return null; // only classes & enums get bridge methods

+  // targetMethod may be inherited

+  if (inheritedMethodToBridge.returnType.erasure() == targetMethod.returnType.erasure()

+    && inheritedMethodToBridge.areParameterErasuresEqual(targetMethod)) {

+      return null; // do not need bridge method

+  }

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) {

+    this.synthetics[SourceTypeBinding.METHOD_EMUL] = new HashMap();

+  } else {

+    // check to see if there is another equivalent inheritedMethod already added

+    Iterator synthMethods = this.synthetics[SourceTypeBinding.METHOD_EMUL].keySet().iterator();

+    while (synthMethods.hasNext()) {

+      Object synthetic = synthMethods.next();

+      if (synthetic instanceof MethodBinding) {

+        MethodBinding method = (MethodBinding) synthetic;

+        if (CharOperation.equals(inheritedMethodToBridge.selector, method.selector)

+          && inheritedMethodToBridge.returnType.erasure() == method.returnType.erasure()

+          && inheritedMethodToBridge.areParameterErasuresEqual(method)) {

+            return null;

+        }

+      }

+    }

+  }

+

+  SyntheticMethodBinding accessMethod = null;

+  SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);

+  if (accessors == null) {

+    accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, targetMethod, this);

+    this.synthetics[SourceTypeBinding.METHOD_EMUL].put(inheritedMethodToBridge, accessors = new SyntheticMethodBinding[2]);

+    accessors[1] = accessMethod;    

+  } else {

+    if ((accessMethod = accessors[1]) == null) {

+      accessMethod = new SyntheticMethodBinding(inheritedMethodToBridge, targetMethod, this);

+      accessors[1] = accessMethod;

+    }

+  }

+  return accessMethod;

+}

+boolean areFieldsInitialized() {

+  return this.fields != Binding.UNINITIALIZED_FIELDS;

+}

+boolean areMethodsInitialized() {

+  return this.methods != Binding.UNINITIALIZED_METHODS;

+}

+public int kind() {

+  if (this.typeVariables != Binding.NO_TYPE_VARIABLES) return Binding.GENERIC_TYPE;

+  return Binding.TYPE;

+}

+

+public char[] computeUniqueKey(boolean isLeaf) {

+  char[] uniqueKey = super.computeUniqueKey(isLeaf);

+  if (uniqueKey.length == 2) return uniqueKey; // problem type's unique key is "L;"

+  if (Util.isClassFileName(this.fileName)) return uniqueKey; // no need to insert compilation unit name for a .class file

+  

+  // insert compilation unit name if the type name is not the main type name

+  int end = CharOperation.lastIndexOf('.', this.fileName);

+  if (end != -1) {

+    int start = CharOperation.lastIndexOf('/', this.fileName) + 1;

+    char[] mainTypeName = CharOperation.subarray(this.fileName, start, end);

+    start = CharOperation.lastIndexOf('/', uniqueKey) + 1;

+    if (start == 0)

+      start = 1; // start after L

+    end = CharOperation.indexOf('$', uniqueKey, start);

+    if (end == -1)

+      end = CharOperation.indexOf('<', uniqueKey, start);

+    if (end == -1)

+      end = CharOperation.indexOf(';', uniqueKey, start);

+    char[] topLevelType = CharOperation.subarray(uniqueKey, start, end);

+    if (!CharOperation.equals(topLevelType, mainTypeName)) {

+      StringBuffer buffer = new StringBuffer();

+      buffer.append(uniqueKey, 0, start);

+      buffer.append(mainTypeName);

+      buffer.append('~');

+      buffer.append(topLevelType);

+      buffer.append(uniqueKey, end, uniqueKey.length - end);

+      int length = buffer.length();

+      uniqueKey = new char[length];

+      buffer.getChars(0, length, uniqueKey, 0);

+      return uniqueKey;

+    }

+  }

+  return uniqueKey;

+}

+

+void faultInTypesForFieldsAndMethods() {

+  // check @Deprecated annotation

+  getAnnotationTagBits(); // marks as deprecated by side effect

+  ReferenceBinding enclosingType = this.enclosingType();

+  if (enclosingType != null && enclosingType.isViewedAsDeprecated() && !this.isDeprecated())

+    this.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;

+  fields();

+  methods();

+

+  for (int i = 0, length = this.memberTypes.length; i < length; i++)

+    ((SourceTypeBinding) this.memberTypes[i]).faultInTypesForFieldsAndMethods();

+}

+// NOTE: the type of each field of a source type is resolved when needed

+public FieldBinding[] fields() {

+  if ((this.tagBits & TagBits.AreFieldsComplete) != 0)

+    return this.fields; 

+

+  int failed = 0;

+  FieldBinding[] resolvedFields = this.fields;

+  try {

+    // lazily sort fields

+    if ((this.tagBits & TagBits.AreFieldsSorted) == 0) {

+      int length = this.fields.length;

+      if (length > 1)

+        ReferenceBinding.sortFields(this.fields, 0, length);

+      this.tagBits |= TagBits.AreFieldsSorted;

+    }

+    for (int i = 0, length = this.fields.length; i < length; i++) {

+      if (resolveTypeFor(this.fields[i]) == null) {

+        // do not alter original field array until resolution is over, due to reentrance (143259)

+        if (resolvedFields == this.fields) {

+          System.arraycopy(this.fields, 0, resolvedFields = new FieldBinding[length], 0, length);

+        }

+        resolvedFields[i] = null;

+        failed++;

+      }

+    }

+  } finally {

+    if (failed > 0) {

+      // ensure fields are consistent reqardless of the error

+      int newSize = resolvedFields.length - failed;

+      if (newSize == 0)

+        return this.fields = Binding.NO_FIELDS;

+

+      FieldBinding[] newFields = new FieldBinding[newSize];

+      for (int i = 0, j = 0, length = resolvedFields.length; i < length; i++) {

+        if (resolvedFields[i] != null)

+          newFields[j++] = resolvedFields[i];

+      }

+      this.fields = newFields;

+    }

+  }

+  this.tagBits |= TagBits.AreFieldsComplete;

+  return this.fields;

+}

+/**

+ * @see org.eclipse.jdt.internal.compiler.lookup.TypeBinding#genericTypeSignature()

+ */

+public char[] genericTypeSignature() {

+    if (this.genericReferenceTypeSignature == null)

+      this.genericReferenceTypeSignature = computeGenericTypeSignature(this.typeVariables);

+    return this.genericReferenceTypeSignature;

+}

+/**

+ * <param1 ... paramN>superclass superinterface1 ... superinterfaceN

+ * <T:LY<TT;>;U:Ljava/lang/Object;V::Ljava/lang/Runnable;:Ljava/lang/Cloneable;:Ljava/util/Map;>Ljava/lang/Exception;Ljava/lang/Runnable;

+ */

+public char[] genericSignature() {

+    StringBuffer sig = null;

+  if (this.typeVariables != Binding.NO_TYPE_VARIABLES) {

+      sig = new StringBuffer(10);

+      sig.append('<');

+      for (int i = 0, length = this.typeVariables.length; i < length; i++)

+          sig.append(this.typeVariables[i].genericSignature());

+      sig.append('>');

+  } else {

+      // could still need a signature if any of supertypes is parameterized

+      noSignature: if (this.superclass == null || !this.superclass.isParameterizedType()) {

+        for (int i = 0, length = this.superInterfaces.length; i < length; i++)

+            if (this.superInterfaces[i].isParameterizedType())

+          break noSignature;

+          return null;

+      }

+      sig = new StringBuffer(10);

+  }

+  if (this.superclass != null)

+    sig.append(this.superclass.genericTypeSignature());

+  else // interface scenario only (as Object cannot be generic) - 65953

+    sig.append(this.scope.getJavaLangObject().genericTypeSignature());

+    for (int i = 0, length = this.superInterfaces.length; i < length; i++)

+        sig.append(this.superInterfaces[i].genericTypeSignature());

+  return sig.toString().toCharArray();

+}

+

+/**

+ * Compute the tagbits for standard annotations. For source types, these could require

+ * lazily resolving corresponding annotation nodes, in case of forward references.

+ * @see org.eclipse.jdt.internal.compiler.lookup.Binding#getAnnotationTagBits()

+ */

+public long getAnnotationTagBits() {

+  if ((this.tagBits & TagBits.AnnotationResolved) == 0 && this.scope != null) {

+    TypeDeclaration typeDecl = this.scope.referenceContext;

+    boolean old = typeDecl.staticInitializerScope.insideTypeAnnotation;

+    try {

+      typeDecl.staticInitializerScope.insideTypeAnnotation = true;

+      ASTNode.resolveAnnotations(typeDecl.staticInitializerScope, typeDecl.annotations, this);

+    } finally {

+      typeDecl.staticInitializerScope.insideTypeAnnotation = old;

+    }

+    if ((this.tagBits & TagBits.AnnotationDeprecated) != 0)

+      this.modifiers |= ClassFileConstants.AccDeprecated;

+  }

+  return this.tagBits;

+}

+public MethodBinding[] getDefaultAbstractMethods() {

+  int count = 0;

+  for (int i = this.methods.length; --i >= 0;)

+    if (this.methods[i].isDefaultAbstract())

+      count++;

+  if (count == 0) return Binding.NO_METHODS;

+

+  MethodBinding[] result = new MethodBinding[count];

+  count = 0;

+  for (int i = this.methods.length; --i >= 0;)

+    if (this.methods[i].isDefaultAbstract())

+      result[count++] = this.methods[i];

+  return result;

+}

+// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed

+public MethodBinding getExactConstructor(TypeBinding[] argumentTypes) {

+  int argCount = argumentTypes.length;

+  if ((this.tagBits & TagBits.AreMethodsComplete) != 0) { // have resolved all arg types & return type of the methods

+    long range;

+    if ((range = ReferenceBinding.binarySearch(TypeConstants.INIT, this.methods)) >= 0) {

+      nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {

+        MethodBinding method = this.methods[imethod];

+        if (method.parameters.length == argCount) {

+          TypeBinding[] toMatch = method.parameters;

+          for (int iarg = 0; iarg < argCount; iarg++)

+            if (toMatch[iarg] != argumentTypes[iarg])

+              continue nextMethod;

+          return method;

+        }

+      }

+    }

+  } else {

+    // lazily sort methods

+    if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {

+      int length = this.methods.length;

+      if (length > 1)

+        ReferenceBinding.sortMethods(this.methods, 0, length);

+      this.tagBits |= TagBits.AreMethodsSorted;

+    }   

+    long range;

+    if ((range = ReferenceBinding.binarySearch(TypeConstants.INIT, this.methods)) >= 0) {

+      nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {

+        MethodBinding method = this.methods[imethod];

+        if (resolveTypesFor(method) == null || method.returnType == null) {

+          methods();

+          return getExactConstructor(argumentTypes);  // try again since the problem methods have been removed

+        }

+        if (method.parameters.length == argCount) {

+          TypeBinding[] toMatch = method.parameters;

+          for (int iarg = 0; iarg < argCount; iarg++)

+            if (toMatch[iarg] != argumentTypes[iarg])

+              continue nextMethod;

+          return method;

+        }

+      }

+    }

+  } 

+  return null;

+}

+

+//NOTE: the return type, arg & exception types of each method of a source type are resolved when needed

+//searches up the hierarchy as long as no potential (but not exact) match was found.

+public MethodBinding getExactMethod(char[] selector, TypeBinding[] argumentTypes, CompilationUnitScope refScope) {

+  // sender from refScope calls recordTypeReference(this)

+  int argCount = argumentTypes.length;

+  boolean foundNothing = true;

+

+  if ((this.tagBits & TagBits.AreMethodsComplete) != 0) { // have resolved all arg types & return type of the methods

+    long range;

+    if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {

+      nextMethod: for (int imethod = (int)range, end = (int)(range >> 32); imethod <= end; imethod++) {

+        MethodBinding method = this.methods[imethod];

+        foundNothing = false; // inner type lookups must know that a method with this name exists

+        if (method.parameters.length == argCount) {

+          TypeBinding[] toMatch = method.parameters;

+          for (int iarg = 0; iarg < argCount; iarg++)

+            if (toMatch[iarg] != argumentTypes[iarg])

+              continue nextMethod;

+          return method;

+        }

+      }

+    }

+  } else {

+    // lazily sort methods

+    if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {

+      int length = this.methods.length;

+      if (length > 1)

+        ReferenceBinding.sortMethods(this.methods, 0, length);

+      this.tagBits |= TagBits.AreMethodsSorted;

+    }

+    

+    long range;

+    if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {

+      // check unresolved method

+      int start = (int) range, end = (int) (range >> 32);

+      for (int imethod = start; imethod <= end; imethod++) {

+        MethodBinding method = this.methods[imethod];     

+        if (resolveTypesFor(method) == null || method.returnType == null) {

+          methods();

+          return getExactMethod(selector, argumentTypes, refScope); // try again since the problem methods have been removed

+        }

+      }

+      // check dup collisions

+      boolean isSource15 = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;

+      for (int i = start; i <= end; i++) {

+        MethodBinding method1 = this.methods[i];

+        for (int j = end; j > i; j--) {

+          MethodBinding method2 = this.methods[j];

+          boolean paramsMatch = isSource15

+            ? method1.areParameterErasuresEqual(method2)

+            : method1.areParametersEqual(method2);

+          if (paramsMatch) {

+            methods();

+            return getExactMethod(selector, argumentTypes, refScope); // try again since the problem methods have been removed

+          }

+        }

+      }

+      nextMethod: for (int imethod = start; imethod <= end; imethod++) {

+        MethodBinding method = this.methods[imethod];           

+        TypeBinding[] toMatch = method.parameters;

+        if (toMatch.length == argCount) {

+          for (int iarg = 0; iarg < argCount; iarg++)

+            if (toMatch[iarg] != argumentTypes[iarg])

+              continue nextMethod;

+          return method;

+        }

+      }       

+    }

+  }

+

+  if (foundNothing) {

+    if (isInterface()) {

+       if (this.superInterfaces.length == 1) {

+        if (refScope != null)

+          refScope.recordTypeReference(this.superInterfaces[0]);

+        return this.superInterfaces[0].getExactMethod(selector, argumentTypes, refScope);

+       }

+    } else if (this.superclass != null) {

+      if (refScope != null)

+        refScope.recordTypeReference(this.superclass);

+      return this.superclass.getExactMethod(selector, argumentTypes, refScope);

+    }

+  }

+  return null;

+}

+

+//NOTE: the type of a field of a source type is resolved when needed

+public FieldBinding getField(char[] fieldName, boolean needResolve) {

+  

+  if ((this.tagBits & TagBits.AreFieldsComplete) != 0)

+    return ReferenceBinding.binarySearch(fieldName, this.fields);

+

+  // lazily sort fields

+  if ((this.tagBits & TagBits.AreFieldsSorted) == 0) {

+    int length = this.fields.length;

+    if (length > 1)

+      ReferenceBinding.sortFields(this.fields, 0, length);

+    this.tagBits |= TagBits.AreFieldsSorted;

+  }   

+  // always resolve anyway on source types

+  FieldBinding field = ReferenceBinding.binarySearch(fieldName, this.fields);

+  if (field != null) {

+    FieldBinding result = null;

+    try {

+      result = resolveTypeFor(field);

+      return result;

+    } finally {

+      if (result == null) {

+        // ensure fields are consistent reqardless of the error

+        int newSize = this.fields.length - 1;

+        if (newSize == 0) {

+          this.fields = Binding.NO_FIELDS;

+        } else {

+          FieldBinding[] newFields = new FieldBinding[newSize];

+          int index = 0;

+          for (int i = 0, length = this.fields.length; i < length; i++) {

+            FieldBinding f = this.fields[i];

+            if (f == field) continue;

+            newFields[index++] = f;

+          }

+          this.fields = newFields;

+        }

+      }

+    }

+  }

+  return null;

+}

+

+// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed

+public MethodBinding[] getMethods(char[] selector) {

+  if ((this.tagBits & TagBits.AreMethodsComplete) != 0) {

+    long range;

+    if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {

+      int start = (int) range, end = (int) (range >> 32);

+      int length = end - start + 1;

+      MethodBinding[] result;

+      System.arraycopy(this.methods, start, result = new MethodBinding[length], 0, length);

+      return result;

+    } else {

+      return Binding.NO_METHODS;      

+    }

+  }

+  // lazily sort methods

+  if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {

+    int length = this.methods.length;

+    if (length > 1)

+      ReferenceBinding.sortMethods(this.methods, 0, length);

+    this.tagBits |= TagBits.AreMethodsSorted;

+  }

+  MethodBinding[] result; 

+  long range;

+  if ((range = ReferenceBinding.binarySearch(selector, this.methods)) >= 0) {

+    int start = (int) range, end = (int) (range >> 32);

+    for (int i = start; i <= end; i++) {

+      MethodBinding method = this.methods[i];

+      if (resolveTypesFor(method) == null || method.returnType == null) {

+        methods();

+        return getMethods(selector); // try again since the problem methods have been removed

+      }

+    }

+    int length = end - start + 1;

+    System.arraycopy(this.methods, start, result = new MethodBinding[length], 0, length);

+  } else {

+    return Binding.NO_METHODS;

+  }

+  boolean isSource15 = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;

+  for (int i = 0, length = result.length - 1; i < length; i++) {

+    MethodBinding method = result[i];

+    for (int j = length; j > i; j--) {

+      boolean paramsMatch = isSource15

+        ? method.areParameterErasuresEqual(result[j])

+        : method.areParametersEqual(result[j]);

+      if (paramsMatch) {

+        methods();

+        return getMethods(selector); // try again since the duplicate methods have been removed

+      }

+    }

+  }

+  return result;

+}

+/* Answer the synthetic field for <actualOuterLocalVariable>

+* or null if one does not exist.

+*/

+public FieldBinding getSyntheticField(LocalVariableBinding actualOuterLocalVariable) {

+  if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null;

+  return (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(actualOuterLocalVariable);

+}

+/* Answer the synthetic field for <targetEnclosingType>

+* or null if one does not exist.

+*/

+public FieldBinding getSyntheticField(ReferenceBinding targetEnclosingType, boolean onlyExactMatch) {

+

+  if (this.synthetics == null || this.synthetics[SourceTypeBinding.FIELD_EMUL] == null) return null;

+  FieldBinding field = (FieldBinding) this.synthetics[SourceTypeBinding.FIELD_EMUL].get(targetEnclosingType);

+  if (field != null) return field;

+

+  // type compatibility : to handle cases such as

+  // class T { class M{}}

+  // class S extends T { class N extends M {}} --> need to use S as a default enclosing instance for the super constructor call in N().

+  if (!onlyExactMatch){

+    Iterator accessFields = this.synthetics[SourceTypeBinding.FIELD_EMUL].values().iterator();

+    while (accessFields.hasNext()) {

+      field = (FieldBinding) accessFields.next();

+      if (CharOperation.prefixEquals(TypeConstants.SYNTHETIC_ENCLOSING_INSTANCE_PREFIX, field.name)

+        && field.type.findSuperTypeOriginatingFrom(targetEnclosingType) != null)

+          return field;

+    }

+  }

+  return null;

+}

+/* 

+ * Answer the bridge method associated for an  inherited methods or null if one does not exist

+ */

+public SyntheticMethodBinding getSyntheticBridgeMethod(MethodBinding inheritedMethodToBridge) {

+  if (this.synthetics == null) return null;

+  if (this.synthetics[SourceTypeBinding.METHOD_EMUL] == null) return null;

+  SyntheticMethodBinding[] accessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(inheritedMethodToBridge);

+  if (accessors == null) return null;

+  return accessors[1];

+}

+

+/**

+ * @see org.eclipse.jdt.internal.compiler.lookup.Binding#initializeDeprecatedAnnotationTagBits()

+ */

+public void initializeDeprecatedAnnotationTagBits() {

+  if ((this.tagBits & TagBits.DeprecatedAnnotationResolved) == 0) {

+    TypeDeclaration typeDecl = this.scope.referenceContext;

+    boolean old = typeDecl.staticInitializerScope.insideTypeAnnotation;

+    try {

+      typeDecl.staticInitializerScope.insideTypeAnnotation = true;

+      ASTNode.resolveDeprecatedAnnotations(typeDecl.staticInitializerScope, typeDecl.annotations, this);

+      this.tagBits |= TagBits.DeprecatedAnnotationResolved;

+    } finally {

+      typeDecl.staticInitializerScope.insideTypeAnnotation = old;

+    }

+    if ((this.tagBits & TagBits.AnnotationDeprecated) != 0) {

+      this.modifiers |= ClassFileConstants.AccDeprecated;

+    }

+  }

+}

+

+// ensure the receiver knows its hierarchy & fields/methods so static imports can be resolved correctly

+// see bug 230026

+void initializeForStaticImports() {

+  if (this.scope == null) return; // already initialized

+

+  if (this.superInterfaces == null)

+    this.scope.connectTypeHierarchy();

+  this.scope.buildFields();

+  this.scope.buildMethods();

+}

+

+/**

+ * Returns true if a type is identical to another one,

+ * or for generic types, true if compared to its raw type.

+ */

+public boolean isEquivalentTo(TypeBinding otherType) {

+

+  if (this == otherType) return true;

+  if (otherType == null) return false;

+  switch(otherType.kind()) {

+

+    case Binding.WILDCARD_TYPE :

+    case Binding.INTERSECTION_TYPE:

+      return ((WildcardBinding) otherType).boundCheck(this);

+

+    case Binding.PARAMETERIZED_TYPE :

+      if ((otherType.tagBits & TagBits.HasDirectWildcard) == 0 && (!this.isMemberType() || !otherType.isMemberType())) 

+        return false; // should have been identical

+      ParameterizedTypeBinding otherParamType = (ParameterizedTypeBinding) otherType;

+      if (this != otherParamType.genericType()) 

+        return false;

+      if (!isStatic()) { // static member types do not compare their enclosing

+              ReferenceBinding enclosing = enclosingType();

+              if (enclosing != null) {

+                ReferenceBinding otherEnclosing = otherParamType.enclosingType();

+                if (otherEnclosing == null) return false;

+                if ((otherEnclosing.tagBits & TagBits.HasDirectWildcard) == 0) {

+            if (enclosing != otherEnclosing) return false;

+                } else {

+                  if (!enclosing.isEquivalentTo(otherParamType.enclosingType())) return false;

+                }

+              }       

+      }

+      int length = this.typeVariables == null ? 0 : this.typeVariables.length;

+      TypeBinding[] otherArguments = otherParamType.arguments;

+      int otherLength = otherArguments == null ? 0 : otherArguments.length;

+      if (otherLength != length) 

+        return false;

+      for (int i = 0; i < length; i++)

+        if (!this.typeVariables[i].isTypeArgumentContainedBy(otherArguments[i]))

+          return false;

+      return true;

+

+    case Binding.RAW_TYPE :

+          return otherType.erasure() == this;

+  }

+  return false;

+}

+public boolean isGenericType() {

+    return this.typeVariables != Binding.NO_TYPE_VARIABLES;

+}

+public ReferenceBinding[] memberTypes() {

+  return this.memberTypes;

+}

+public FieldBinding getUpdatedFieldBinding(FieldBinding targetField, ReferenceBinding newDeclaringClass) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] == null)

+    this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] = new HashMap();

+

+  Hashtable fieldMap = (Hashtable) this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].get(targetField);

+  if (fieldMap == null) {

+    fieldMap = new Hashtable(5);

+    this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].put(targetField, fieldMap);

+  }

+  FieldBinding updatedField = (FieldBinding) fieldMap.get(newDeclaringClass);

+  if (updatedField == null){

+    updatedField = new FieldBinding(targetField, newDeclaringClass);

+    fieldMap.put(newDeclaringClass, updatedField);

+  }

+  return updatedField;

+}

+public MethodBinding getUpdatedMethodBinding(MethodBinding targetMethod, ReferenceBinding newDeclaringClass) {

+  if (this.synthetics == null)

+    this.synthetics = new HashMap[MAX_SYNTHETICS];

+  if (this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] == null)

+    this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL] = new HashMap();

+

+  Hashtable methodMap = (Hashtable) this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].get(targetMethod);

+  if (methodMap == null) {

+    methodMap = new Hashtable(5);

+    this.synthetics[SourceTypeBinding.RECEIVER_TYPE_EMUL].put(targetMethod, methodMap);

+  }

+  MethodBinding updatedMethod = (MethodBinding) methodMap.get(newDeclaringClass);

+  if (updatedMethod == null){

+    updatedMethod = new MethodBinding(targetMethod, newDeclaringClass);

+    methodMap.put(newDeclaringClass, updatedMethod);

+  }

+  return updatedMethod;

+}

+public boolean hasMemberTypes() {

+    return this.memberTypes.length > 0;

+}

+// NOTE: the return type, arg & exception types of each method of a source type are resolved when needed

+public MethodBinding[] methods() {

+  if ((this.tagBits & TagBits.AreMethodsComplete) != 0)

+    return this.methods;

+  

+  // lazily sort methods

+  if ((this.tagBits & TagBits.AreMethodsSorted) == 0) {

+    int length = this.methods.length;

+    if (length > 1)

+      ReferenceBinding.sortMethods(this.methods, 0, length);

+    this.tagBits |= TagBits.AreMethodsSorted;

+  }

+

+  int failed = 0;

+  MethodBinding[] resolvedMethods = this.methods;

+  try {

+    for (int i = 0, length = this.methods.length; i < length; i++) {

+      if (resolveTypesFor(this.methods[i]) == null) {

+        // do not alter original method array until resolution is over, due to reentrance (143259)

+        if (resolvedMethods == this.methods) {

+          System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);

+        }       

+        resolvedMethods[i] = null; // unable to resolve parameters

+        failed++;

+      }

+    }

+

+    // find & report collision cases

+    boolean complyTo15 = this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;

+    for (int i = 0, length = this.methods.length; i < length; i++) {

+      MethodBinding method = resolvedMethods[i];

+      if (method == null) 

+        continue;

+      char[] selector = method.selector;

+      AbstractMethodDeclaration methodDecl = null;

+      nextSibling: for (int j = i + 1; j < length; j++) {

+        MethodBinding method2 = resolvedMethods[j];

+        if (method2 == null)

+          continue nextSibling;

+        if (!CharOperation.equals(selector, method2.selector)) 

+          break nextSibling; // methods with same selector are contiguous

+

+        if (complyTo15 && method.returnType != null && method2.returnType != null) {

+          // 8.4.2, for collision to be detected between m1 and m2:

+          // signature(m1) == signature(m2) i.e. same arity, same type parameter count, can be substituted

+          // signature(m1) == erasure(signature(m2)) or erasure(signature(m1)) == signature(m2)

+          TypeBinding[] params1 = method.parameters;

+          TypeBinding[] params2 = method2.parameters;

+          int pLength = params1.length;

+          if (pLength != params2.length)

+            continue nextSibling;

+

+          TypeVariableBinding[] vars = method.typeVariables;

+          TypeVariableBinding[] vars2 = method2.typeVariables;

+          boolean equalTypeVars = vars == vars2;

+          MethodBinding subMethod = method2;

+          if (!equalTypeVars) {

+            MethodBinding temp = method.computeSubstitutedMethod(method2, this.scope.environment());

+            if (temp != null) {

+              equalTypeVars = true;

+              subMethod = temp;

+            }

+          }

+          boolean equalParams = method.areParametersEqual(subMethod);

+          if (equalParams && equalTypeVars) {

+            // duplicates regardless of return types

+          } else if (method.returnType.erasure() == subMethod.returnType.erasure() && (equalParams || method.areParameterErasuresEqual(method2))) {

+            // name clash for sure if not duplicates, report as duplicates

+          } else if (!equalTypeVars && vars != Binding.NO_TYPE_VARIABLES && vars2 != Binding.NO_TYPE_VARIABLES) {

+            // type variables are different so we can distinguish between methods

+            continue nextSibling;

+          } else if (pLength > 0) {

+            // check to see if the erasure of either method is equal to the other

+            int index = pLength;

+            for (; --index >= 0;) {

+              if (params1[index] != params2[index].erasure())

+                break;

+              if (params1[index] == params2[index]) {

+                TypeBinding type = params1[index].leafComponentType();

+                if (type instanceof SourceTypeBinding && type.typeVariables() != Binding.NO_TYPE_VARIABLES) {

+                  index = pLength; // handle comparing identical source types like X<T>... its erasure is itself BUT we need to answer false

+                  break;

+                }

+              }

+            }

+            if (index >= 0 && index < pLength) {

+              for (index = pLength; --index >= 0;)

+                if (params1[index].erasure() != params2[index])

+                  break;

+            }

+            if (index >= 0)

+              continue nextSibling;

+          }

+        } else if (!method.areParametersEqual(method2)) { // prior to 1.5, parameter identity meant a collision case

+          continue nextSibling;

+        }

+        boolean isEnumSpecialMethod = isEnum() && (CharOperation.equals(selector,TypeConstants.VALUEOF) || CharOperation.equals(selector,TypeConstants.VALUES));

+        // report duplicate

+        if (methodDecl == null) {

+          methodDecl = method.sourceMethod(); // cannot be retrieved after binding is lost & may still be null if method is special

+          if (methodDecl != null && methodDecl.binding != null) { // ensure its a valid user defined method

+            if (isEnumSpecialMethod) {

+              this.scope.problemReporter().duplicateEnumSpecialMethod(this, methodDecl);

+            } else {

+              this.scope.problemReporter().duplicateMethodInType(this, methodDecl, method.areParametersEqual(method2));

+            }

+            methodDecl.binding = null;

+            // do not alter original method array until resolution is over, due to reentrance (143259)

+            if (resolvedMethods == this.methods) {

+              System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);

+            }               

+            resolvedMethods[i] = null;

+            failed++;

+          }

+        }

+        AbstractMethodDeclaration method2Decl = method2.sourceMethod();

+        if (method2Decl != null && method2Decl.binding != null) { // ensure its a valid user defined method

+          if (isEnumSpecialMethod) {

+            this.scope.problemReporter().duplicateEnumSpecialMethod(this, method2Decl);

+          } else {

+            this.scope.problemReporter().duplicateMethodInType(this, method2Decl, method.areParametersEqual(method2));

+          }

+          method2Decl.binding = null;

+          // do not alter original method array until resolution is over, due to reentrance (143259)

+          if (resolvedMethods == this.methods) {

+            System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);

+          }             

+          resolvedMethods[j] = null;

+          failed++;

+        }

+      }

+      if (method.returnType == null && methodDecl == null) { // forget method with invalid return type... was kept to detect possible collisions

+        methodDecl = method.sourceMethod();

+        if (methodDecl != null) {

+          methodDecl.binding = null;

+        }

+        // do not alter original method array until resolution is over, due to reentrance (143259)

+        if (resolvedMethods == this.methods) {

+          System.arraycopy(this.methods, 0, resolvedMethods = new MethodBinding[length], 0, length);

+        }           

+        resolvedMethods[i] = null;

+        failed++;

+      }

+    }

+  } finally {

+    if (failed > 0) {

+      int newSize = resolvedMethods.length - failed;

+      if (newSize == 0) {

+        this.methods = Binding.NO_METHODS;

+      } else {

+        MethodBinding[] newMethods = new MethodBinding[newSize];

+        for (int i = 0, j = 0, length = resolvedMethods.length; i < length; i++)

+          if (resolvedMethods[i] != null)

+            newMethods[j++] = resolvedMethods[i];

+        this.methods = newMethods;

+      }

+    }

+

+    // handle forward references to potential default abstract methods

+    addDefaultAbstractMethods();

+    this.tagBits |= TagBits.AreMethodsComplete;

+  }   

+  return this.methods;

+}

+private FieldBinding resolveTypeFor(FieldBinding field) {

+  if ((field.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)

+    return field;

+

+  if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {

+    if ((field.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0)

+      field.modifiers |= ClassFileConstants.AccDeprecated;

+  }

+  if (isViewedAsDeprecated() && !field.isDeprecated())

+    field.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;  

+  if (hasRestrictedAccess())

+    field.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;

+  FieldDeclaration[] fieldDecls = this.scope.referenceContext.fields;

+  for (int f = 0, length = fieldDecls.length; f < length; f++) {

+    if (fieldDecls[f].binding != field)

+      continue;

+

+      MethodScope initializationScope = field.isStatic() 

+        ? this.scope.referenceContext.staticInitializerScope 

+        : this.scope.referenceContext.initializerScope;

+      FieldBinding previousField = initializationScope.initializedField;

+      try {

+        initializationScope.initializedField = field;

+        FieldDeclaration fieldDecl = fieldDecls[f];

+        TypeBinding fieldType = 

+          fieldDecl.getKind() == AbstractVariableDeclaration.ENUM_CONSTANT

+            ? initializationScope.environment().convertToRawType(this, false /*do not force conversion of enclosing types*/) // enum constant is implicitly of declaring enum type

+            : fieldDecl.type.resolveType(initializationScope, true /* check bounds*/);

+        field.type = fieldType;

+        field.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;

+        if (fieldType == null) {

+          fieldDecl.binding = null;

+          return null;

+        }

+        if (fieldType == TypeBinding.VOID) {

+          this.scope.problemReporter().variableTypeCannotBeVoid(fieldDecl);

+          fieldDecl.binding = null;

+          return null;

+        }

+        if (fieldType.isArrayType() && ((ArrayBinding) fieldType).leafComponentType == TypeBinding.VOID) {

+          this.scope.problemReporter().variableTypeCannotBeVoidArray(fieldDecl);

+          fieldDecl.binding = null;

+          return null;

+        }

+        if ((fieldType.tagBits & TagBits.HasMissingType) != 0) {

+          field.tagBits |= TagBits.HasMissingType;

+        }           

+        TypeBinding leafType = fieldType.leafComponentType();

+        if (leafType instanceof ReferenceBinding && (((ReferenceBinding)leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0) {

+          field.modifiers |= ExtraCompilerModifiers.AccGenericSignature;

+        }       

+      } finally {

+          initializationScope.initializedField = previousField;

+      }

+    return field;

+  }

+  return null; // should never reach this point

+}

+public MethodBinding resolveTypesFor(MethodBinding method) {

+  if ((method.modifiers & ExtraCompilerModifiers.AccUnresolved) == 0)

+    return method;

+

+  if (this.scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5) {

+    if ((method.getAnnotationTagBits() & TagBits.AnnotationDeprecated) != 0)

+      method.modifiers |= ClassFileConstants.AccDeprecated;

+  }

+  if (isViewedAsDeprecated() && !method.isDeprecated())

+    method.modifiers |= ExtraCompilerModifiers.AccDeprecatedImplicitly;

+  if (hasRestrictedAccess())

+    method.modifiers |= ExtraCompilerModifiers.AccRestrictedAccess;

+

+  AbstractMethodDeclaration methodDecl = method.sourceMethod();

+  if (methodDecl == null) return null; // method could not be resolved in previous iteration

+

+  TypeParameter[] typeParameters = methodDecl.typeParameters();

+  if (typeParameters != null) {

+    methodDecl.scope.connectTypeVariables(typeParameters, true);

+    // Perform deferred bound checks for type variables (only done after type variable hierarchy is connected)

+    for (int i = 0, paramLength = typeParameters.length; i < paramLength; i++)

+      typeParameters[i].checkBounds(methodDecl.scope);

+  }

+  TypeReference[] exceptionTypes = methodDecl.thrownExceptions;

+  if (exceptionTypes != null) {

+    int size = exceptionTypes.length;

+    method.thrownExceptions = new ReferenceBinding[size];

+    int count = 0;

+    ReferenceBinding resolvedExceptionType;

+    for (int i = 0; i < size; i++) {

+      resolvedExceptionType = (ReferenceBinding) exceptionTypes[i].resolveType(methodDecl.scope, true /* check bounds*/);

+      if (resolvedExceptionType == null)

+        continue;

+      if (resolvedExceptionType.isBoundParameterizedType()) {

+        methodDecl.scope.problemReporter().invalidParameterizedExceptionType(resolvedExceptionType, exceptionTypes[i]);

+        continue;

+      }

+      if (resolvedExceptionType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null) {

+        if (resolvedExceptionType.isValidBinding()) {

+          methodDecl.scope.problemReporter().cannotThrowType(exceptionTypes[i], resolvedExceptionType);

+          continue;

+        }

+      }

+      if ((resolvedExceptionType.tagBits & TagBits.HasMissingType) != 0) {

+        method.tagBits |= TagBits.HasMissingType;

+      }           

+      method.modifiers |= (resolvedExceptionType.modifiers & ExtraCompilerModifiers.AccGenericSignature);

+      method.thrownExceptions[count++] = resolvedExceptionType;

+    }

+    if (count < size)

+      System.arraycopy(method.thrownExceptions, 0, method.thrownExceptions = new ReferenceBinding[count], 0, count);

+  }

+

+  boolean foundArgProblem = false;

+  Argument[] arguments = methodDecl.arguments;

+  if (arguments != null) {

+    int size = arguments.length;

+    method.parameters = Binding.NO_PARAMETERS;

+    TypeBinding[] newParameters = new TypeBinding[size];

+    for (int i = 0; i < size; i++) {

+      Argument arg = arguments[i];

+      if (arg.annotations != null) {

+        method.tagBits |= TagBits.HasParameterAnnotations;

+      }

+      TypeBinding parameterType = arg.type.resolveType(methodDecl.scope, true /* check bounds*/);

+      if (parameterType == null) {

+        foundArgProblem = true;

+      } else if (parameterType == TypeBinding.VOID) {

+        methodDecl.scope.problemReporter().argumentTypeCannotBeVoid(this, methodDecl, arg);

+        foundArgProblem = true;

+      } else {

+        if ((parameterType.tagBits & TagBits.HasMissingType) != 0) {

+          method.tagBits |= TagBits.HasMissingType;

+        }           

+        TypeBinding leafType = parameterType.leafComponentType();

+        if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)

+          method.modifiers |= ExtraCompilerModifiers.AccGenericSignature;

+        newParameters[i] = parameterType;

+        arg.binding = new LocalVariableBinding(arg, parameterType, arg.modifiers, true);

+      }

+    }

+    // only assign parameters if no problems are found

+    if (!foundArgProblem) {

+      method.parameters = newParameters;

+    }

+  }

+

+  boolean foundReturnTypeProblem = false;

+  if (!method.isConstructor()) {

+    TypeReference returnType = methodDecl instanceof MethodDeclaration

+      ? ((MethodDeclaration) methodDecl).returnType

+      : null;

+    if (returnType == null) {

+      methodDecl.scope.problemReporter().missingReturnType(methodDecl);

+      method.returnType = null;

+      foundReturnTypeProblem = true;

+    } else {

+      TypeBinding methodType = returnType.resolveType(methodDecl.scope, true /* check bounds*/);

+      if (methodType == null) {

+        foundReturnTypeProblem = true;

+      } else if (methodType.isArrayType() && ((ArrayBinding) methodType).leafComponentType == TypeBinding.VOID) {

+        methodDecl.scope.problemReporter().returnTypeCannotBeVoidArray((MethodDeclaration) methodDecl);

+        foundReturnTypeProblem = true;

+      } else {

+        if ((methodType.tagBits & TagBits.HasMissingType) != 0) {

+          method.tagBits |= TagBits.HasMissingType;

+        }         

+        method.returnType = methodType;

+        TypeBinding leafType = methodType.leafComponentType();

+        if (leafType instanceof ReferenceBinding && (((ReferenceBinding) leafType).modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)

+          method.modifiers |= ExtraCompilerModifiers.AccGenericSignature;

+      }

+    }

+  }

+  if (foundArgProblem) {

+    methodDecl.binding = null;

+    method.parameters = Binding.NO_PARAMETERS; // see 107004

+    // nullify type parameter bindings as well as they have a backpointer to the method binding

+    // (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=81134)

+    if (typeParameters != null)

+      for (int i = 0, length = typeParameters.length; i < length; i++)

+        typeParameters[i].binding = null;

+    return null;

+  }

+  if (foundReturnTypeProblem)

+    return method; // but its still unresolved with a null return type & is still connected to its method declaration

+

+  method.modifiers &= ~ExtraCompilerModifiers.AccUnresolved;

+  return method;

+}

+public AnnotationHolder retrieveAnnotationHolder(Binding binding, boolean forceInitialization) {

+  if (forceInitialization)

+    binding.getAnnotationTagBits(); // ensure annotations are up to date

+  return super.retrieveAnnotationHolder(binding, false);

+}

+public void setFields(FieldBinding[] fields) {

+  this.fields = fields;

+}

+public void setMethods(MethodBinding[] methods) {

+  this.methods = methods;

+}

+public final int sourceEnd() {

+  return this.scope.referenceContext.sourceEnd;

+}

+public final int sourceStart() {

+  return this.scope.referenceContext.sourceStart;

+}

+SimpleLookupTable storedAnnotations(boolean forceInitialize) {

+  if (forceInitialize && this.storedAnnotations == null && this.scope != null) { // scope null when no annotation cached, and type got processed fully (159631)

+    this.scope.referenceCompilationUnit().compilationResult.hasAnnotations = true;

+    if (!this.scope.environment().globalOptions.storeAnnotations)

+      return null; // not supported during this compile

+    this.storedAnnotations = new SimpleLookupTable(3);

+  }

+  return this.storedAnnotations;

+}

+public ReferenceBinding superclass() {

+  return this.superclass;

+}

+public ReferenceBinding[] superInterfaces() {

+  return this.superInterfaces;

+}

+// TODO (philippe) could be a performance issue since some senders are building the list just to count them

+public SyntheticMethodBinding[] syntheticMethods() {

+  

+  if (this.synthetics == null || this.synthetics[SourceTypeBinding.METHOD_EMUL] == null || this.synthetics[SourceTypeBinding.METHOD_EMUL].size() == 0) return null;

+

+  // difficult to compute size up front because of the embedded arrays so assume there is only 1

+  int index = 0;

+  SyntheticMethodBinding[] bindings = new SyntheticMethodBinding[1];

+  Iterator fieldsOrMethods = this.synthetics[SourceTypeBinding.METHOD_EMUL].keySet().iterator();

+  while (fieldsOrMethods.hasNext()) {

+

+    Object fieldOrMethod = fieldsOrMethods.next();

+

+    if (fieldOrMethod instanceof MethodBinding) {

+

+      SyntheticMethodBinding[] methodAccessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(fieldOrMethod);

+      int numberOfAccessors = 0;

+      if (methodAccessors[0] != null) numberOfAccessors++;

+      if (methodAccessors[1] != null) numberOfAccessors++;

+      if (index + numberOfAccessors > bindings.length)

+        System.arraycopy(bindings, 0, (bindings = new SyntheticMethodBinding[index + numberOfAccessors]), 0, index);

+      if (methodAccessors[0] != null) 

+        bindings[index++] = methodAccessors[0]; // super access 

+      if (methodAccessors[1] != null) 

+        bindings[index++] = methodAccessors[1]; // normal access or bridge

+

+    } else {

+

+      SyntheticMethodBinding[] fieldAccessors = (SyntheticMethodBinding[]) this.synthetics[SourceTypeBinding.METHOD_EMUL].get(fieldOrMethod);

+      int numberOfAccessors = 0;

+      if (fieldAccessors[0] != null) numberOfAccessors++;

+      if (fieldAccessors[1] != null) numberOfAccessors++;

+      if (index + numberOfAccessors > bindings.length)

+        System.arraycopy(bindings, 0, (bindings = new SyntheticMethodBinding[index + numberOfAccessors]), 0, index);

+      if (fieldAccessors[0] != null) 

+        bindings[index++] = fieldAccessors[0]; // read access

+      if (fieldAccessors[1] != null) 

+        bindings[index++] = fieldAccessors[1]; // write access

+    }

+  }

+

+  // sort them in according to their own indexes

+  int length;

+  SyntheticMethodBinding[] sortedBindings = new SyntheticMethodBinding[length = bindings.length];

+  for (int i = 0; i < length; i++){

+    SyntheticMethodBinding binding = bindings[i];

+    sortedBindings[binding.index] = binding;

+  }

+  return sortedBindings;

+}

+/**

+ * Answer the collection of synthetic fields to append into the classfile

+ */

+public FieldBinding[] syntheticFields() {

+  

+  if (this.synthetics == null) return null;

+

+  int fieldSize = this.synthetics[SourceTypeBinding.FIELD_EMUL] == null ? 0 : this.synthetics[SourceTypeBinding.FIELD_EMUL].size();

+  int literalSize = this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] == null ? 0 :this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].size();

+  int totalSize = fieldSize + literalSize;

+  if (totalSize == 0) return null;

+  FieldBinding[] bindings = new FieldBinding[totalSize];

+

+  // add innerclass synthetics

+  if (this.synthetics[SourceTypeBinding.FIELD_EMUL] != null){

+    Iterator elements = this.synthetics[SourceTypeBinding.FIELD_EMUL].values().iterator();

+    for (int i = 0; i < fieldSize; i++) {

+      SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.next();

+      bindings[synthBinding.index] = synthBinding;

+    }

+  }

+  // add class literal synthetics

+  if (this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL] != null){

+    Iterator elements = this.synthetics[SourceTypeBinding.CLASS_LITERAL_EMUL].values().iterator();

+    for (int i = 0; i < literalSize; i++) {

+      SyntheticFieldBinding synthBinding = (SyntheticFieldBinding) elements.next();

+      bindings[fieldSize+synthBinding.index] = synthBinding;

+    }

+  }

+  return bindings;

+}

+public String toString() {

+    StringBuffer buffer = new StringBuffer(30);

+    buffer.append("(id="); //$NON-NLS-1$

+    if (this.id == TypeIds.NoId) 

+        buffer.append("NoId"); //$NON-NLS-1$

+    else 

+        buffer.append(this.id);

+    buffer.append(")\n"); //$NON-NLS-1$

+  if (isDeprecated()) buffer.append("deprecated "); //$NON-NLS-1$

+  if (isPublic()) buffer.append("public "); //$NON-NLS-1$

+  if (isProtected()) buffer.append("protected "); //$NON-NLS-1$

+  if (isPrivate()) buffer.append("private "); //$NON-NLS-1$

+  if (isAbstract() && isClass()) buffer.append("abstract "); //$NON-NLS-1$

+  if (isStatic() && isNestedType()) buffer.append("static "); //$NON-NLS-1$

+  if (isFinal()) buffer.append("final "); //$NON-NLS-1$

+

+  if (isEnum()) buffer.append("enum "); //$NON-NLS-1$

+  else if (isAnnotationType()) buffer.append("@interface "); //$NON-NLS-1$

+  else if (isClass()) buffer.append("class "); //$NON-NLS-1$

+  else buffer.append("interface "); //$NON-NLS-1$

+  buffer.append((this.compoundName != null) ? CharOperation.toString(this.compoundName) : "UNNAMED TYPE"); //$NON-NLS-1$

+

+  if (this.typeVariables == null) {

+    buffer.append("<NULL TYPE VARIABLES>"); //$NON-NLS-1$

+  } else if (this.typeVariables != Binding.NO_TYPE_VARIABLES) {

+    buffer.append("<"); //$NON-NLS-1$

+    for (int i = 0, length = this.typeVariables.length; i < length; i++) {

+      if (i  > 0) buffer.append(", "); //$NON-NLS-1$

+      if (this.typeVariables[i] == null) {

+        buffer.append("NULL TYPE VARIABLE"); //$NON-NLS-1$

+        continue;

+      }

+      char[] varChars = this.typeVariables[i].toString().toCharArray();

+      buffer.append(varChars, 1, varChars.length - 2);

+    }

+    buffer.append(">"); //$NON-NLS-1$

+  }

+  buffer.append("\n\textends "); //$NON-NLS-1$

+  buffer.append((this.superclass != null) ? this.superclass.debugName() : "NULL TYPE"); //$NON-NLS-1$

+

+  if (this.superInterfaces != null) {

+    if (this.superInterfaces != Binding.NO_SUPERINTERFACES) {

+      buffer.append("\n\timplements : "); //$NON-NLS-1$

+      for (int i = 0, length = this.superInterfaces.length; i < length; i++) {

+        if (i  > 0)

+          buffer.append(", "); //$NON-NLS-1$

+        buffer.append((this.superInterfaces[i] != null) ? this.superInterfaces[i].debugName() : "NULL TYPE"); //$NON-NLS-1$

+      }

+    }

+  } else {

+    buffer.append("NULL SUPERINTERFACES"); //$NON-NLS-1$

+  }

+

+  if (enclosingType() != null) {

+    buffer.append("\n\tenclosing type : "); //$NON-NLS-1$

+    buffer.append(enclosingType().debugName());

+  }

+

+  if (this.fields != null) {

+    if (this.fields != Binding.NO_FIELDS) {

+      buffer.append("\n/*   fields   */"); //$NON-NLS-1$

+      for (int i = 0, length = this.fields.length; i < length; i++)

+          buffer.append('\n').append((this.fields[i] != null) ? this.fields[i].toString() : "NULL FIELD"); //$NON-NLS-1$ 

+    }

+  } else {

+    buffer.append("NULL FIELDS"); //$NON-NLS-1$

+  }

+

+  if (this.methods != null) {

+    if (this.methods != Binding.NO_METHODS) {

+      buffer.append("\n/*   methods   */"); //$NON-NLS-1$

+      for (int i = 0, length = this.methods.length; i < length; i++)

+        buffer.append('\n').append((this.methods[i] != null) ? this.methods[i].toString() : "NULL METHOD"); //$NON-NLS-1$

+    }

+  } else {

+    buffer.append("NULL METHODS"); //$NON-NLS-1$

+  }

+

+  if (this.memberTypes != null) {

+    if (this.memberTypes != Binding.NO_MEMBER_TYPES) {

+      buffer.append("\n/*   members   */"); //$NON-NLS-1$

+      for (int i = 0, length = this.memberTypes.length; i < length; i++)

+        buffer.append('\n').append((this.memberTypes[i] != null) ? this.memberTypes[i].toString() : "NULL TYPE"); //$NON-NLS-1$

+    }

+  } else {

+    buffer.append("NULL MEMBER TYPES"); //$NON-NLS-1$

+  }

+

+  buffer.append("\n\n"); //$NON-NLS-1$

+  return buffer.toString();

+}

+public TypeVariableBinding[] typeVariables() {

+  return this.typeVariables;

+}

+void verifyMethods(MethodVerifier verifier) {

+  verifier.verify(this);

+

+  for (int i = this.memberTypes.length; --i >= 0;)

+     ((SourceTypeBinding) this.memberTypes[i]).verifyMethods(verifier);

+}

+}