Package org.eclipse.jdt.internal.codeassist

Source Code of org.eclipse.jdt.internal.codeassist.CompletionEngine$CompletionProblemFactory

/*******************************************************************************
* Copyright (c) 2000, 2011 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.codeassist;

import java.util.ArrayList;
import java.util.Locale;
import java.util.Map;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jdt.core.CompletionContext;
import org.eclipse.jdt.core.CompletionFlags;
import org.eclipse.jdt.core.CompletionProposal;
import org.eclipse.jdt.core.CompletionRequestor;
import org.eclipse.jdt.core.Flags;
import org.eclipse.jdt.core.IAccessRule;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.ITypeRoot;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.core.search.IJavaSearchConstants;

import org.eclipse.jdt.internal.codeassist.complete.*;
import org.eclipse.jdt.internal.codeassist.impl.AssistParser;
import org.eclipse.jdt.internal.codeassist.impl.Engine;
import org.eclipse.jdt.internal.codeassist.impl.Keywords;
import org.eclipse.jdt.internal.compiler.CompilationResult;
import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
import org.eclipse.jdt.internal.compiler.ExtraFlags;
import org.eclipse.jdt.internal.compiler.ast.*;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.env.*;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.*;
import org.eclipse.jdt.internal.compiler.parser.ScannerHelper;
import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter;
import org.eclipse.jdt.internal.compiler.parser.JavadocTagConstants;
import org.eclipse.jdt.internal.compiler.parser.TerminalTokens;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
import org.eclipse.jdt.internal.compiler.problem.ProblemReporter;
import org.eclipse.jdt.internal.compiler.problem.ProblemSeverities;
import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
import org.eclipse.jdt.internal.compiler.util.ObjectVector;
import org.eclipse.jdt.internal.core.BasicCompilationUnit;
import org.eclipse.jdt.internal.core.INamingRequestor;
import org.eclipse.jdt.internal.core.InternalNamingConventions;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.core.SourceMethod;
import org.eclipse.jdt.internal.core.SourceMethodElementInfo;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.core.BinaryTypeConverter;
import org.eclipse.jdt.internal.core.SearchableEnvironment;
import org.eclipse.jdt.internal.core.SourceTypeElementInfo;
import org.eclipse.jdt.internal.core.search.matching.JavaSearchNameEnvironment;
import org.eclipse.jdt.internal.core.util.Messages;

/**
* This class is the entry point for source completions.
* It contains two public APIs used to call CodeAssist on a given source with
* a given environment, assisting position and storage (and possibly options).
*/
public final class CompletionEngine
  extends Engine
  implements ISearchRequestor, TypeConstants , TerminalTokens , RelevanceConstants, SuffixConstants {
 
  private static class AcceptedConstructor {
    public int modifiers;
    public char[] simpleTypeName;
    public int parameterCount;
    public char[] signature;
    public char[][] parameterTypes;
    public char[][] parameterNames;
    public int typeModifiers;
    public char[] packageName;
    public int extraFlags;
    public int accessibility;
    public boolean proposeType = false;
    public boolean proposeConstructor = false;
    public char[] fullyQualifiedName = null;
   
    public boolean mustBeQualified = false;
   
    public AcceptedConstructor(
        int modifiers,
        char[] simpleTypeName,
        int parameterCount,
        char[] signature,
        char[][] parameterTypes,
        char[][] parameterNames,
        int typeModifiers,
        char[] packageName,
        int extraFlags,
        int accessibility) {
      this.modifiers = modifiers;
      this.simpleTypeName = simpleTypeName;
      this.parameterCount = parameterCount;
      this.signature = signature;
      this.parameterTypes = parameterTypes;
      this.parameterNames = parameterNames;
      this.typeModifiers = typeModifiers;
      this.packageName = packageName;
      this.extraFlags = extraFlags;
      this.accessibility = accessibility;
    }

    public String toString() {
      StringBuffer buffer = new StringBuffer();
      buffer.append('{');
      buffer.append(this.packageName);
      buffer.append(',');
      buffer.append(this.simpleTypeName);
      buffer.append('}');
      return buffer.toString();
    }
  }
 
  private static class AcceptedType {
    public char[] packageName;
    public char[] simpleTypeName;
    public char[][] enclosingTypeNames;
    public int modifiers;
    public int accessibility;
    public boolean mustBeQualified = false;

    public char[] fullyQualifiedName = null;
    public char[] qualifiedTypeName = null;
    public AcceptedType(
      char[] packageName,
      char[] simpleTypeName,
      char[][] enclosingTypeNames,
      int modifiers,
      int accessibility) {
      this.packageName = packageName;
      this.simpleTypeName = simpleTypeName;
      this.enclosingTypeNames = enclosingTypeNames;
      this.modifiers = modifiers;
      this.accessibility = accessibility;
    }

    public String toString() {
      StringBuffer buffer = new StringBuffer();
      buffer.append('{');
      buffer.append(this.packageName);
      buffer.append(',');
      buffer.append(this.simpleTypeName);
      buffer.append(',');
      buffer.append(CharOperation.concatWith(this.enclosingTypeNames, '.'));
      buffer.append('}');
      return buffer.toString();
    }
  }
 
  public class CompletionProblemFactory extends DefaultProblemFactory {
    private int lastErrorStart;

    private boolean checkProblems = false;
    public boolean hasForbiddenProblems = false;
    public boolean hasAllowedProblems = false;

    public CompletionProblemFactory(Locale loc) {
      super(loc);
    }

    private CategorizedProblem checkProblem(CategorizedProblem pb,
      char[] originatingFileName,  int severity, int start) {
      int id = pb.getID();
      if (CompletionEngine.this.actualCompletionPosition > start
        && this.lastErrorStart < start
        && pb.isError()
        && (id & IProblem.Syntax) == 0
        && (CompletionEngine.this.fileName == null || CharOperation.equals(CompletionEngine.this.fileName, originatingFileName))) {

        CompletionEngine.this.problem = pb;
        this.lastErrorStart = start;
      }
      if (this.checkProblems && !this.hasForbiddenProblems) {
        switch (id) {
          case IProblem.UsingDeprecatedType:
            this.hasForbiddenProblems =
              CompletionEngine.this.options.checkDeprecation;
            break;
          case IProblem.NotVisibleType:
            this.hasForbiddenProblems =
              CompletionEngine.this.options.checkVisibility;
            break;
          case IProblem.ForbiddenReference:
            this.hasForbiddenProblems =
              CompletionEngine.this.options.checkForbiddenReference;
            break;
          case IProblem.DiscouragedReference:
            this.hasForbiddenProblems =
              CompletionEngine.this.options.checkDiscouragedReference;
            break;
          default:
            if ((severity & ProblemSeverities.Optional) != 0) {
              this.hasAllowedProblems = true;
            } else {
              this.hasForbiddenProblems = true;
            }

            break;
        }
      }

      return pb;
    }

    public CategorizedProblem createProblem(
        char[] originatingFileName,
        int problemId,
        String[] problemArguments,
        int elaborationId,
        String[] messageArguments,
        int severity,
        int start,
        int end,
        int lineNumber,
        int columnNumber) {
        return checkProblem(
          super.createProblem(
            originatingFileName,
            problemId,
            problemArguments,
            elaborationId,
            messageArguments,
            severity,
            start,
            end,
            lineNumber,
            columnNumber), originatingFileName, severity, start);
    }

    public CategorizedProblem createProblem(
        char[] originatingFileName,
        int problemId,
        String[] problemArguments,
        String[] messageArguments,
        int severity,
        int start,
        int end,
        int lineNumber,
        int columnNumber) {
        return checkProblem(
          super.createProblem(
            originatingFileName,
            problemId,
            problemArguments,
            messageArguments,
            severity,
            start,
            end,
            lineNumber,
            columnNumber), originatingFileName, severity, start);
    }

    public void startCheckingProblems() {
      this.checkProblems = true;
      this.hasForbiddenProblems = false;
      this.hasAllowedProblems = false;
    }

    public void stopCheckingProblems() {
      this.checkProblems = false;
    }
  }
 
  public static char[] createBindingKey(char[] packageName, char[] typeName) {
    char[] signature = createTypeSignature(packageName, typeName);
    CharOperation.replace(signature, '.', '/');
    return signature;
  }

  public static char[][] createDefaultParameterNames(int length) {
    char[][] parameters;
    switch (length) {
      case 0 :
        parameters = new char[length][];
        break;
      case 1 :
        parameters = ARGS1;
        break;
      case 2 :
        parameters = ARGS2;
        break;
      case 3 :
        parameters = ARGS3;
        break;
      case 4 :
        parameters = ARGS4;
        break;
      default :
        parameters = new char[length][];
        for (int i = 0; i < length; i++) {
          parameters[i] = CharOperation.concat(ARG, String.valueOf(i).toCharArray());
        }
        break;
    }
    return parameters;
  }
  public static char[] createMethodSignature(char[][] parameterPackageNames, char[][] parameterTypeNames, char[] returnTypeSignature) {
    char[][] parameterTypeSignature = new char[parameterTypeNames.length][];
    for (int i = 0; i < parameterTypeSignature.length; i++) {
      parameterTypeSignature[i] =
        Signature.createCharArrayTypeSignature(
            CharOperation.concat(
                parameterPackageNames[i],
                CharOperation.replaceOnCopy(parameterTypeNames[i], '.', '$'), '.'), true);
    }

    return Signature.createMethodSignature(
        parameterTypeSignature,
        returnTypeSignature);
  }

  public static char[] createMethodSignature(char[][] parameterPackageNames, char[][] parameterTypeNames, char[] returnPackagename, char[] returnTypeName) {
    char[] returnTypeSignature =
      returnTypeName == null || returnTypeName.length == 0
      ? Signature.createCharArrayTypeSignature(VOID, true)
      : Signature.createCharArrayTypeSignature(
          CharOperation.concat(
              returnPackagename,
              CharOperation.replaceOnCopy(returnTypeName, '.', '$'), '.'), true);

    return createMethodSignature(
        parameterPackageNames,
        parameterTypeNames,
        returnTypeSignature);
  }
  public static char[] createNonGenericTypeSignature(char[] qualifiedPackageName, char[] qualifiedTypeName) {
    return Signature.createCharArrayTypeSignature(
        CharOperation.concat(
            qualifiedPackageName,
            CharOperation.replaceOnCopy(qualifiedTypeName, '.', '$'), '.'), true);
  }

  public static char[] createTypeSignature(char[] qualifiedPackageName, char[] qualifiedTypeName) {
    char[] name = new char[qualifiedTypeName.length];
    System.arraycopy(qualifiedTypeName, 0, name, 0, qualifiedTypeName.length);

    int depth = 0;
    int length = name.length;
    for (int i = length -1; i >= 0; i--) {
      switch (name[i]) {
        case '.':
          if (depth == 0 && name[i - 1] != '>') {
            name[i] = '$';
          }
          break;
        case '<':
          depth--;
          break;
        case '>':
          depth++;
          break;
      }
    }
    return Signature.createCharArrayTypeSignature(
        CharOperation.concat(
            qualifiedPackageName,
            name, '.'), true);
  }

  private static char[] getRequiredTypeSignature(TypeBinding typeBinding) {
    char[] result = null;
    StringBuffer sig = new StringBuffer(10);

    sig.append(typeBinding.signature());

    int sigLength = sig.length();
    result = new char[sigLength];
    sig.getChars(0, sigLength, result, 0);
    result = CharOperation.replaceOnCopy(result, '/', '.');
    return result;
  }
 
  private static char[] getTypeName(TypeReference typeReference) {
    char[] typeName = CharOperation.concatWith(typeReference.getTypeName(), '.');
    int dims = typeReference.dimensions();
    if (dims > 0) {
      int length = typeName.length;
      int newLength = length + (dims*2);
      System.arraycopy(typeName, 0, typeName = new char[newLength], 0, length);
      for (int k = length; k < newLength; k += 2) {
        typeName[k] = '[';
        typeName[k+1] = ']';
      }
    }
   
    return typeName;
  }
 
  private static boolean hasStaticMemberTypes(ReferenceBinding typeBinding, SourceTypeBinding invocationType, CompilationUnitScope unitScope) {
    ReferenceBinding[] memberTypes = typeBinding.memberTypes();
    int length = memberTypes == null ? 0 : memberTypes.length;
    next : for (int i = 0; i < length; i++) {
      ReferenceBinding memberType = memberTypes[i];
      if (invocationType != null && !memberType.canBeSeenBy(typeBinding, invocationType)) {
        continue next;
      } else if(invocationType == null && !memberType.canBeSeenBy(unitScope.fPackage)) {
        continue next;
      }
     
      if ((memberType.modifiers & ClassFileConstants.AccStatic) != 0) {
        return true;
      }
    }
    return false;
  }
 
  private static boolean hasMemberTypesInEnclosingScope(SourceTypeBinding typeBinding, Scope scope) {
    ReferenceBinding[] memberTypes = typeBinding.memberTypes();
    int length = memberTypes == null ? 0 : memberTypes.length;
   
    if (length > 0) {
      MethodScope methodScope = scope.methodScope();
      if (methodScope != null && !methodScope.isStatic) {
        ClassScope classScope = typeBinding.scope;
        Scope currentScope = scope;
        while (currentScope != null) {
          if (currentScope == classScope) {
            return true;
          }
          currentScope = currentScope.parent;
        }
      }
    }
    return false;
  }
 
  public HashtableOfObject typeCache;
  public int openedBinaryTypes; // used during InternalCompletionProposal#findConstructorParameterNames()
 
  public static boolean DEBUG = false;
  public static boolean PERF = false;
 
  private static final char[] KNOWN_TYPE_WITH_UNKNOWN_CONSTRUCTORS = new char[]{};
  private static final char[] KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS = new char[]{};
 
  private static final char[] ARG = "arg".toCharArray()//$NON-NLS-1$
  private static final char[] ARG0 = "arg0".toCharArray()//$NON-NLS-1$
  private static final char[] ARG1 = "arg1".toCharArray()//$NON-NLS-1$
  private static final char[] ARG2 = "arg2".toCharArray()//$NON-NLS-1$
  private static final char[] ARG3 = "arg3".toCharArray()//$NON-NLS-1$
  private static final char[][] ARGS1 = new char[][]{ARG0};
  private static final char[][] ARGS2 = new char[][]{ARG0, ARG1};
  private static final char[][] ARGS3 = new char[][]{ARG0, ARG1, ARG2};
  private static final char[][] ARGS4 = new char[][]{ARG0, ARG1, ARG2, ARG3};
 
  private final static int CHECK_CANCEL_FREQUENCY = 50;
 
  // temporary constants to quickly disabled polish features if necessary
  public final static boolean NO_TYPE_COMPLETION_ON_EMPTY_TOKEN = false;
 
  private final static char[] ERROR_PATTERN = "*error*".toCharArray()//$NON-NLS-1$
  private final static char[] EXCEPTION_PATTERN = "*exception*".toCharArray()//$NON-NLS-1$
  private final static char[] SEMICOLON = new char[] { ';' };

  private final static char[] CLASS = "Class".toCharArray()//$NON-NLS-1$
  private final static char[] VOID = "void".toCharArray()//$NON-NLS-1$
  private final static char[] INT = "int".toCharArray()//$NON-NLS-1$
  private final static char[] INT_SIGNATURE = new char[]{Signature.C_INT};
  private final static char[] VALUE = "value".toCharArray()//$NON-NLS-1$
  private final static char[] EXTENDS = "extends".toCharArray()//$NON-NLS-1$
  private final static char[] SUPER = "super".toCharArray()//$NON-NLS-1$
  private final static char[] DEFAULT_CONSTRUCTOR_SIGNATURE = "()V".toCharArray()//$NON-NLS-1$
 
  private final static char[] DOT = ".".toCharArray()//$NON-NLS-1$

  private final static char[] VARARGS = "...".toCharArray()//$NON-NLS-1$
 
  private final static char[] IMPORT = "import".toCharArray()//$NON-NLS-1$
  private final static char[] STATIC = "static".toCharArray()//$NON-NLS-1$
  private final static char[] ON_DEMAND = ".*".toCharArray()//$NON-NLS-1$
  private final static char[] IMPORT_END = ";\n".toCharArray()//$NON-NLS-1$

  private final static char[] JAVA_LANG_OBJECT_SIGNATURE =
    createTypeSignature(CharOperation.concatWith(JAVA_LANG, '.'), OBJECT);
  private final static char[] JAVA_LANG_NAME =
    CharOperation.concatWith(JAVA_LANG, '.');
 
  private final static int NONE = 0;
  private final static int SUPERTYPE = 1;
  private final static int SUBTYPE = 2;
 
  private final static char[] DOT_ENUM = ".enum".toCharArray(); //$NON-NLS-1$
 
  int expectedTypesPtr = -1;
  TypeBinding[] expectedTypes = new TypeBinding[1];
  int expectedTypesFilter;
  boolean hasJavaLangObjectAsExpectedType = false;
  boolean hasExpectedArrayTypes = false;
  boolean hasComputedExpectedArrayTypes = false;
  int uninterestingBindingsPtr = -1;
  Binding[] uninterestingBindings = new Binding[1];
  int forbbidenBindingsPtr = -1;
  Binding[] forbbidenBindings = new Binding[1];
  int uninterestingBindingsFilter;     // only set when completing on an exception type
 
  ImportBinding[] favoriteReferenceBindings;
 
  boolean assistNodeIsClass;
  boolean assistNodeIsEnum;
  boolean assistNodeIsException;
  boolean assistNodeIsInterface;
  boolean assistNodeIsAnnotation;
  boolean assistNodeIsConstructor;
  boolean assistNodeIsSuperType;
  boolean assistNodeIsExtendedType;
  boolean assistNodeIsInterfaceExcludingAnnotation; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310423
  int  assistNodeInJavadoc = 0;
  boolean assistNodeCanBeSingleMemberAnnotation = false;
  boolean assistNodeIsInsideCase = false; // https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346
  boolean assistNodeIsString = false// https://bugs.eclipse.org/bugs/show_bug.cgi?id=343476
 
  long targetedElement;
 
  WorkingCopyOwner owner;
  IProgressMonitor monitor;
  IJavaProject javaProject;
  ITypeRoot typeRoot;
  CompletionParser parser;
  CompletionRequestor requestor;
  CompletionProblemFactory problemFactory;
  ProblemReporter problemReporter;
  private JavaSearchNameEnvironment noCacheNameEnvironment;
  char[] source;
  char[] completionToken;
  char[] qualifiedCompletionToken;
  boolean resolvingImports = false;
  boolean resolvingStaticImports = false;
  boolean insideQualifiedReference = false;
  boolean noProposal = true;
  CategorizedProblem problem = null;
  char[] fileName = null;
  int startPosition, actualCompletionPosition, endPosition, offset;
  int tokenStart, tokenEnd;
  int javadocTagPosition; // Position of previous tag while completing in javadoc
  HashtableOfObject knownPkgs = new HashtableOfObject(10);
  HashtableOfObject knownTypes = new HashtableOfObject(10);
 
   /*
    static final char[][] mainDeclarations =
      new char[][] {
        "package".toCharArray(),
        "import".toCharArray(),
        "abstract".toCharArray(),
        "final".toCharArray(),
        "public".toCharArray(),
        "class".toCharArray(),
        "interface".toCharArray()};

    static final char[][] modifiers = // may want field, method, type & member type modifiers
      new char[][] {
        "abstract".toCharArray(),
        "final".toCharArray(),
        "native".toCharArray(),
        "public".toCharArray(),
        "protected".toCharArray(),
        "private".toCharArray(),
        "static".toCharArray(),
        "strictfp".toCharArray(),
        "synchronized".toCharArray(),
        "transient".toCharArray(),
        "volatile".toCharArray()};
  */
  static final BaseTypeBinding[] BASE_TYPES = {
    TypeBinding.BOOLEAN,
    TypeBinding.BYTE,
    TypeBinding.CHAR,
    TypeBinding.DOUBLE,
    TypeBinding.FLOAT,
    TypeBinding.INT,
    TypeBinding.LONG,
    TypeBinding.SHORT,
    TypeBinding.VOID
  };
  static final int BASE_TYPES_LENGTH = BASE_TYPES.length;
  static final char[][] BASE_TYPE_NAMES = new char[BASE_TYPES_LENGTH][];
  static final int BASE_TYPES_WITHOUT_VOID_LENGTH = BASE_TYPES.length - 1;
  static final char[][] BASE_TYPE_NAMES_WITHOUT_VOID = new char[BASE_TYPES_WITHOUT_VOID_LENGTH][];
  static {
     for (int i=0; i<BASE_TYPES_LENGTH; i++) {
       BASE_TYPE_NAMES[i] = BASE_TYPES[i].simpleName;
     }
    for (int i=0; i<BASE_TYPES_WITHOUT_VOID_LENGTH; i++) {
      BASE_TYPE_NAMES_WITHOUT_VOID[i] = BASE_TYPES[i].simpleName;
    }
   }
 
  static final char[] classField = "class".toCharArray()//$NON-NLS-1$
  static final char[] lengthField = "length".toCharArray()//$NON-NLS-1$
  static final char[] cloneMethod = "clone".toCharArray()//$NON-NLS-1$
  static final char[] THIS = "this".toCharArray()//$NON-NLS-1$
  static final char[] THROWS = "throws".toCharArray()//$NON-NLS-1$

  static InvocationSite FakeInvocationSite = new InvocationSite(){
    public TypeBinding[] genericTypeArguments() { return null; }
    public boolean isSuperAccess(){ return false; }
    public boolean isTypeAccess(){ return false; }
    public void setActualReceiverType(ReferenceBinding receiverType) {/* empty */}
    public void setDepth(int depth){/* empty */}
    public void setFieldIndex(int depth){/* empty */}
    public int sourceEnd() { return 0;   }
    public int sourceStart() { return 0;   }
    public TypeBinding expectedType() { return null; }
  };

  private int foundTypesCount;
  private ObjectVector acceptedTypes;
 
  private int foundConstructorsCount;
  private ObjectVector acceptedConstructors;

  /**
   * The CompletionEngine is responsible for computing source completions.
   *
   * It requires a searchable name environment, which supports some
   * specific search APIs, and a requestor to feed back the results to a UI.
   *
   *  @param nameEnvironment org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment
   *      used to resolve type/package references and search for types/packages
   *      based on partial names.
   *
   *  @param requestor org.eclipse.jdt.internal.codeassist.ICompletionRequestor
   *      since the engine might produce answers of various forms, the engine
   *      is associated with a requestor able to accept all possible completions.
   *
   *  @param settings java.util.Map
   *    set of options used to configure the code assist engine.
   */
  public CompletionEngine(
      SearchableEnvironment nameEnvironment,
      CompletionRequestor requestor,
      Map settings,
      IJavaProject javaProject,
      WorkingCopyOwner owner,
      IProgressMonitor monitor) {
    super(settings);
    this.javaProject = javaProject;
    this.requestor = requestor;
    this.nameEnvironment = nameEnvironment;
    this.typeCache = new HashtableOfObject(5);
    this.openedBinaryTypes = 0;

    this.problemFactory = new CompletionProblemFactory(Locale.getDefault());
    this.problemReporter = new ProblemReporter(
        DefaultErrorHandlingPolicies.proceedWithAllProblems(),
        this.compilerOptions,
        this.problemFactory);
    this.lookupEnvironment =
      new LookupEnvironment(this, this.compilerOptions, this.problemReporter, nameEnvironment);
    this.parser =
      new CompletionParser(this.problemReporter, this.requestor.isExtendedContextRequired());
    this.owner = owner;
    this.monitor = monitor;
  }
 
  public void accept(ICompilationUnit sourceUnit, AccessRestriction accessRestriction) {
    if (!CharOperation.equals(sourceUnit.getMainTypeName(), TypeConstants.PACKAGE_INFO_NAME)) {
      // do not accept package-info.java as a type for completion engine
      // because it contains no extra info that will help in completion
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343865
      // Required after the fix for https://bugs.eclipse.org/bugs/show_bug.cgi?id=337868
      // because now we get a type corresponding to the package-info.java from the java model.
      super.accept(sourceUnit, accessRestriction);
    }
  }
 
  public void acceptConstructor(
      int modifiers,
      char[] simpleTypeName,
      int parameterCount,
      char[] signature,
      char[][] parameterTypes,
      char[][] parameterNames,
      int typeModifiers,
      char[] packageName,
      int extraFlags,
      String path,
      AccessRestriction accessRestriction) {
   
    // does not check cancellation for every types to avoid performance loss
    if ((this.foundConstructorsCount % (CHECK_CANCEL_FREQUENCY)) == 0) checkCancel();
    this.foundConstructorsCount++;
   
    if ((typeModifiers & ClassFileConstants.AccEnum) != 0) return;
   
    if (this.options.checkDeprecation && (typeModifiers & ClassFileConstants.AccDeprecated) != 0) return;

    if (this.options.checkVisibility) {
      if((typeModifiers & ClassFileConstants.AccPublic) == 0) {
        if((typeModifiers & ClassFileConstants.AccPrivate) != 0) return;

        if (this.currentPackageName == null) {
          initializePackageCache();
        }
       
        if(!CharOperation.equals(packageName, this.currentPackageName)) return;
      }
    }

    int accessibility = IAccessRule.K_ACCESSIBLE;
    if(accessRestriction != null) {
      switch (accessRestriction.getProblemId()) {
        case IProblem.ForbiddenReference:
          if (this.options.checkForbiddenReference) {
            return;
          }
          accessibility = IAccessRule.K_NON_ACCESSIBLE;
          break;
        case IProblem.DiscouragedReference:
          if (this.options.checkDiscouragedReference) {
            return;
          }
          accessibility = IAccessRule.K_DISCOURAGED;
          break;
      }
    }
   
    if(this.acceptedConstructors == null) {
      this.acceptedConstructors = new ObjectVector();
    }
    this.acceptedConstructors.add(
        new AcceptedConstructor(
            modifiers,
            simpleTypeName,
            parameterCount,
            signature,
            parameterTypes,
            parameterNames,
            typeModifiers,
            packageName,
            extraFlags,
            accessibility));
  }
 
  private void acceptConstructors(Scope scope) {
    final boolean DEFER_QUALIFIED_PROPOSALS = false;
   
    this.checkCancel();
   
    if(this.acceptedConstructors == null) return;

    int length = this.acceptedConstructors.size();

    if(length == 0) return;
   
    HashtableOfObject onDemandFound = new HashtableOfObject();
   
    ArrayList deferredProposals = null;
    if (DEFER_QUALIFIED_PROPOSALS) {
      deferredProposals = new ArrayList();
    }
   
    try {
      next : for (int i = 0; i < length; i++) {
       
        // does not check cancellation for every types to avoid performance loss
        if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
       
        AcceptedConstructor acceptedConstructor = (AcceptedConstructor)this.acceptedConstructors.elementAt(i);
        final int typeModifiers = acceptedConstructor.typeModifiers;
        final char[] packageName = acceptedConstructor.packageName;
        final char[] simpleTypeName = acceptedConstructor.simpleTypeName;
        final int modifiers = acceptedConstructor.modifiers;
        final int parameterCount = acceptedConstructor.parameterCount;
        final char[] signature = acceptedConstructor.signature;
        final char[][] parameterTypes = acceptedConstructor.parameterTypes;
        final char[][] parameterNames = acceptedConstructor.parameterNames;
        final int extraFlags = acceptedConstructor.extraFlags;
        final int accessibility = acceptedConstructor.accessibility;
       
        boolean proposeType = hasArrayTypeAsExpectedSuperTypes() || (extraFlags & ExtraFlags.HasNonPrivateStaticMemberTypes) != 0;
       
        char[] fullyQualifiedName = CharOperation.concat(packageName, simpleTypeName, '.');
           
        Object knownTypeKind = this.knownTypes.get(fullyQualifiedName);
        if (knownTypeKind != null) {
          if (knownTypeKind == KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS) {
            // the type and its constructors are already accepted
            continue next;
          }
          // this type is already accepted
          proposeType = false;
        } else {
          this.knownTypes.put(fullyQualifiedName, KNOWN_TYPE_WITH_UNKNOWN_CONSTRUCTORS);
        }
       
        boolean proposeConstructor = true;
         
        if (this.options.checkVisibility) {
          if((modifiers & ClassFileConstants.AccPublic) == 0) {
            if((modifiers & ClassFileConstants.AccPrivate) != 0) {
              if (!proposeType) continue next;
              proposeConstructor = false;
            } else {
              if (this.currentPackageName == null) {
                initializePackageCache();
              }
             
              if(!CharOperation.equals(packageName, this.currentPackageName)) {
               
                if((typeModifiers & ClassFileConstants.AccAbstract) == 0 ||
                    (modifiers & ClassFileConstants.AccProtected) == 0) {
                  if (!proposeType) continue next;
                  proposeConstructor = false;
                }
              }
            }
          }
        }
       
        acceptedConstructor.fullyQualifiedName = fullyQualifiedName;
        acceptedConstructor.proposeType = proposeType;
        acceptedConstructor.proposeConstructor = proposeConstructor;
       
       
        if(!this.importCachesInitialized) {
          initializeImportCaches();
        }
       
        for (int j = 0; j < this.importCacheCount; j++) {
          char[][] importName = this.importsCache[j];
          if(CharOperation.equals(simpleTypeName, importName[0])) {
            if (proposeType) {
              proposeType(
                  packageName,
                  simpleTypeName,
                  typeModifiers,
                  accessibility,
                  simpleTypeName,
                  fullyQualifiedName,
                  !CharOperation.equals(fullyQualifiedName, importName[1]),
                  scope);
            }
           
            if (proposeConstructor && !Flags.isEnum(typeModifiers)) {
              boolean isQualified = !CharOperation.equals(fullyQualifiedName, importName[1]);
              if (!isQualified) {
                proposeConstructor(
                    simpleTypeName,
                    parameterCount,
                    signature,
                    parameterTypes,
                    parameterNames,
                    modifiers,
                    packageName,
                    typeModifiers,
                    accessibility,
                    simpleTypeName,
                    fullyQualifiedName,
                    isQualified,
                    scope,
                    extraFlags);
              } else {
                acceptedConstructor.mustBeQualified = true;
                if (DEFER_QUALIFIED_PROPOSALS) {
                  deferredProposals.add(acceptedConstructor);
                } else {
                  proposeConstructor(acceptedConstructor, scope);
                }
              }
            }
            continue next;
          }
        }


        if (CharOperation.equals(this.currentPackageName, packageName)) {
          if (proposeType) {
            proposeType(
                packageName,
                simpleTypeName,
                typeModifiers,
                accessibility,
                simpleTypeName,
                fullyQualifiedName,
                false,
                scope);
          }
         
          if (proposeConstructor && !Flags.isEnum(typeModifiers)) {
            proposeConstructor(
                simpleTypeName,
                parameterCount,
                signature,
                parameterTypes,
                parameterNames,
                modifiers,
                packageName,
                typeModifiers,
                accessibility,
                simpleTypeName,
                fullyQualifiedName,
                false,
                scope,
                extraFlags);
          }
          continue next;
        } else {
          char[] fullyQualifiedEnclosingTypeOrPackageName = null;

          AcceptedConstructor foundConstructor = null;
          if((foundConstructor = (AcceptedConstructor)onDemandFound.get(simpleTypeName)) == null) {
            for (int j = 0; j < this.onDemandImportCacheCount; j++) {
              ImportBinding importBinding = this.onDemandImportsCache[j];

              char[][] importName = importBinding.compoundName;
              char[] importFlatName = CharOperation.concatWith(importName, '.');

              if(fullyQualifiedEnclosingTypeOrPackageName == null) {
                fullyQualifiedEnclosingTypeOrPackageName = packageName;
              }
              if(CharOperation.equals(fullyQualifiedEnclosingTypeOrPackageName, importFlatName)) {
                if(importBinding.isStatic()) {
                  if((typeModifiers & ClassFileConstants.AccStatic) != 0) {
                    onDemandFound.put(
                        simpleTypeName,
                        acceptedConstructor);
                    continue next;
                  }
                } else {
                  onDemandFound.put(
                      simpleTypeName,
                      acceptedConstructor);
                  continue next;
                }
              }
            }
          } else if(!foundConstructor.mustBeQualified){
            done : for (int j = 0; j < this.onDemandImportCacheCount; j++) {
              ImportBinding importBinding = this.onDemandImportsCache[j];

              char[][] importName = importBinding.compoundName;
              char[] importFlatName = CharOperation.concatWith(importName, '.');

              if(fullyQualifiedEnclosingTypeOrPackageName == null) {
                fullyQualifiedEnclosingTypeOrPackageName = packageName;
              }
              if(CharOperation.equals(fullyQualifiedEnclosingTypeOrPackageName, importFlatName)) {
                if(importBinding.isStatic()) {
                  if((typeModifiers & ClassFileConstants.AccStatic) != 0) {
                    foundConstructor.mustBeQualified = true;
                    break done;
                  }
                } else {
                  foundConstructor.mustBeQualified = true;
                  break done;
                }
              }
            }
          }
          if (proposeType) {
            proposeType(
                packageName,
                simpleTypeName,
                typeModifiers,
                accessibility,
                simpleTypeName,
                fullyQualifiedName,
                true,
                scope);
          }
         
          if (proposeConstructor && !Flags.isEnum(typeModifiers)) {
            acceptedConstructor.mustBeQualified = true;
            if (DEFER_QUALIFIED_PROPOSALS) {
              deferredProposals.add(acceptedConstructor);
            } else {
              proposeConstructor(acceptedConstructor, scope);
            }
          }
        }
      }
   
      char[][] keys = onDemandFound.keyTable;
      Object[] values = onDemandFound.valueTable;
      int max = keys.length;
      for (int i = 0; i < max; i++) {
       
        // does not check cancellation for every types to avoid performance loss
        if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
       
        if(keys[i] != null) {
          AcceptedConstructor value = (AcceptedConstructor) values[i];
          if(value != null) {
            if (value.proposeType) {
              proposeType(
                  value.packageName,
                  value.simpleTypeName,
                  value.typeModifiers,
                  value.accessibility,
                  value.simpleTypeName,
                  value.fullyQualifiedName,
                  value.mustBeQualified,
                  scope);
            }
           
            if (value.proposeConstructor && !Flags.isEnum(value.modifiers)) {
              if (!value.mustBeQualified) {
                proposeConstructor(
                    value.simpleTypeName,
                    value.parameterCount,
                    value.signature,
                    value.parameterTypes,
                    value.parameterNames,
                    value.modifiers,
                    value.packageName,
                    value.typeModifiers,
                    value.accessibility,
                    value.simpleTypeName,
                    value.fullyQualifiedName,
                    value.mustBeQualified,
                    scope,
                    value.extraFlags);
              } else {
                if (DEFER_QUALIFIED_PROPOSALS) {
                  deferredProposals.add(value);
                } else {
                  proposeConstructor(value, scope);
                }
              }
            }
          }
        }
      }
     
      if (DEFER_QUALIFIED_PROPOSALS) {
        int size = deferredProposals.size();
        for (int i = 0; i < size; i++) {
         
          // does not check cancellation for every types to avoid performance loss
          if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
       
          AcceptedConstructor deferredProposal = (AcceptedConstructor)deferredProposals.get(i);
         
          if (deferredProposal.proposeConstructor) {
            proposeConstructor(
                deferredProposal.simpleTypeName,
                deferredProposal.parameterCount,
                deferredProposal.signature,
                deferredProposal.parameterTypes,
                deferredProposal.parameterNames,
                deferredProposal.modifiers,
                deferredProposal.packageName,
                deferredProposal.typeModifiers,
                deferredProposal.accessibility,
                deferredProposal.simpleTypeName,
                deferredProposal.fullyQualifiedName,
                deferredProposal.mustBeQualified,
                scope,
                deferredProposal.extraFlags);
          }
        }
      }
    } finally {
      this.acceptedTypes = null; // reset
    }
  }

  /**
   * One result of the search consists of a new package.
   *
   * NOTE - All package names are presented in their readable form:
   *    Package names are in the form "a.b.c".
   *    The default package is represented by an empty array.
   */
  public void acceptPackage(char[] packageName) {

    if (this.knownPkgs.containsKey(packageName)) return;

    this.knownPkgs.put(packageName, this);

    char[] completion;
    if(this.resolvingImports) {
      if(this.resolvingStaticImports) {
        completion = CharOperation.concat(packageName, new char[] { '.' });
      } else {
        completion = CharOperation.concat(packageName, new char[] { '.', '*', ';' });
      }
    } else {
      completion = packageName;
    }

    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution();
    relevance += computeRelevanceForInterestingProposal();
    relevance += computeRelevanceForCaseMatching(this.qualifiedCompletionToken == null ? this.completionToken : this.qualifiedCompletionToken, packageName);
    if(!this.resolvingImports) {
      relevance += computeRelevanceForQualification(true);
    }
    relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

    this.noProposal = false;
    if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
      InternalCompletionProposal proposal = createProposal(CompletionProposal.PACKAGE_REF, this.actualCompletionPosition);
      proposal.setDeclarationSignature(packageName);
      proposal.setPackageName(packageName);
      proposal.setCompletion(completion);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }
  }

  /**
   * One result of the search consists of a new type.
   *
   * NOTE - All package and type names are presented in their readable form:
   *    Package names are in the form "a.b.c".
   *    Nested type names are in the qualified form "A.I".
   *    The default package is represented by an empty array.
   */
  public void acceptType(
    char[] packageName,
    char[] simpleTypeName,
    char[][] enclosingTypeNames,
    int modifiers,
    AccessRestriction accessRestriction) {
   
    // does not check cancellation for every types to avoid performance loss
    if ((this.foundTypesCount % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
    this.foundTypesCount++;
   
    if (this.options.checkDeprecation && (modifiers & ClassFileConstants.AccDeprecated) != 0) return;
    if (this.assistNodeIsExtendedType && (modifiers & ClassFileConstants.AccFinal) != 0) return;

    if (this.options.checkVisibility) {
      if((modifiers & ClassFileConstants.AccPublic) == 0) {
        if((modifiers & ClassFileConstants.AccPrivate) != 0) return;

        char[] currentPackage = CharOperation.concatWith(this.unitScope.fPackage.compoundName, '.');
        if(!CharOperation.equals(packageName, currentPackage)) return;
      }
    }

    int accessibility = IAccessRule.K_ACCESSIBLE;
    if(accessRestriction != null) {
      switch (accessRestriction.getProblemId()) {
        case IProblem.ForbiddenReference:
          if (this.options.checkForbiddenReference) {
            return;
          }
          accessibility = IAccessRule.K_NON_ACCESSIBLE;
          break;
        case IProblem.DiscouragedReference:
          if (this.options.checkDiscouragedReference) {
            return;
          }
          accessibility = IAccessRule.K_DISCOURAGED;
          break;
      }
    }
   
    if (isForbiddenType(packageName, simpleTypeName, enclosingTypeNames)) {
      return;
    }

    if(this.acceptedTypes == null) {
      this.acceptedTypes = new ObjectVector();
    }
    this.acceptedTypes.add(new AcceptedType(packageName, simpleTypeName, enclosingTypeNames, modifiers, accessibility));
  }

  private void acceptTypes(Scope scope) {
    this.checkCancel();
   
    if(this.acceptedTypes == null) return;

    int length = this.acceptedTypes.size();

    if(length == 0) return;

    HashtableOfObject onDemandFound = new HashtableOfObject();
   
    try {
      next : for (int i = 0; i < length; i++) {
       
        // does not check cancellation for every types to avoid performance loss
        if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
       
        AcceptedType acceptedType = (AcceptedType)this.acceptedTypes.elementAt(i);
        char[] packageName = acceptedType.packageName;
        char[] simpleTypeName = acceptedType.simpleTypeName;
        char[][] enclosingTypeNames = acceptedType.enclosingTypeNames;
        int modifiers = acceptedType.modifiers;
        int accessibility = acceptedType.accessibility;
 
        char[] typeName;
        char[] flatEnclosingTypeNames;
        if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
          flatEnclosingTypeNames = null;
          typeName = simpleTypeName;
        } else {
          flatEnclosingTypeNames = CharOperation.concatWith(acceptedType.enclosingTypeNames, '.');
          typeName = CharOperation.concat(flatEnclosingTypeNames, simpleTypeName, '.');
        }
        char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');
 
        if (this.knownTypes.containsKey(fullyQualifiedName)) continue next;
 
        this.knownTypes.put(fullyQualifiedName, KNOWN_TYPE_WITH_UNKNOWN_CONSTRUCTORS);
 
        if (this.resolvingImports) {
          if(this.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_4 && packageName.length == 0) {
            continue next; // import of default package is forbidden when compliance is 1.4 or higher
          }
 
          char[] completionName = this.insideQualifiedReference ? simpleTypeName : fullyQualifiedName;
 
          if(this.resolvingStaticImports) {
            if(enclosingTypeNames == null || enclosingTypeNames.length == 0) {
              completionName = CharOperation.concat(completionName, new char[] { '.' });
            } else if ((modifiers & ClassFileConstants.AccStatic) == 0) {
              continue next;
            } else {
              completionName = CharOperation.concat(completionName, new char[] { ';' });
            }
          } else {
            completionName = CharOperation.concat(completionName, new char[] { ';' });
          }
 
          int relevance = computeBaseRelevance();
          relevance += computeRelevanceForResolution();
          relevance += computeRelevanceForInterestingProposal(packageName, fullyQualifiedName);
          relevance += computeRelevanceForRestrictions(accessibility);
          relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
 
          this.noProposal = false;
          if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
            createTypeProposal(packageName, typeName, modifiers, accessibility, completionName, relevance);
          }
        } else {
          if(!this.importCachesInitialized) {
            initializeImportCaches();
          }
 
          for (int j = 0; j < this.importCacheCount; j++) {
            char[][] importName = this.importsCache[j];
            if(CharOperation.equals(typeName, importName[0])) {
              proposeType(
                  packageName,
                  simpleTypeName,
                  modifiers,
                  accessibility,
                  typeName,
                  fullyQualifiedName,
                  !CharOperation.equals(fullyQualifiedName, importName[1]),
                  scope);
              continue next;
            }
          }
 
 
          if ((enclosingTypeNames == null || enclosingTypeNames.length == 0 ) && CharOperation.equals(this.currentPackageName, packageName)) {
            proposeType(
                packageName,
                simpleTypeName,
                modifiers,
                accessibility,
                typeName,
                fullyQualifiedName,
                false,
                scope);
            continue next;
          } else {
            char[] fullyQualifiedEnclosingTypeOrPackageName = null;
 
            AcceptedType foundType = null;
            if((foundType = (AcceptedType)onDemandFound.get(simpleTypeName)) == null) {
              for (int j = 0; j < this.onDemandImportCacheCount; j++) {
                ImportBinding importBinding = this.onDemandImportsCache[j];
 
                char[][] importName = importBinding.compoundName;
                char[] importFlatName = CharOperation.concatWith(importName, '.');
 
                if(fullyQualifiedEnclosingTypeOrPackageName == null) {
                  if(enclosingTypeNames != null && enclosingTypeNames.length != 0) {
                    fullyQualifiedEnclosingTypeOrPackageName =
                      CharOperation.concat(
                          packageName,
                          flatEnclosingTypeNames,
                          '.');
                  } else {
                    fullyQualifiedEnclosingTypeOrPackageName =
                      packageName;
                  }
                }
                if(CharOperation.equals(fullyQualifiedEnclosingTypeOrPackageName, importFlatName)) {
                  if(importBinding.isStatic()) {
                    if((modifiers & ClassFileConstants.AccStatic) != 0) {
                      acceptedType.qualifiedTypeName = typeName;
                      acceptedType.fullyQualifiedName = fullyQualifiedName;
                      onDemandFound.put(
                          simpleTypeName,
                          acceptedType);
                      continue next;
                    }
                  } else {
                    acceptedType.qualifiedTypeName = typeName;
                    acceptedType.fullyQualifiedName = fullyQualifiedName;
                    onDemandFound.put(
                        simpleTypeName,
                        acceptedType);
                    continue next;
                  }
                }
              }
            } else if(!foundType.mustBeQualified){
              done : for (int j = 0; j < this.onDemandImportCacheCount; j++) {
                ImportBinding importBinding = this.onDemandImportsCache[j];
 
                char[][] importName = importBinding.compoundName;
                char[] importFlatName = CharOperation.concatWith(importName, '.');
 
                if(fullyQualifiedEnclosingTypeOrPackageName == null) {
                  if(enclosingTypeNames != null && enclosingTypeNames.length != 0) {
                    fullyQualifiedEnclosingTypeOrPackageName =
                      CharOperation.concat(
                          packageName,
                          flatEnclosingTypeNames,
                          '.');
                  } else {
                    fullyQualifiedEnclosingTypeOrPackageName =
                      packageName;
                  }
                }
                if(CharOperation.equals(fullyQualifiedEnclosingTypeOrPackageName, importFlatName)) {
                  if(importBinding.isStatic()) {
                    if((modifiers & ClassFileConstants.AccStatic) != 0) {
                      foundType.mustBeQualified = true;
                      break done;
                    }
                  } else {
                    foundType.mustBeQualified = true;
                    break done;
                  }
                }
              }
            }
            proposeType(
                packageName,
                simpleTypeName,
                modifiers,
                accessibility,
                typeName,
                fullyQualifiedName,
                true,
                scope);
          }
        }
      }
   
      char[][] keys = onDemandFound.keyTable;
      Object[] values = onDemandFound.valueTable;
      int max = keys.length;
      for (int i = 0; i < max; i++) {
        if ((i % CHECK_CANCEL_FREQUENCY) == 0) checkCancel();
        if(keys[i] != null) {
          AcceptedType value = (AcceptedType) values[i];
          if(value != null) {
            proposeType(
                value.packageName,
                value.simpleTypeName,
                value.modifiers,
                value.accessibility,
                value.qualifiedTypeName,
                value.fullyQualifiedName,
                value.mustBeQualified,
                scope);
          }
        }
      }
    } finally {
      this.acceptedTypes = null; // reset
    }
  }
 
  public void acceptUnresolvedName(char[] name) {
    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution(false);
    relevance += computeRelevanceForInterestingProposal();
    relevance += computeRelevanceForCaseMatching(this.completionToken, name);
    relevance += computeRelevanceForQualification(false);
    relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for local variable
    CompletionEngine.this.noProposal = false;
    if(!CompletionEngine.this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) {
      InternalCompletionProposal proposal = CompletionEngine.this.createProposal(CompletionProposal.LOCAL_VARIABLE_REF, CompletionEngine.this.actualCompletionPosition);
      proposal.setSignature(JAVA_LANG_OBJECT_SIGNATURE);
      proposal.setPackageName(JAVA_LANG_NAME);
      proposal.setTypeName(OBJECT);
      proposal.setName(name);
      proposal.setCompletion(name);
      proposal.setFlags(Flags.AccDefault);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance);
      CompletionEngine.this.requestor.accept(proposal);
      if(DEBUG) {
        CompletionEngine.this.printDebug(proposal);
      }
    }
  }
  private void addExpectedType(TypeBinding type, Scope scope){
    if (type == null || !type.isValidBinding() || type == TypeBinding.NULL) return;

    // do not add twice the same type
    for (int i = 0; i <= this.expectedTypesPtr; i++) {
      if (this.expectedTypes[i] == type) return;
    }

    int length = this.expectedTypes.length;
    if (++this.expectedTypesPtr >= length)
      System.arraycopy(this.expectedTypes, 0, this.expectedTypes = new TypeBinding[length * 2], 0, length);
    this.expectedTypes[this.expectedTypesPtr] = type;

    if(type == scope.getJavaLangObject()) {
      this.hasJavaLangObjectAsExpectedType = true;
    }
  }

  private void addForbiddenBindings(Binding binding){
    if (binding == null) return;

    int length = this.forbbidenBindings.length;
    if (++this.forbbidenBindingsPtr >= length)
      System.arraycopy(this.forbbidenBindings, 0, this.forbbidenBindings = new Binding[length * 2], 0, length);
    this.forbbidenBindings[this.forbbidenBindingsPtr] = binding;
  }

  private void addUninterestingBindings(Binding binding){
    if (binding == null) return;

    int length = this.uninterestingBindings.length;
    if (++this.uninterestingBindingsPtr >= length)
      System.arraycopy(this.uninterestingBindings, 0, this.uninterestingBindings = new Binding[length * 2], 0, length);
    this.uninterestingBindings[this.uninterestingBindingsPtr] = binding;
  }

  // this code is derived from MethodBinding#areParametersCompatibleWith(TypeBinding[])
  private final boolean areParametersCompatibleWith(TypeBinding[] parameters, TypeBinding[] arguments, boolean isVarargs) {
    int paramLength = parameters.length;
    int argLength = arguments.length;
    int lastIndex = argLength;
    if (isVarargs) {
      lastIndex = paramLength - 1;
      if (paramLength == argLength) { // accept X[] but not X or X[][]
        TypeBinding varArgType = parameters[lastIndex]; // is an ArrayBinding by definition
        TypeBinding lastArgument = arguments[lastIndex];
        if (varArgType != lastArgument && !lastArgument.isCompatibleWith(varArgType))
          return false;
      } else if (paramLength < argLength) { // all remainig argument types must be compatible with the elementsType of varArgType
        TypeBinding varArgType = ((ArrayBinding) parameters[lastIndex]).elementsType();
        for (int i = lastIndex; i < argLength; i++)
          if (varArgType != arguments[i] && !arguments[i].isCompatibleWith(varArgType))
            return false;
      } else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
        return false;
      }
      // now compare standard arguments from 0 to lastIndex
    } else {
      if(paramLength != argLength)
        return false;
    }
    for (int i = 0; i < lastIndex; i++)
      if (parameters[i] != arguments[i] && !arguments[i].isCompatibleWith(parameters[i]))
        return false;
    return true;
  }

  private void buildContext(
      ASTNode astNode,
      ASTNode astNodeParent,
      CompilationUnitDeclaration compilationUnitDeclaration,
      Binding qualifiedBinding,
      Scope scope) {
    InternalCompletionContext context = new InternalCompletionContext();
    if (this.requestor.isExtendedContextRequired()) {
      context.setExtendedData(
          this.typeRoot,
          compilationUnitDeclaration,
          this.lookupEnvironment,
          scope,
          astNode,
          this.owner,
          this.parser);
    }

    // build expected types context
    if (this.expectedTypesPtr > -1) {
      int length = this.expectedTypesPtr + 1;
      char[][] expTypes = new char[length][];
      char[][] expKeys = new char[length][];
      for (int i = 0; i < length; i++) {
        expTypes[i] = getSignature(this.expectedTypes[i]);
        expKeys[i] = this.expectedTypes[i].computeUniqueKey();
      }
      context.setExpectedTypesSignatures(expTypes);
      context.setExpectedTypesKeys(expKeys);
    }

    context.setOffset(this.actualCompletionPosition + 1 - this.offset);

    // Set javadoc info
    if (astNode instanceof CompletionOnJavadoc) {
      this.assistNodeInJavadoc = ((CompletionOnJavadoc)astNode).getCompletionFlags();
      context.setJavadoc(this.assistNodeInJavadoc);
    }

    if (!(astNode instanceof CompletionOnJavadoc)) {
      CompletionScanner scanner = (CompletionScanner)this.parser.scanner;
      context.setToken(scanner.completionIdentifier);
      context.setTokenRange(
          scanner.completedIdentifierStart - this.offset,
          scanner.completedIdentifierEnd - this.offset,
          scanner.endOfEmptyToken - this.offset);
    } else if(astNode instanceof CompletionOnJavadocTag) {
      CompletionOnJavadocTag javadocTag = (CompletionOnJavadocTag) astNode;
      context.setToken(CharOperation.concat(new char[]{'@'}, javadocTag.token));
      context.setTokenRange(
          javadocTag.tagSourceStart - this.offset,
          javadocTag.tagSourceEnd - this.offset,
          ((CompletionScanner)this.parser.javadocParser.scanner).endOfEmptyToken - this.offset);
    } else {
      CompletionScanner scanner = (CompletionScanner)this.parser.javadocParser.scanner;
      context.setToken(scanner.completionIdentifier);
      context.setTokenRange(
          scanner.completedIdentifierStart - this.offset,
          scanner.completedIdentifierEnd - this.offset,
          scanner.endOfEmptyToken - this.offset);
    }

    if(astNode instanceof CompletionOnStringLiteral) {
      context.setTokenKind(CompletionContext.TOKEN_KIND_STRING_LITERAL);
    } else {
      context.setTokenKind(CompletionContext.TOKEN_KIND_NAME);
    }

    buildTokenLocationContext(context, scope, astNode, astNodeParent);

    if(DEBUG) {
      System.out.println(context.toString());
    }
    this.requestor.acceptContext(context);
  }

  private void buildTokenLocationContext(InternalCompletionContext context, Scope scope, ASTNode astNode, ASTNode astNodeParent) {
    if (scope == null || context.isInJavadoc()) return;

    if (astNode instanceof CompletionOnFieldType) {
      CompletionOnFieldType field = (CompletionOnFieldType) astNode;
      if (!field.isLocalVariable &&
          field.modifiers == ClassFileConstants.AccDefault &&
          (field.annotations == null || field.annotations.length == 0)) {
        context.setTokenLocation(CompletionContext.TL_MEMBER_START);
      }
    } else if (astNode instanceof CompletionOnMethodReturnType) {
      CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode;
      if (method.modifiers == ClassFileConstants.AccDefault &&
          (method.annotations == null || method.annotations.length == 0)) {
        context.setTokenLocation(CompletionContext.TL_MEMBER_START);
      }
    } else {
      ReferenceContext referenceContext = scope.referenceContext();
      if (referenceContext instanceof AbstractMethodDeclaration) {
        AbstractMethodDeclaration methodDeclaration = (AbstractMethodDeclaration)referenceContext;
        if (methodDeclaration.bodyStart <= astNode.sourceStart &&
            astNode.sourceEnd <= methodDeclaration.bodyEnd) {
          // completion is inside a method body
          if (astNodeParent == null &&
              astNode instanceof CompletionOnSingleNameReference &&
              !((CompletionOnSingleNameReference)astNode).isPrecededByModifiers) {
            context.setTokenLocation(CompletionContext.TL_STATEMENT_START);
          }
        }
      } else if (referenceContext instanceof TypeDeclaration) {
        TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext;
        FieldDeclaration[] fields = typeDeclaration.fields;
        if (fields != null) {
          done : for (int i = 0; i < fields.length; i++) {
            if (fields[i] instanceof Initializer) {
              Initializer initializer = (Initializer) fields[i];
              if (initializer.block.sourceStart <= astNode.sourceStart &&
                  astNode.sourceStart < initializer.bodyEnd) {
                // completion is inside an initializer
                if (astNodeParent == null &&
                    astNode instanceof CompletionOnSingleNameReference &&
                    !((CompletionOnSingleNameReference)astNode).isPrecededByModifiers) {
                  context.setTokenLocation(CompletionContext.TL_STATEMENT_START);
                }
                break done;
              }
            }
          }
        }
      }
    }
  }

  void checkCancel() {
    if (this.monitor != null && this.monitor.isCanceled()) {
      throw new OperationCanceledException();
    }
  }

  private boolean complete(
      ASTNode astNode,
      ASTNode astNodeParent,
      ASTNode enclosingNode,
      CompilationUnitDeclaration compilationUnitDeclaration,
      Binding qualifiedBinding,
      Scope scope,
      boolean insideTypeAnnotation) {

    setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd);

    scope = computeForbiddenBindings(astNode, astNodeParent, scope);
    computeUninterestingBindings(astNode, astNodeParent, scope);
    if(astNodeParent != null) {
      if(!isValidParent(astNodeParent, astNode, scope)) return false;
      computeExpectedTypes(astNodeParent, astNode, scope);
    }

    buildContext(astNode, astNodeParent, compilationUnitDeclaration, qualifiedBinding, scope);

    if (astNode instanceof CompletionOnFieldType) {
      completionOnFieldType(astNode, scope);
    } else if (astNode instanceof CompletionOnMethodReturnType) {
      completionOnMethodReturnType(astNode, scope);
    } else if (astNode instanceof CompletionOnSingleNameReference) {
      completionOnSingleNameReference(astNode, astNodeParent, scope, insideTypeAnnotation);
    } else if (astNode instanceof CompletionOnSingleTypeReference) {
      completionOnSingleTypeReference(astNode, astNodeParent, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnQualifiedNameReference) {
      completionOnQualifiedNameReference(astNode, enclosingNode, qualifiedBinding, scope, insideTypeAnnotation);
    } else if (astNode instanceof CompletionOnQualifiedTypeReference) {
      completionOnQualifiedTypeReference(astNode, astNodeParent, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnMemberAccess) {
      completionOnMemberAccess(astNode, enclosingNode, qualifiedBinding, scope, insideTypeAnnotation);
    } else if (astNode instanceof CompletionOnMessageSend) {
      completionOnMessageSend(astNode, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnExplicitConstructorCall) {
      completionOnExplicitConstructorCall(astNode, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnQualifiedAllocationExpression) {
      completionOnQualifiedAllocationExpression(astNode, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnClassLiteralAccess) {
      completionOnClassLiteralAccess(astNode, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnMethodName) {
      completionOnMethodName(astNode, scope);
    } else if (astNode instanceof CompletionOnFieldName) {
      completionOnFieldName(astNode, scope);
    } else if (astNode instanceof CompletionOnLocalName) {
      completionOnLocalOrArgumentName(astNode, scope);
    } else if (astNode instanceof CompletionOnArgumentName) {
      completionOnLocalOrArgumentName(astNode, scope);
    } else if (astNode instanceof CompletionOnKeyword) {
      completionOnKeyword(astNode);
    } else if (astNode instanceof CompletionOnParameterizedQualifiedTypeReference) {
      completionOnParameterizedQualifiedTypeReference(astNode, astNodeParent, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnMarkerAnnotationName) {
      completionOnMarkerAnnotationName(astNode, qualifiedBinding, scope);
    } else if (astNode instanceof CompletionOnMemberValueName) {
      completionOnMemberValueName(astNode, astNodeParent, scope, insideTypeAnnotation);
    } else if(astNode instanceof CompletionOnBranchStatementLabel) {
      completionOnBranchStatementLabel(astNode);
    } else if(astNode instanceof CompletionOnMessageSendName) {
      completionOnMessageSendName(astNode, qualifiedBinding, scope);
    // Completion on Javadoc nodes
    } else if ((astNode.bits & ASTNode.InsideJavadoc) != 0) {
      if (astNode instanceof CompletionOnJavadocSingleTypeReference) {
        completionOnJavadocSingleTypeReference(astNode, scope);
      } else if (astNode instanceof CompletionOnJavadocQualifiedTypeReference) {
        completionOnJavadocQualifiedTypeReference(astNode, qualifiedBinding, scope);
      } else if (astNode instanceof CompletionOnJavadocFieldReference) {
        completionOnJavadocFieldReference(astNode, scope);
      } else if (astNode instanceof CompletionOnJavadocMessageSend) {
        completionOnJavadocMessageSend(astNode, qualifiedBinding, scope);
      } else if (astNode instanceof CompletionOnJavadocAllocationExpression) {
        completionOnJavadocAllocationExpression(astNode, qualifiedBinding, scope);
      } else if (astNode instanceof CompletionOnJavadocParamNameReference) {
        completionOnJavadocParamNameReference(astNode);
      } else if (astNode instanceof CompletionOnJavadocTypeParamReference) {
        completionOnJavadocTypeParamReference(astNode);
      } else if (astNode instanceof CompletionOnJavadocTag) {
        completionOnJavadocTag(astNode);
      }
    }
    return true;
  }

  /**
   * Ask the engine to compute a completion at the specified position
   * of the given compilation unit.
   *
   *  No return
   *      completion results are answered through a requestor.
   *
   *  @param sourceUnit org.eclipse.jdt.internal.compiler.env.ICompilationUnit
   *      the source of the current compilation unit.
   *
   *  @param completionPosition int
   *      a position in the source where the completion is taking place.
   *      This position is relative to the source provided.
   */
  public void complete(ICompilationUnit sourceUnit, int completionPosition, int pos, ITypeRoot root) {

    if(DEBUG) {
      System.out.print("COMPLETION IN "); //$NON-NLS-1$
      System.out.print(sourceUnit.getFileName());
      System.out.print(" AT POSITION "); //$NON-NLS-1$
      System.out.println(completionPosition);
      System.out.println("COMPLETION - Source :"); //$NON-NLS-1$
      System.out.println(sourceUnit.getContents());
    }
    if (this.monitor != null) this.monitor.beginTask(Messages.engine_completing, IProgressMonitor.UNKNOWN);
    this.requestor.beginReporting();
    boolean contextAccepted = false;
    try {
      this.fileName = sourceUnit.getFileName();
      this.actualCompletionPosition = completionPosition - 1;
      this.offset = pos;
      this.typeRoot = root;
     
      this.checkCancel();
     
      // for now until we can change the UI.
      CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
      CompilationUnitDeclaration parsedUnit = this.parser.dietParse(sourceUnit, result, this.actualCompletionPosition);

      //    boolean completionNodeFound = false;
      if (parsedUnit != null) {
        if(DEBUG) {
          System.out.println("COMPLETION - Diet AST :"); //$NON-NLS-1$
          System.out.println(parsedUnit.toString());
        }

        // scan the package & import statements first
        if (parsedUnit.currentPackage instanceof CompletionOnPackageReference) {
          contextAccepted = true;
          buildContext(parsedUnit.currentPackage, null, parsedUnit, null, null);
          if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
            findPackages((CompletionOnPackageReference) parsedUnit.currentPackage);
          }
          if(this.noProposal && this.problem != null) {
            this.requestor.completionFailure(this.problem);
            if(DEBUG) {
              this.printDebug(this.problem);
            }
          }
          return;
        }

        ImportReference[] imports = parsedUnit.imports;
        if (imports != null) {
          for (int i = 0, length = imports.length; i < length; i++) {
            ImportReference importReference = imports[i];
            if (importReference instanceof CompletionOnImportReference) {
              this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);
              if ((this.unitScope = parsedUnit.scope) != null) {
                contextAccepted = true;
                buildContext(importReference, null, parsedUnit, null, null);

                long positions = importReference.sourcePositions[importReference.tokens.length - 1];
                setSourceAndTokenRange((int) (positions >>> 32), (int) positions);

                char[][] oldTokens = importReference.tokens;
                int tokenCount = oldTokens.length;
                if (tokenCount == 1) {
                  findImports((CompletionOnImportReference)importReference, true);
                } else if(tokenCount > 1){
                  this.insideQualifiedReference = true;

                  char[] lastToken = oldTokens[tokenCount - 1];
                  char[][] qualifierTokens = CharOperation.subarray(oldTokens, 0, tokenCount - 1);

                  Binding binding = this.unitScope.getTypeOrPackage(qualifierTokens);
                  if(binding != null) {
                    if(binding instanceof PackageBinding) {
                      findImports((CompletionOnImportReference)importReference, false);
                    } else {
                      ReferenceBinding ref = (ReferenceBinding) binding;

                      if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
                        findImportsOfMemberTypes(lastToken, ref, importReference.isStatic());
                      }
                      if(importReference.isStatic()) {

                        if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
                          findImportsOfStaticFields(lastToken, ref);
                        }
                        if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) {
                          findImportsOfStaticMethods(lastToken, ref);
                        }
                      }
                    }
                  }
                }

                if(this.noProposal && this.problem != null) {
                  this.requestor.completionFailure(this.problem);
                  if(DEBUG) {
                    this.printDebug(this.problem);
                  }
                }
              }
              return;
            } else if(importReference instanceof CompletionOnKeyword) {
              contextAccepted = true;
              buildContext(importReference, null, parsedUnit, null, null);
              if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
                setSourceAndTokenRange(importReference.sourceStart, importReference.sourceEnd);
                CompletionOnKeyword keyword = (CompletionOnKeyword)importReference;
                findKeywords(keyword.getToken(), keyword.getPossibleKeywords(), false, false);
              }
              if(this.noProposal && this.problem != null) {
                this.requestor.completionFailure(this.problem);
                if(DEBUG) {
                  this.printDebug(this.problem);
                }
              }
              return;
            }
          }
        }

        if (parsedUnit.types != null) {
          try {
            this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/);

            if ((this.unitScope = parsedUnit.scope) != null) {
              this.source = sourceUnit.getContents();
              this.lookupEnvironment.completeTypeBindings(parsedUnit, true);
              parsedUnit.scope.faultInTypes();
              parseBlockStatements(parsedUnit, this.actualCompletionPosition);
              if(DEBUG) {
                System.out.println("COMPLETION - AST :"); //$NON-NLS-1$
                System.out.println(parsedUnit.toString());
              }
              parsedUnit.resolve();
            }
          } catch (CompletionNodeFound e) {
            //          completionNodeFound = true;
            if (e.astNode != null) {
              // if null then we found a problem in the completion node
              if(DEBUG) {
                System.out.print("COMPLETION - Completion node : "); //$NON-NLS-1$
                System.out.println(e.astNode.toString());
                if(this.parser.assistNodeParent != null) {
                  System.out.print("COMPLETION - Parent Node : ")//$NON-NLS-1$
                  System.out.println(this.parser.assistNodeParent);
                }
              }
              this.lookupEnvironment.unitBeingCompleted = parsedUnit; // better resilient to further error reporting
              contextAccepted =
                complete(
                  e.astNode,
                  this.parser.assistNodeParent,
                  this.parser.enclosingNode,
                  parsedUnit,
                  e.qualifiedBinding,
                  e.scope,
                  e.insideTypeAnnotation);
            }
          }
        }
      }

      if(this.noProposal && this.problem != null) {
        if(!contextAccepted) {
          contextAccepted = true;
          InternalCompletionContext context = new InternalCompletionContext();
          context.setOffset(completionPosition - this.offset);
          context.setTokenKind(CompletionContext.TOKEN_KIND_UNKNOWN);
          if (this.requestor.isExtendedContextRequired()) context.setExtended();
          this.requestor.acceptContext(context);
        }
        this.requestor.completionFailure(this.problem);
        if(DEBUG) {
          this.printDebug(this.problem);
        }
      }
      /* Ignore package, import, class & interface keywords for now...
          if (!completionNodeFound) {
            if (parsedUnit == null || parsedUnit.types == null) {
              // this is not good enough... can still be trying to define a second type
              CompletionScanner scanner = (CompletionScanner) this.parser.scanner;
              setSourceRange(scanner.completedIdentifierStart, scanner.completedIdentifierEnd);
              findKeywords(scanner.completionIdentifier, mainDeclarations, null);
            }
            // currently have no way to know if extends/implements are possible keywords
          }
      */
    } catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch (InvalidCursorLocation e) { // may eventually report a usefull error
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch (CompletionNodeFound e){ // internal failure - bugs 5618
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } finally {
      if(!contextAccepted) {
        contextAccepted = true;
        InternalCompletionContext context = new InternalCompletionContext();
        context.setTokenKind(CompletionContext.TOKEN_KIND_UNKNOWN);
        context.setOffset(completionPosition - this.offset);
        if (this.requestor.isExtendedContextRequired()) context.setExtended();
        this.requestor.acceptContext(context);
      }
      this.requestor.endReporting();
      if (this.monitor != null) this.monitor.done();
      reset();
    }
  }

  public void complete(IType type, char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){
    if(this.requestor != null){
      this.requestor.beginReporting();
    }
    boolean contextAccepted = false;
    IType topLevelType = type;
    while(topLevelType.getDeclaringType() != null) {
      topLevelType = topLevelType.getDeclaringType();
    }

    this.fileName = topLevelType.getParent().getElementName().toCharArray();
    CompilationResult compilationResult = new CompilationResult(this.fileName, 1, 1, this.compilerOptions.maxProblemsPerUnit);

    CompilationUnitDeclaration compilationUnit = null;

    try {
      // TypeConverter is used instead of SourceTypeConverter because the type
      // to convert can be a binary type or a source type
      TypeDeclaration typeDeclaration = null;
      if (type instanceof SourceType) {
        SourceType sourceType = (SourceType) type;
        ISourceType info = (ISourceType) sourceType.getElementInfo();
        compilationUnit = SourceTypeConverter.buildCompilationUnit(
          new ISourceType[] {info},//sourceTypes[0] is always toplevel here
          SourceTypeConverter.FIELD_AND_METHOD // need field and methods
          | SourceTypeConverter.MEMBER_TYPE, // need member types
          // no need for field initialization
          this.problemReporter,
          compilationResult);
        if (compilationUnit.types != null)
          typeDeclaration = compilationUnit.types[0];
      } else {
        compilationUnit = new CompilationUnitDeclaration(this.problemReporter, compilationResult, 0);
        typeDeclaration = new BinaryTypeConverter(this.parser.problemReporter(), compilationResult, null/*no need to remember type names*/).buildTypeDeclaration(type, compilationUnit);
      }

      if(typeDeclaration != null) {
        // build AST from snippet
        Initializer fakeInitializer = parseSnippeInitializer(snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);

        // merge AST
        FieldDeclaration[] oldFields = typeDeclaration.fields;
        FieldDeclaration[] newFields = null;
        if (oldFields != null) {
          newFields = new FieldDeclaration[oldFields.length + 1];
          System.arraycopy(oldFields, 0, newFields, 0, oldFields.length);
          newFields[oldFields.length] = fakeInitializer;
        } else {
          newFields = new FieldDeclaration[] {fakeInitializer};
        }
        typeDeclaration.fields = newFields;

        if(DEBUG) {
          System.out.println("SNIPPET COMPLETION AST :"); //$NON-NLS-1$
          System.out.println(compilationUnit.toString());
        }

        if (compilationUnit.types != null) {
          try {
            this.lookupEnvironment.buildTypeBindings(compilationUnit, null /*no access restriction*/);

            if ((this.unitScope = compilationUnit.scope) != null) {
              this.lookupEnvironment.completeTypeBindings(compilationUnit, true);
              compilationUnit.scope.faultInTypes();
              compilationUnit.resolve();
            }
          } catch (CompletionNodeFound e) {
            //          completionNodeFound = true;
            if (e.astNode != null) {
              // if null then we found a problem in the completion node
              contextAccepted =
                complete(
                  e.astNode,
                  this.parser.assistNodeParent,
                  this.parser.enclosingNode,
                  compilationUnit,
                  e.qualifiedBinding,
                  e.scope,
                  e.insideTypeAnnotation);
            }
          }
        }
        if(this.noProposal && this.problem != null) {
          if(!contextAccepted) {
            contextAccepted = true;
            InternalCompletionContext context = new InternalCompletionContext();
            if (this.requestor.isExtendedContextRequired()) context.setExtended();
            this.requestor.acceptContext(context);
          }
          this.requestor.completionFailure(this.problem);
          if(DEBUG) {
            this.printDebug(this.problem);
          }
        }
      }
    }  catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D (added with fix of 99629)
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch (InvalidCursorLocation e) { // may eventually report a usefull error (added to fix 99629)
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object (added with fix of 99629)
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch (CompletionNodeFound e){ // internal failure - bugs 5618 (added with fix of 99629)
      if(DEBUG) {
        System.out.println("Exception caught by CompletionEngine:"); //$NON-NLS-1$
        e.printStackTrace(System.out);
      }
    } catch(JavaModelException e) {
      // Do nothing
    }
    if(!contextAccepted) {
      contextAccepted = true;
      InternalCompletionContext context = new InternalCompletionContext();
      if (this.requestor.isExtendedContextRequired()) context.setExtended();
      this.requestor.acceptContext(context);
    }
    if(this.requestor != null){
      this.requestor.endReporting();
    }
  }
 
  private void completionOnBranchStatementLabel(ASTNode astNode) {
    if (!this.requestor.isIgnored(CompletionProposal.LABEL_REF)) {
      CompletionOnBranchStatementLabel label = (CompletionOnBranchStatementLabel) astNode;
      this.completionToken = label.label;
      findLabels(this.completionToken, label.possibleLabels);
    }
  }
 
  private void completionOnClassLiteralAccess(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
      CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode;
      setSourceAndTokenRange(access.classStart, access.sourceEnd);
      this.completionToken = access.completionIdentifier;
      findClassField(
          this.completionToken,
          (TypeBinding) qualifiedBinding,
          scope,
          null,
          null,
          null,
          false);
    }
  }
 
  private void completionOnExplicitConstructorCall(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
      setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false);
      CompletionOnExplicitConstructorCall constructorCall = (CompletionOnExplicitConstructorCall) astNode;
      TypeBinding[] argTypes = computeTypes(constructorCall.arguments);
      findConstructors(
        (ReferenceBinding) qualifiedBinding,
        argTypes,
        scope,
        constructorCall,
        false,
        null,
        null,
        null,
        false);
    }
  }
 
  private void completionOnFieldName(ASTNode astNode, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
      CompletionOnFieldName field = (CompletionOnFieldName) astNode;

      FieldBinding[] fields = scope.enclosingSourceType().fields();
      char[][] excludeNames = new char[fields.length][];
      for(int i = 0 ; i < fields.length ; i++){
        excludeNames[i] = fields[i].name;
      }

      this.completionToken = field.realName;

     
      int kind =
         (field.modifiers & ClassFileConstants.AccStatic) == 0 ?
            InternalNamingConventions.VK_INSTANCE_FIELD :
              (field.modifiers & ClassFileConstants.AccFinal) == 0 ?
                  InternalNamingConventions.VK_STATIC_FIELD :
                    InternalNamingConventions.VK_STATIC_FINAL_FIELD;
     
      findVariableNames(field.realName, field.type, excludeNames, null, kind);
    }
  }
 
  private void completionOnFieldType(ASTNode astNode, Scope scope) {
    CompletionOnFieldType field = (CompletionOnFieldType) astNode;
    CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) field.type;
    this.completionToken = type.token;
    setSourceAndTokenRange(type.sourceStart, type.sourceEnd);

    findTypesAndPackages(this.completionToken, scope, true, true, new ObjectVector());
    if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
      findKeywordsForMember(this.completionToken, field.modifiers);
    }

    if (!field.isLocalVariable && field.modifiers == ClassFileConstants.AccDefault) {
      SourceTypeBinding enclosingType = scope.enclosingSourceType();
      if (!enclosingType.isAnnotationType()) {
        if (!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) {
          findMethodDeclarations(
              this.completionToken,
              enclosingType,
              scope,
              new ObjectVector(),
              null,
              null,
              null,
              false);
        }
        if (!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) {
          proposeNewMethod(this.completionToken, enclosingType);
        }
      }
    }
  }
  //TODO
  private void completionOnJavadocAllocationExpression(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    // setSourceRange(astNode.sourceStart, astNode.sourceEnd, false);
   
    CompletionOnJavadocAllocationExpression allocExpression = (CompletionOnJavadocAllocationExpression) astNode;
    this.javadocTagPosition = allocExpression.tagSourceStart;
    int rangeStart = astNode.sourceStart;
    if (allocExpression.type.isThis()) {
      if (allocExpression.completeInText()) {
        rangeStart = allocExpression.separatorPosition;
      }
    } else if (allocExpression.completeInText()) {
      rangeStart = allocExpression.type.sourceStart;
    }
    setSourceAndTokenRange(rangeStart, astNode.sourceEnd, false);
    TypeBinding[] argTypes = computeTypes(allocExpression.arguments);

    ReferenceBinding ref = (ReferenceBinding) qualifiedBinding;
    if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF) && ref.isClass()) {
      findConstructors(ref, argTypes, scope, allocExpression, false, null, null, null, false);
    }
  }
  //TODO
  private void completionOnJavadocFieldReference(ASTNode astNode, Scope scope) {
    this.insideQualifiedReference = true;
    CompletionOnJavadocFieldReference fieldRef = (CompletionOnJavadocFieldReference) astNode;
    this.completionToken = fieldRef.token;
    long completionPosition = fieldRef.nameSourcePosition;
    this.javadocTagPosition = fieldRef.tagSourceStart;

    if (fieldRef.actualReceiverType != null && fieldRef.actualReceiverType.isValidBinding()) {
        ReferenceBinding receiverType = (ReferenceBinding) fieldRef.actualReceiverType;
      int rangeStart = (int) (completionPosition >>> 32);
      if (fieldRef.receiver.isThis()) {
        if (fieldRef.completeInText()) {
          rangeStart = fieldRef.separatorPosition;
        }
      } else if (fieldRef.completeInText()) {
        rangeStart = fieldRef.receiver.sourceStart;
      }
      setSourceAndTokenRange(rangeStart, (int) completionPosition);

      if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)
          || !this.requestor.isIgnored(CompletionProposal.JAVADOC_FIELD_REF)) {
        findFields(this.completionToken,
          receiverType,
          scope,
          new ObjectVector(),
          new ObjectVector(),
          false, /*not only static */
          fieldRef,
          scope,
          false,
          true,
          null,
          null,
          null,
          false,
          null,
          -1,
          -1);
      }

      if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)
          || !this.requestor.isIgnored(CompletionProposal.JAVADOC_METHOD_REF)) {
        findMethods(
          this.completionToken,
          null,
          null,
          receiverType,
          scope,
          new ObjectVector(),
          false, /*not only static */
          false,
          fieldRef,
          scope,
          false,
          false,
          true,
          null,
          null,
          null,
          false,
          null,
          -1,
          -1);
        if (fieldRef.actualReceiverType instanceof ReferenceBinding) {
          ReferenceBinding refBinding = (ReferenceBinding)fieldRef.actualReceiverType;
          if (this.completionToken == null
              || CharOperation.prefixEquals(this.completionToken, refBinding.sourceName)
              || (this.options.camelCaseMatch && CharOperation.camelCaseMatch(this.completionToken, refBinding.sourceName))) {
            findConstructors(refBinding, null, scope, fieldRef, false, null, null, null, false);
          }
        }
      }
    }
  }
  //TODO
  private void completionOnJavadocMessageSend(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    CompletionOnJavadocMessageSend messageSend = (CompletionOnJavadocMessageSend) astNode;
    TypeBinding[] argTypes = null; //computeTypes(messageSend.arguments);
    this.completionToken = messageSend.selector;
    this.javadocTagPosition = messageSend.tagSourceStart;

    // Set source range
    int rangeStart = astNode.sourceStart;
    if (messageSend.receiver.isThis()) {
      if (messageSend.completeInText()) {
        rangeStart = messageSend.separatorPosition;
      }
    } else if (messageSend.completeInText()) {
      rangeStart = messageSend.receiver.sourceStart;
    }
    setSourceAndTokenRange(rangeStart, astNode.sourceEnd, false);

    if (qualifiedBinding == null) {
      if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
        findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope, new ObjectVector());
      }
    } else if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
      findMethods(
        this.completionToken,
        null,
        argTypes,
        (ReferenceBinding) ((ReferenceBinding) qualifiedBinding).capture(scope, messageSend.receiver.sourceEnd),
        scope,
        new ObjectVector(),
        false,
        false/* prefix match */,
        messageSend,
        scope,
        false,
        messageSend.receiver instanceof SuperReference,
        true,
        null,
        null,
        null,
        false,
        null,
        -1,
        -1);
    }
  }
  //TODO
  private void completionOnJavadocParamNameReference(ASTNode astNode) {
    if (!this.requestor.isIgnored(CompletionProposal.JAVADOC_PARAM_REF)) {
      CompletionOnJavadocParamNameReference paramRef = (CompletionOnJavadocParamNameReference) astNode;
      setSourceAndTokenRange(paramRef.tagSourceStart, paramRef.tagSourceEnd);
      findJavadocParamNames(paramRef.token, paramRef.missingParams, false);
      findJavadocParamNames(paramRef.token, paramRef.missingTypeParams, true);
    }
  }
  //TODO
  private void completionOnJavadocQualifiedTypeReference(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    this.insideQualifiedReference = true;

    CompletionOnJavadocQualifiedTypeReference typeRef = (CompletionOnJavadocQualifiedTypeReference) astNode;
    this.completionToken = typeRef.completionIdentifier;
    long completionPosition = typeRef.sourcePositions[typeRef.tokens.length];
    this.javadocTagPosition = typeRef.tagSourceStart;

    // get the source positions of the completion identifier
    if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) {
      if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF) ||
          ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF))) {
        int rangeStart = typeRef.completeInText() ? typeRef.sourceStart : (int) (completionPosition >>> 32);
        setSourceAndTokenRange(rangeStart, (int) completionPosition);
        findMemberTypes(
          this.completionToken,
          (ReferenceBinding) qualifiedBinding,
          scope,
          scope.enclosingSourceType(),
          false,
          false,
          new ObjectVector(),
          null,
          null,
          null,
          false);
      }
    } else if (qualifiedBinding instanceof PackageBinding) {

      setSourceRange(astNode.sourceStart, (int) completionPosition);
      int rangeStart = typeRef.completeInText() ? typeRef.sourceStart : (int) (completionPosition >>> 32);
      setTokenRange(rangeStart, (int) completionPosition);
      // replace to the end of the completion identifier
      findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
    }
  }
  //TODO
  private void completionOnJavadocSingleTypeReference(ASTNode astNode, Scope scope) {
    CompletionOnJavadocSingleTypeReference typeRef = (CompletionOnJavadocSingleTypeReference) astNode;
    this.completionToken = typeRef.token;
    this.javadocTagPosition = typeRef.tagSourceStart;
    setSourceAndTokenRange(typeRef.sourceStart, typeRef.sourceEnd);
    findTypesAndPackages(
        this.completionToken,
        scope,
        (this.assistNodeInJavadoc & CompletionOnJavadoc.BASE_TYPES) != 0,
        false,
        new ObjectVector());
  }
  //TODO
  private void completionOnJavadocTag(ASTNode astNode) {
    CompletionOnJavadocTag javadocTag = (CompletionOnJavadocTag) astNode;
    setSourceAndTokenRange(javadocTag.tagSourceStart, javadocTag.sourceEnd);
    findJavadocBlockTags(javadocTag);
    findJavadocInlineTags(javadocTag);
  }
  //TODO
  private void completionOnJavadocTypeParamReference(ASTNode astNode) {
    if (!this.requestor.isIgnored(CompletionProposal.JAVADOC_PARAM_REF)) {
      CompletionOnJavadocTypeParamReference paramRef = (CompletionOnJavadocTypeParamReference) astNode;
      setSourceAndTokenRange(paramRef.tagSourceStart, paramRef.tagSourceEnd);
      findJavadocParamNames(paramRef.token, paramRef.missingParams, true);
    }
  }
 
  private void completionOnKeyword(ASTNode astNode) {
    if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
      CompletionOnKeyword keyword = (CompletionOnKeyword)astNode;
      findKeywords(keyword.getToken(), keyword.getPossibleKeywords(), keyword.canCompleteEmptyToken(), false);
    }
  }
 
  private void completionOnLocalOrArgumentName(ASTNode astNode, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
      LocalDeclaration variable = (LocalDeclaration) astNode;

      int kind;
      if (variable instanceof CompletionOnLocalName){
        this.completionToken = ((CompletionOnLocalName) variable).realName;
        kind = InternalNamingConventions.VK_LOCAL;
      } else {
        CompletionOnArgumentName arg = (CompletionOnArgumentName) variable;
        this.completionToken = arg.realName;
        kind = arg.isCatchArgument ? InternalNamingConventions.VK_LOCAL : InternalNamingConventions.VK_PARAMETER;
      }

      char[][] alreadyDefinedName = computeAlreadyDefinedName((BlockScope)scope, variable);

      char[][] forbiddenNames = findVariableFromUnresolvedReference(variable, (BlockScope)scope, alreadyDefinedName);

      LocalVariableBinding[] locals = ((BlockScope)scope).locals;
      char[][] discouragedNames = new char[locals.length][];
      int localCount = 0;
      for(int i = 0 ; i < locals.length ; i++){
        if (locals[i] != null) {
          discouragedNames[localCount++] = locals[i].name;
        }
      }

      System.arraycopy(discouragedNames, 0, discouragedNames = new char[localCount][], 0, localCount);

      findVariableNames(this.completionToken, variable.type, discouragedNames, forbiddenNames, kind);
    }
  }
 
  private void completionOnMarkerAnnotationName(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    CompletionOnMarkerAnnotationName annot = (CompletionOnMarkerAnnotationName) astNode;

    CompletionOnAnnotationOfType fakeType = (CompletionOnAnnotationOfType)scope.parent.referenceContext();
    if (fakeType.annotations[0] == annot) {
      // When the completion is inside a method body the annotation cannot be accuratly attached to the correct node by completion recovery.
      // So 'targetedElement' is not computed in this case.
      if (scope.parent.parent == null || !(scope.parent.parent instanceof MethodScope)) {
        this.targetedElement = computeTargetedElement(fakeType);
      }

    }

    this.assistNodeIsAnnotation = true;
    if (annot.type instanceof CompletionOnSingleTypeReference) {
      CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) annot.type;
      this.completionToken = type.token;
      setSourceAndTokenRange(type.sourceStart, type.sourceEnd);

      if (scope.parent.parent != null &&
          !(scope.parent.parent instanceof MethodScope) &&
          !fakeType.isParameter) {

        if (this.completionToken.length <= Keywords.INTERFACE.length
          && CharOperation.prefixEquals(this.completionToken, Keywords.INTERFACE, false /* ignore case */
        )){
          int relevance = computeBaseRelevance();
          relevance += computeRelevanceForResolution();
          relevance += computeRelevanceForInterestingProposal();
          relevance += computeRelevanceForCaseMatching(this.completionToken, Keywords.INTERFACE);
          relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywords
          relevance += R_ANNOTATION; // this proposal is most relevant than annotation proposals

          this.noProposal = false;
          if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
            CompletionProposal proposal = createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition);
            proposal.setName(Keywords.INTERFACE);
            proposal.setCompletion(Keywords.INTERFACE);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
      }

      findTypesAndPackages(this.completionToken, scope, false, false, new ObjectVector());
    } else if (annot.type instanceof CompletionOnQualifiedTypeReference) {
      this.insideQualifiedReference = true;

      CompletionOnQualifiedTypeReference type = (CompletionOnQualifiedTypeReference) annot.type;
      this.completionToken = type.completionIdentifier;
      long completionPosition = type.sourcePositions[type.tokens.length];
      if (qualifiedBinding instanceof PackageBinding) {

        setSourceRange(astNode.sourceStart, (int) completionPosition);
        setTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
        // replace to the end of the completion identifier
        findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
      } else {
        setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);

        findMemberTypes(
          this.completionToken,
          (ReferenceBinding) qualifiedBinding,
          scope,
          scope.enclosingSourceType(),
          false,
          false,
          new ObjectVector(),
          null,
          null,
          null,
          false);
      }
    }
  }
 
  private void completionOnMemberAccess(ASTNode astNode, ASTNode enclosingNode, Binding qualifiedBinding,
      Scope scope, boolean insideTypeAnnotation) {
    this.insideQualifiedReference = true;
    CompletionOnMemberAccess access = (CompletionOnMemberAccess) astNode;
    long completionPosition = access.nameSourcePosition;
    setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);

    this.completionToken = access.token;

    if (qualifiedBinding.problemId() == ProblemReasons.NotFound) {
      // complete method members with missing return type
      // class X {
      //   Missing f() {return null;}
      //   void foo() {
      //     f().|
      //   }
      // }
      if (this.assistNodeInJavadoc == 0 &&
          (this.requestor.isAllowingRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF) ||
              this.requestor.isAllowingRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF))) {
        ProblemMethodBinding problemMethodBinding = (ProblemMethodBinding) qualifiedBinding;
        findFieldsAndMethodsFromMissingReturnType(
            problemMethodBinding.selector,
            problemMethodBinding.parameters,
            scope,
            access,
            insideTypeAnnotation);
      }
    } else {
      if (!access.isInsideAnnotation) {
        if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
          findKeywords(this.completionToken, new char[][]{Keywords.NEW}, false, false);
        }

        ObjectVector fieldsFound = new ObjectVector();
        ObjectVector methodsFound = new ObjectVector();

        boolean superCall = access.receiver instanceof SuperReference;

        findFieldsAndMethods(
          this.completionToken,
          ((TypeBinding) qualifiedBinding).capture(scope, access.receiver.sourceEnd),
          scope,
          fieldsFound,
          methodsFound,
          access,
          scope,
          false,
          superCall,
          null,
          null,
          null,
          false,
          null,
          -1,
          -1);

        if (!superCall) {
         
          checkCancel();
         
          findFieldsAndMethodsFromCastedReceiver(
              enclosingNode,
              qualifiedBinding,
              scope,
              fieldsFound,
              methodsFound,
              access,
              scope,
              access.receiver);
        }
      }
    }
  }
 
  private void completionOnMemberValueName(ASTNode astNode, ASTNode astNodeParent, Scope scope,
      boolean insideTypeAnnotation) {
    CompletionOnMemberValueName memberValuePair = (CompletionOnMemberValueName) astNode;
    Annotation annotation = (Annotation) astNodeParent;

    this.completionToken = memberValuePair.name;

    ReferenceBinding annotationType = (ReferenceBinding)annotation.resolvedType;

    if (annotationType != null && annotationType.isAnnotationType()) {
      if (!this.requestor.isIgnored(CompletionProposal.ANNOTATION_ATTRIBUTE_REF)) {
        findAnnotationAttributes(this.completionToken, annotation.memberValuePairs(), annotationType);
      }
      if (this.assistNodeCanBeSingleMemberAnnotation) {
        if (this.expectedTypesPtr > -1 && this.expectedTypes[0].isAnnotationType()) {
          findTypesAndPackages(this.completionToken, scope, false, false, new ObjectVector());
        } else {
          if (this.expectedTypesPtr > -1) {
            this.assistNodeIsEnum = true;
            done : for (int i = 0; i <= this.expectedTypesPtr; i++) {
              if (!this.expectedTypes[i].isEnum()) {
                this.assistNodeIsEnum = false;
                break done;
              }
            }

          }
          if (scope instanceof BlockScope && !this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) {
            char[][] alreadyDefinedName = computeAlreadyDefinedName((BlockScope)scope, FakeInvocationSite);

            findUnresolvedReference(
                memberValuePair.sourceStart,
                memberValuePair.sourceEnd,
                (BlockScope)scope,
                alreadyDefinedName);
          }
          findVariablesAndMethods(
            this.completionToken,
            scope,
            FakeInvocationSite,
            scope,
            insideTypeAnnotation,
            true);
          // can be the start of a qualified type name
          findTypesAndPackages(this.completionToken, scope, false, false, new ObjectVector());
        }
      }
    }
  }
 
  private void completionOnMessageSend(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false);

    CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode;
    TypeBinding[] argTypes = computeTypes(messageSend.arguments);
    this.completionToken = messageSend.selector;
    if (qualifiedBinding == null) {
      if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
        ObjectVector methodsFound = new ObjectVector();

        findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope, methodsFound);
       
        checkCancel();
       
        findLocalMethodsFromStaticImports(
            this.completionToken,
            scope,
            messageSend,
            scope,
            true,
            methodsFound,
            true);
      }
    } else  if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
      findMethods(
        this.completionToken,
        null,
        argTypes,
        (ReferenceBinding)((ReferenceBinding) qualifiedBinding).capture(scope, messageSend.receiver.sourceEnd),
        scope,
        new ObjectVector(),
        false,
        true,
        messageSend,
        scope,
        false,
        messageSend.receiver instanceof SuperReference,
        false,
        null,
        null,
        null,
        false,
        null,
        -1,
        -1);
    }
  }
 
  private void completionOnMessageSendName(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
      CompletionOnMessageSendName messageSend = (CompletionOnMessageSendName) astNode;

      this.insideQualifiedReference = true;
      this.completionToken = messageSend.selector;
      boolean onlyStatic = false;
      if (messageSend.receiver instanceof NameReference) {
        onlyStatic = ((NameReference)messageSend.receiver).isTypeReference();
      } else if (!(messageSend.receiver instanceof MessageSend) &&
          !(messageSend.receiver instanceof FieldReference) &&
          !(messageSend.receiver.isThis())) {
        onlyStatic = true;
      }

      TypeBinding receiverType = (TypeBinding)qualifiedBinding;

      if(receiverType != null && receiverType instanceof ReferenceBinding) {
        TypeBinding[] typeArgTypes = computeTypesIfCorrect(messageSend.typeArguments);
        if(typeArgTypes != null) {
          findMethods(
              this.completionToken,
              typeArgTypes,
              null,
              (ReferenceBinding)receiverType.capture(scope, messageSend.receiver.sourceEnd),
              scope,
              new ObjectVector(),
              onlyStatic,
              false,
              messageSend,
              scope,
              false,
              false,
              false,
              null,
              null,
              null,
              false,
              null,
              -1,
              -1);
        }
      }
    }
  }
 
  private void completionOnMethodName(ASTNode astNode, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
      CompletionOnMethodName method = (CompletionOnMethodName) astNode;

      setSourceAndTokenRange(method.sourceStart, method.selectorEnd);

      FieldBinding[] fields = scope.enclosingSourceType().fields();
      char[][] excludeNames = new char[fields.length][];
      for(int i = 0 ; i < fields.length ; i++){
        excludeNames[i] = fields[i].name;
      }

      this.completionToken = method.selector;

     
      int kind =
         (method.modifiers & ClassFileConstants.AccStatic) == 0 ?
            InternalNamingConventions.VK_INSTANCE_FIELD :
              (method.modifiers & ClassFileConstants.AccFinal) == 0 ?
                  InternalNamingConventions.VK_STATIC_FIELD :
                    InternalNamingConventions.VK_STATIC_FINAL_FIELD;
           
      findVariableNames(this.completionToken, method.returnType, excludeNames, null, kind);
    }
  }
 
  private void completionOnMethodReturnType(ASTNode astNode, Scope scope) {
    CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode;
    SingleTypeReference type = (CompletionOnSingleTypeReference) method.returnType;
    this.completionToken = type.token;
    setSourceAndTokenRange(type.sourceStart, type.sourceEnd);
    findTypesAndPackages(this.completionToken, scope.parent, true, true, new ObjectVector());
    if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
      findKeywordsForMember(this.completionToken, method.modifiers);
    }

    if (method.modifiers == ClassFileConstants.AccDefault) {
      SourceTypeBinding enclosingType = scope.enclosingSourceType();
      if (!enclosingType.isAnnotationType()) {
        if (!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) {
          findMethodDeclarations(
              this.completionToken,
              scope.enclosingSourceType(),
              scope,
              new ObjectVector(),
              null,
              null,
              null,
              false);
        }
        if (!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) {
          proposeNewMethod(this.completionToken, scope.enclosingSourceType());
        }
      }
    }
  }
 
  private void completionOnParameterizedQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
    if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      CompletionOnParameterizedQualifiedTypeReference ref = (CompletionOnParameterizedQualifiedTypeReference) astNode;

      this.insideQualifiedReference = true;

      this.assistNodeIsClass = ref.isClass();
      this.assistNodeIsException = ref.isException();
      this.assistNodeIsInterface = ref.isInterface();
      this.assistNodeIsSuperType = ref.isSuperType();
      this.assistNodeIsExtendedType = assistNodeIsExtendedType(astNode, astNodeParent);
      this.assistNodeIsInterfaceExcludingAnnotation = assistNodeIsInterfaceExcludingAnnotation(astNode, astNodeParent);

      this.completionToken = ref.completionIdentifier;
      long completionPosition = ref.sourcePositions[ref.tokens.length];
      setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);

      if (qualifiedBinding.problemId() == ProblemReasons.NotFound ||
          (((ReferenceBinding)qualifiedBinding).tagBits & TagBits.HasMissingType) != 0) {
        if (this.assistNodeInJavadoc == 0 &&
            (this.requestor.isAllowingRequiredProposals(CompletionProposal.TYPE_REF, CompletionProposal.TYPE_REF))) {
          if(ref.tokens.length == 1) {
            findMemberTypesFromMissingType(
                ref,
                ref.sourcePositions[0],
                scope);
          }
        }
      } else {
        ObjectVector typesFound = new ObjectVector();
        if (this.assistNodeIsException && astNodeParent instanceof TryStatement) {
          findExceptionFromTryStatement(
              this.completionToken,
              (ReferenceBinding)qualifiedBinding,
              scope.enclosingSourceType(),
              (BlockScope)scope,
              typesFound);
        }
       
        checkCancel();
       
        findMemberTypes(
          this.completionToken,
          (ReferenceBinding) qualifiedBinding,
          scope,
          scope.enclosingSourceType(),
          false,
          false,
          typesFound,
          null,
          null,
          null,
          false);
      }
    }
  }

  private boolean assistNodeIsExtendedType(ASTNode astNode, ASTNode astNodeParent) {
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=99399, don't propose final types for extension.
    if (astNodeParent == null)
      return false;
    if (astNodeParent instanceof TypeDeclaration) {
      TypeDeclaration typeDeclaration = (TypeDeclaration) astNodeParent;
      return (typeDeclaration.superclass == astNode)
    } else if (astNodeParent instanceof TypeParameter) {
      TypeParameter typeParameter = (TypeParameter) astNodeParent;
      return (typeParameter.type == astNode);
    } else if (astNodeParent instanceof Wildcard) {
      Wildcard wildcard = (Wildcard) astNodeParent;
      return (wildcard.bound == astNode && wildcard.kind == Wildcard.EXTENDS);
    }
    return false;
  }
 
  private boolean assistNodeIsInterfaceExcludingAnnotation(ASTNode astNode, ASTNode astNodeParent) {
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310423, don't propose annotations for implements.
    if (astNodeParent == null)
      return false;
    if (astNodeParent instanceof TypeDeclaration) {
      TypeDeclaration typeDeclaration = (TypeDeclaration) astNodeParent;
      TypeReference [] superInterfaces = typeDeclaration.superInterfaces;
      int length = superInterfaces == null ? 0 : superInterfaces.length;
      for (int i = 0; i < length; i++) {
        if (superInterfaces[i] == astNode)
          return true;
      }
    }
    return false;
  }
 
  private boolean assistNodeIsInsideCase(ASTNode astNode, ASTNode astNodeParent) {
    // To find whether we're completing inside the case expression in a
    // switch case construct (https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346)
    if (astNodeParent instanceof SwitchStatement) {
      CaseStatement[] cases = ((SwitchStatement) astNodeParent).cases;
      for (int i = 0, caseCount = ((SwitchStatement) astNodeParent).caseCount; i < caseCount; i++) {
        CompletionNodeDetector detector = new CompletionNodeDetector(astNode, cases[i]);
        if (detector.containsCompletionNode()) {
          return true;
        }
      }
    }
    return false;
  }

  private void completionOnQualifiedAllocationExpression(ASTNode astNode, Binding qualifiedBinding, Scope scope) {
    setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false);

    CompletionOnQualifiedAllocationExpression allocExpression =
      (CompletionOnQualifiedAllocationExpression) astNode;
    TypeBinding[] argTypes = computeTypes(allocExpression.arguments);

    ReferenceBinding ref = (ReferenceBinding) qualifiedBinding;
   
    if (ref.problemId() == ProblemReasons.NotFound) {
      findConstructorsFromMissingType(
          allocExpression.type,
          argTypes,
          scope,
          allocExpression);
    } else {
      if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)
          && ref.isClass()
          && !ref.isAbstract()) {
          findConstructors(
            ref,
            argTypes,
            scope,
            allocExpression,
            false,
            null,
            null,
            null,
            false);
      }
     
      checkCancel();
     
      if (!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)
          && !ref.isFinal()
          && !ref.isEnum()){
        findAnonymousType(
          ref,
          argTypes,
          scope,
          allocExpression,
          null,
          null,
          null,
          false);
      }
    }
  }
 
  private void completionOnQualifiedNameReference(ASTNode astNode, ASTNode enclosingNode, Binding qualifiedBinding,
      Scope scope, boolean insideTypeAnnotation) {
    this.insideQualifiedReference = true;
    CompletionOnQualifiedNameReference ref =
      (CompletionOnQualifiedNameReference) astNode;
    this.completionToken = ref.completionIdentifier;
    long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1];
   
    if (qualifiedBinding.problemId() == ProblemReasons.NotFound) {
      setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
      // complete field members with missing fields type
      // class X {
      //   Missing f;
      //   void foo() {
      //     f.|
      //   }
      // }
      if (this.assistNodeInJavadoc == 0 &&
          (this.requestor.isAllowingRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF) ||
              this.requestor.isAllowingRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF) ||
              this.requestor.isAllowingRequiredProposals(CompletionProposal.TYPE_REF, CompletionProposal.TYPE_REF))) {
        if(ref.tokens.length == 1) {
          boolean foundSomeFields = findFieldsAndMethodsFromMissingFieldType(ref.tokens[0], scope, ref, insideTypeAnnotation);

          if (!foundSomeFields) {
           
            checkCancel();
           
            findMembersFromMissingType(
                ref.tokens[0],
                ref.sourcePositions[0],
                null,
                scope,
                ref,
                ref.isInsideAnnotationAttribute);
          }
        }
      }
    } else if (qualifiedBinding instanceof VariableBinding) {
      setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
      TypeBinding receiverType = ((VariableBinding) qualifiedBinding).type;
      if (receiverType != null && (receiverType.tagBits & TagBits.HasMissingType) == 0) {
        ObjectVector fieldsFound = new ObjectVector();
        ObjectVector methodsFound = new ObjectVector();

        findFieldsAndMethods(
            this.completionToken,
            receiverType.capture(scope, ref.sourceEnd),
            scope,
            fieldsFound,
            methodsFound,
            ref,
            scope,
            false,
            false,
            null,
            null,
            null,
            false,
            null,
            -1,
            -1);
       
        checkCancel();

        findFieldsAndMethodsFromCastedReceiver(
            enclosingNode,
            qualifiedBinding,
            scope,
            fieldsFound,
            methodsFound,
            ref,
            scope,
            ref);

      } else if (this.assistNodeInJavadoc == 0 &&
          (this.requestor.isAllowingRequiredProposals(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_REF) ||
              this.requestor.isAllowingRequiredProposals(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_REF))) {
        boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF);
        boolean proposeMethod = !this.requestor.isIgnored(CompletionProposal.METHOD_REF);
        if (proposeField || proposeMethod) {
          if(ref.tokens.length == 1) {
            if (qualifiedBinding instanceof LocalVariableBinding) {
              // complete local variable members with missing variables type
              // class X {
              //   void foo() {
              //     Missing f;
              //     f.|
              //   }
              // }
              LocalVariableBinding localVariableBinding = (LocalVariableBinding) qualifiedBinding;
              findFieldsAndMethodsFromMissingType(
                  localVariableBinding.declaration.type,
                  localVariableBinding.declaringScope,
                  ref,
                  scope);
            } else {
              // complete field members with missing fields type
              // class X {
              //   Missing f;
              //   void foo() {
              //     f.|
              //   }
              // }
              findFieldsAndMethodsFromMissingFieldType(ref.tokens[0], scope, ref, insideTypeAnnotation);
            }

          }
        }
      }

    } else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) {
      boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute;
      ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
      setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);

      findMembers(
          this.completionToken,
          receiverType,
          scope,
          ref,
          isInsideAnnotationAttribute,
          null,
          null,
          null,
          false);

    } else if (qualifiedBinding instanceof PackageBinding) {

      setSourceRange(astNode.sourceStart, (int) completionPosition);
      setTokenRange((int) (completionPosition >>> 32), (int) completionPosition);

      // replace to the end of the completion identifier
      findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
    }
  }
 
  private void completionOnQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding,
      Scope scope) {
    this.insideQualifiedReference = true;

    CompletionOnQualifiedTypeReference ref =
      (CompletionOnQualifiedTypeReference) astNode;

    this.assistNodeIsClass = ref.isClass();
    this.assistNodeIsException = ref.isException();
    this.assistNodeIsInterface = ref.isInterface();
    this.assistNodeIsConstructor = ref.isConstructorType;
    this.assistNodeIsSuperType = ref.isSuperType();
    this.assistNodeIsExtendedType = assistNodeIsExtendedType(astNode, astNodeParent);
    this.assistNodeIsInterfaceExcludingAnnotation = assistNodeIsInterfaceExcludingAnnotation(astNode, astNodeParent);
   
    this.completionToken = ref.completionIdentifier;
    long completionPosition = ref.sourcePositions[ref.tokens.length];

    // get the source positions of the completion identifier
    if (qualifiedBinding.problemId() == ProblemReasons.NotFound) {
      setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
      if (this.assistNodeInJavadoc == 0 &&
          (this.requestor.isAllowingRequiredProposals(CompletionProposal.TYPE_REF, CompletionProposal.TYPE_REF))) {
        if(ref.tokens.length == 1) {
          findMemberTypesFromMissingType(
              ref.tokens[0],
              ref.sourcePositions[0],
              scope);
        }
      }
    } else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) {
      if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
        setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition);

        ObjectVector typesFound = new ObjectVector();

        if (this.assistNodeIsException && astNodeParent instanceof TryStatement) {
          findExceptionFromTryStatement(
              this.completionToken,
              (ReferenceBinding)qualifiedBinding,
              scope.enclosingSourceType(),
              (BlockScope)scope,
              typesFound);
        }
       
        checkCancel();

        findMemberTypes(
          this.completionToken,
          (ReferenceBinding) qualifiedBinding,
          scope,
          scope.enclosingSourceType(),
          false,
          false,
          typesFound,
          null,
          null,
          null,
          false);
      }
    } else if (qualifiedBinding instanceof PackageBinding) {

      setSourceRange(astNode.sourceStart, (int) completionPosition);
      setTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
      // replace to the end of the completion identifier
      findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope);
    }
  }
 
  private void completionOnSingleNameReference(ASTNode astNode, ASTNode astNodeParent, Scope scope,
      boolean insideTypeAnnotation) {
    CompletionOnSingleNameReference singleNameReference = (CompletionOnSingleNameReference) astNode;
    this.completionToken = singleNameReference.token;
    SwitchStatement switchStatement = astNodeParent instanceof SwitchStatement ? (SwitchStatement) astNodeParent : null;
    if (switchStatement != null
        && switchStatement.expression.resolvedType != null
        && switchStatement.expression.resolvedType.isEnum()) {
      if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
        this.assistNodeIsEnum = true;
        findEnumConstantsFromSwithStatement(this.completionToken, (SwitchStatement) astNodeParent);
      }
    } else if (this.expectedTypesPtr > -1 && this.expectedTypes[0].isAnnotationType()) {
      findTypesAndPackages(this.completionToken, scope, false, false, new ObjectVector());
    } else {
      if (this.expectedTypesPtr > -1) {
        this.assistNodeIsEnum = true;
        done : for (int i = 0; i <= this.expectedTypesPtr; i++) {
          if (!this.expectedTypes[i].isEnum()) {
            this.assistNodeIsEnum = false;
            break done;
          }
        }

      }
      if (scope instanceof BlockScope && !this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) {
        char[][] alreadyDefinedName = computeAlreadyDefinedName((BlockScope)scope, singleNameReference);

        findUnresolvedReference(
            singleNameReference.sourceStart,
            singleNameReference.sourceEnd,
            (BlockScope)scope,
            alreadyDefinedName);
      }
     
      checkCancel();
     
      findVariablesAndMethods(
        this.completionToken,
        scope,
        singleNameReference,
        scope,
        insideTypeAnnotation,
        singleNameReference.isInsideAnnotationAttribute);
     
      checkCancel();
     
      // can be the start of a qualified type name
      findTypesAndPackages(this.completionToken, scope, true, false, new ObjectVector());
      if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
        if (this.completionToken != null && this.completionToken.length != 0) {
          findKeywords(this.completionToken, singleNameReference.possibleKeywords, false, false);
        } else {
          findTrueOrFalseKeywords(singleNameReference.possibleKeywords);
        }
      }
      if (singleNameReference.canBeExplicitConstructor && !this.requestor.isIgnored(CompletionProposal.METHOD_REF)){
        if (CharOperation.prefixEquals(this.completionToken, Keywords.THIS, false)) {
          ReferenceBinding ref = scope.enclosingSourceType();
          findExplicitConstructors(Keywords.THIS, ref, (MethodScope)scope, singleNameReference);
        } else if (CharOperation.prefixEquals(this.completionToken, Keywords.SUPER, false)) {
          ReferenceBinding ref = scope.enclosingSourceType();
          findExplicitConstructors(Keywords.SUPER, ref.superclass(), (MethodScope)scope, singleNameReference);
        }
      }
    }
  }
 
  private void completionOnSingleTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) {
    CompletionOnSingleTypeReference singleRef = (CompletionOnSingleTypeReference) astNode;

    this.completionToken = singleRef.token;

    this.assistNodeIsClass = singleRef.isClass();
    this.assistNodeIsException = singleRef.isException();
    this.assistNodeIsInterface = singleRef.isInterface();
    this.assistNodeIsConstructor = singleRef.isConstructorType;
    this.assistNodeIsSuperType = singleRef.isSuperType();
    this.assistNodeIsExtendedType = assistNodeIsExtendedType(astNode, astNodeParent);
    this.assistNodeIsInterfaceExcludingAnnotation = assistNodeIsInterfaceExcludingAnnotation(astNode, astNodeParent);
   
    // can be the start of a qualified type name
    if (qualifiedBinding == null) {
      if (this.completionToken.length == 0 &&
          (astNodeParent instanceof ParameterizedSingleTypeReference ||
              astNodeParent instanceof ParameterizedQualifiedTypeReference)) {
        this.setSourceAndTokenRange(astNode.sourceStart, astNode.sourceStart - 1, false);

        findParameterizedType((TypeReference)astNodeParent, scope);
      } else {
        ObjectVector typesFound = new ObjectVector();
        if (this.assistNodeIsException && astNodeParent instanceof TryStatement) {
          findExceptionFromTryStatement(
              this.completionToken,
              null,
              scope.enclosingSourceType(),
              (BlockScope)scope,
              typesFound);
        }
       
        checkCancel();
       
        findTypesAndPackages(this.completionToken, scope, this.assistNodeIsConstructor, false, typesFound);
      }
    } else if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      findMemberTypes(
        this.completionToken,
        (ReferenceBinding) qualifiedBinding,
        scope,
        scope.enclosingSourceType(),
        false,
        false,
        false,
        false,
        !this.assistNodeIsConstructor,
        null,
        new ObjectVector(),
        null,
        null,
        null,
        false);
    }
  }

  private char[][] computeAlreadyDefinedName(
      BlockScope scope,
      InvocationSite invocationSite) {
    ArrayList result = new ArrayList();

    boolean staticsOnly = false;

    Scope currentScope = scope;

    done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found

      switch (currentScope.kind) {

        case Scope.METHOD_SCOPE :
          // handle the error case inside an explicit constructor call (see MethodScope>>findField)
          MethodScope methodScope = (MethodScope) currentScope;
          staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;

        //$FALL-THROUGH$
        case Scope.BLOCK_SCOPE :
          BlockScope blockScope = (BlockScope) currentScope;

          next : for (int i = 0, length = blockScope.locals.length; i < length; i++) {
            LocalVariableBinding local = blockScope.locals[i];

            if (local == null)
              break next;

            if (local.isSecret())
              continue next;

            result.add(local.name);
          }
          break;

        case Scope.CLASS_SCOPE :
          ClassScope classScope = (ClassScope) currentScope;
          SourceTypeBinding enclosingType = classScope.referenceContext.binding;
          computeAlreadyDefinedName(
              enclosingType,
              classScope,
              staticsOnly,
              invocationSite,
              result);
          staticsOnly |= enclosingType.isStatic();
          break;

        case Scope.COMPILATION_UNIT_SCOPE :
          break done1;
      }
      currentScope = currentScope.parent;
    }

    if (result.size() == 0) return CharOperation.NO_CHAR_CHAR;

    return (char[][])result.toArray(new char[result.size()][]);
  }

  private void computeAlreadyDefinedName(
      FieldBinding[] fields,
      Scope scope,
      boolean onlyStaticFields,
      ReferenceBinding receiverType,
      InvocationSite invocationSite,
      ArrayList result) {

    next : for (int f = fields.length; --f >= 0;) {
      FieldBinding field = fields[f];

      if (field.isSynthetic()) continue next;

      if (onlyStaticFields && !field.isStatic()) continue next;

      if (!field.canBeSeenBy(receiverType, invocationSite, scope)) continue next;

      result.add(field.name);
    }
  }

  private void computeAlreadyDefinedName(
      SourceTypeBinding receiverType,
      ClassScope scope,
      boolean onlyStaticFields,
      InvocationSite invocationSite,
      ArrayList result) {

    ReferenceBinding currentType = receiverType;
    ReferenceBinding[] interfacesToVisit = null;
    int nextPosition = 0;
    do {
      ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
      if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
        if (interfacesToVisit == null) {
          interfacesToVisit = itsInterfaces;
          nextPosition = interfacesToVisit.length;
        } else {
          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;
          }
        }
      }

      FieldBinding[] fields = currentType.availableFields();
      if(fields != null && fields.length > 0) {
        computeAlreadyDefinedName(
          fields,
          scope,
          onlyStaticFields,
          receiverType,
          invocationSite,
          result);
      }
      currentType = currentType.superclass();
    } while ( currentType != null);

    if (interfacesToVisit != null) {
      for (int i = 0; i < nextPosition; i++) {
        ReferenceBinding anInterface = interfacesToVisit[i];
        FieldBinding[] fields = anInterface.availableFields();
        if(fields !=  null) {
          computeAlreadyDefinedName(
            fields,
            scope,
            onlyStaticFields,
            receiverType,
            invocationSite,
            result);
        }

        ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
        if (itsInterfaces != 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;
          }
        }
      }
    }
  }

  int computeBaseRelevance(){
    return R_DEFAULT;
  }

  private void computeExpectedTypes(ASTNode parent, ASTNode node, Scope scope){

    // default filter
    this.expectedTypesFilter = SUBTYPE;
    this.hasJavaLangObjectAsExpectedType = false;

    // find types from parent
    if(parent instanceof AbstractVariableDeclaration && !(parent instanceof TypeParameter)) {
      AbstractVariableDeclaration variable = (AbstractVariableDeclaration)parent;
      TypeBinding binding = variable.type.resolvedType;
      if(binding != null) {
        if(!(variable.initialization instanceof ArrayInitializer)) {
          addExpectedType(binding, scope);
        } else { // https://bugs.eclipse.org/bugs/show_bug.cgi?id=310747
          // If the variable is of type X[], and we're in the initializer
          // we should have X as the expected type for the variable initializers.
          binding = binding.leafComponentType();
          addExpectedType(binding, scope);
        }
      }
    } else if(parent instanceof Assignment) {
      TypeBinding binding = ((Assignment)parent).lhs.resolvedType;
      if(binding != null) {
        addExpectedType(binding, scope);
      }
    } else if(parent instanceof ReturnStatement) {
      if(scope.methodScope().referenceContext instanceof AbstractMethodDeclaration) {
        MethodBinding methodBinding = ((AbstractMethodDeclaration) scope.methodScope().referenceContext).binding;
        TypeBinding binding = methodBinding  == null ? null : methodBinding.returnType;
        if(binding != null) {
          addExpectedType(binding, scope);
        }
      }
    } else if(parent instanceof CastExpression) {
      TypeReference e = ((CastExpression)parent).type;
      TypeBinding binding = e.resolvedType;
      if(binding != null){
        addExpectedType(binding, scope);
        this.expectedTypesFilter = SUBTYPE | SUPERTYPE;
      }
    } else if(parent instanceof MessageSend) {
      MessageSend messageSend = (MessageSend) parent;

      if(messageSend.actualReceiverType instanceof ReferenceBinding) {
        ReferenceBinding binding = (ReferenceBinding)messageSend.actualReceiverType;
        boolean isStatic = messageSend.receiver.isTypeReference();

        while(binding != null) {
          computeExpectedTypesForMessageSend(
            binding,
            messageSend.selector,
            messageSend.arguments,
            (ReferenceBinding)messageSend.actualReceiverType,
            scope,
            messageSend,
            isStatic);
          computeExpectedTypesForMessageSendForInterface(
            binding,
            messageSend.selector,
            messageSend.arguments,
            (ReferenceBinding)messageSend.actualReceiverType,
            scope,
            messageSend,
            isStatic);
          binding = binding.superclass();
        }
      }
    } else if(parent instanceof AllocationExpression) {
      AllocationExpression allocationExpression = (AllocationExpression) parent;

      ReferenceBinding binding = (ReferenceBinding)allocationExpression.type.resolvedType;

      if(binding != null) {
        computeExpectedTypesForAllocationExpression(
          binding,
          allocationExpression.arguments,
          scope,
          allocationExpression);
      }
    } else if(parent instanceof OperatorExpression) {
      int operator = (parent.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
      if(parent instanceof ConditionalExpression) {
        // for future use
      } else if(parent instanceof InstanceOfExpression) {
        InstanceOfExpression e = (InstanceOfExpression) parent;
        TypeBinding binding = e.expression.resolvedType;
        if(binding != null){
          addExpectedType(binding, scope);
          this.expectedTypesFilter = SUBTYPE | SUPERTYPE;
        }
      } else if(parent instanceof BinaryExpression) {
        BinaryExpression binaryExpression = (BinaryExpression) parent;
        switch(operator) {
          case OperatorIds.EQUAL_EQUAL :
            // expected type is not relevant in this case
            TypeBinding binding = binaryExpression.left.resolvedType;
            if (binding != null) {
              addExpectedType(binding, scope);
              this.expectedTypesFilter = SUBTYPE | SUPERTYPE;
            }
            break;
          case OperatorIds.PLUS :
            addExpectedType(TypeBinding.SHORT, scope);
            addExpectedType(TypeBinding.INT, scope);
            addExpectedType(TypeBinding.LONG, scope);
            addExpectedType(TypeBinding.FLOAT, scope);
            addExpectedType(TypeBinding.DOUBLE, scope);
            addExpectedType(TypeBinding.CHAR, scope);
            addExpectedType(TypeBinding.BYTE, scope);
            addExpectedType(scope.getJavaLangString(), scope);
            break;
          case OperatorIds.AND_AND :
          case OperatorIds.OR_OR :
          case OperatorIds.XOR :
            addExpectedType(TypeBinding.BOOLEAN, scope);
            break;
          default :
            addExpectedType(TypeBinding.SHORT, scope);
            addExpectedType(TypeBinding.INT, scope);
            addExpectedType(TypeBinding.LONG, scope);
            addExpectedType(TypeBinding.FLOAT, scope);
            addExpectedType(TypeBinding.DOUBLE, scope);
            addExpectedType(TypeBinding.CHAR, scope);
            addExpectedType(TypeBinding.BYTE, scope);
            break;
        }
        if(operator == OperatorIds.LESS) {
          if(binaryExpression.left instanceof SingleNameReference){
            SingleNameReference name = (SingleNameReference) binaryExpression.left;
            Binding b = scope.getBinding(name.token, Binding.VARIABLE | Binding.TYPE, name, false);
            if(b instanceof ReferenceBinding) {
              TypeVariableBinding[] typeVariableBindings =((ReferenceBinding)b).typeVariables();
              if(typeVariableBindings != null && typeVariableBindings.length > 0) {
                addExpectedType(typeVariableBindings[0].firstBound, scope);
              }

            }
          }
        }
      } else if(parent instanceof UnaryExpression) {
        switch(operator) {
          case OperatorIds.NOT :
            addExpectedType(TypeBinding.BOOLEAN, scope);
            break;
          case OperatorIds.TWIDDLE :
            addExpectedType(TypeBinding.SHORT, scope);
            addExpectedType(TypeBinding.INT, scope);
            addExpectedType(TypeBinding.LONG, scope);
            addExpectedType(TypeBinding.CHAR, scope);
            addExpectedType(TypeBinding.BYTE, scope);
            break;
          case OperatorIds.PLUS :
          case OperatorIds.MINUS :
          case OperatorIds.PLUS_PLUS :
          case OperatorIds.MINUS_MINUS :
            addExpectedType(TypeBinding.SHORT, scope);
            addExpectedType(TypeBinding.INT, scope);
            addExpectedType(TypeBinding.LONG, scope);
            addExpectedType(TypeBinding.FLOAT, scope);
            addExpectedType(TypeBinding.DOUBLE, scope);
            addExpectedType(TypeBinding.CHAR, scope);
            addExpectedType(TypeBinding.BYTE, scope);
            break;
        }
      }
    } else if(parent instanceof ArrayReference) {
      addExpectedType(TypeBinding.SHORT, scope);
      addExpectedType(TypeBinding.INT, scope);
      addExpectedType(TypeBinding.LONG, scope);
    } else if(parent instanceof ParameterizedSingleTypeReference) {
      ParameterizedSingleTypeReference ref = (ParameterizedSingleTypeReference) parent;
      TypeBinding expected = null;
      if (this.parser.enclosingNode instanceof AbstractVariableDeclaration ||
          this.parser.enclosingNode instanceof ReturnStatement) {
        // completing inside the diamond
        if (this.parser.enclosingNode instanceof AbstractVariableDeclaration) {
          AbstractVariableDeclaration abstractVariableDeclaration = (AbstractVariableDeclaration) this.parser.enclosingNode;
          expected = abstractVariableDeclaration.initialization != null ? abstractVariableDeclaration.initialization.expectedType() : null;         
        } else {
          ReturnStatement returnStatement = (ReturnStatement) this.parser.enclosingNode;
          if (returnStatement.expression != null) {
            expected = returnStatement.expression.expectedType();
          }
        } 
        addExpectedType(expected, scope);
      } else {
        TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables();
        int length = ref.typeArguments == null ? 0 : ref.typeArguments.length;
        if(typeVariables != null && typeVariables.length >= length) {
          int index = length - 1;
          while(index > -1 && ref.typeArguments[index] != node) index--;
 
          TypeBinding bound = typeVariables[index].firstBound;
          addExpectedType(bound == null ? scope.getJavaLangObject() : bound, scope);
        }
      }
    } else if(parent instanceof ParameterizedQualifiedTypeReference) {
      ParameterizedQualifiedTypeReference ref = (ParameterizedQualifiedTypeReference) parent;
      TypeReference[][] arguments = ref.typeArguments;
      TypeBinding expected = null;
      if (this.parser.enclosingNode instanceof AbstractVariableDeclaration ||
          this.parser.enclosingNode instanceof ReturnStatement) {
        // completing inside the diamond
        if (this.parser.enclosingNode instanceof AbstractVariableDeclaration) {
          AbstractVariableDeclaration abstractVariableDeclaration = (AbstractVariableDeclaration) this.parser.enclosingNode;
          expected = abstractVariableDeclaration.initialization != null ? abstractVariableDeclaration.initialization.expectedType() : null;
        } else {
          ReturnStatement returnStatement = (ReturnStatement) this.parser.enclosingNode;
          if (returnStatement.expression != null) {
            expected = returnStatement.expression.expectedType();
          }
        }
        addExpectedType(expected, scope);
      } else {
        TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables();
        if(typeVariables != null) {
          int iLength = arguments == null ? 0 : arguments.length;
          done: for (int i = 0; i < iLength; i++) {
            int jLength = arguments[i] == null ? 0 : arguments[i].length;
            for (int j = 0; j < jLength; j++) {
              if(arguments[i][j] == node && typeVariables.length > j) {
                TypeBinding bound = typeVariables[j].firstBound;
                addExpectedType(bound == null ? scope.getJavaLangObject() : bound, scope);
                break done;
              }
            }
          }
        }
      }
    } else if(parent instanceof MemberValuePair) {
      MemberValuePair memberValuePair = (MemberValuePair) parent;
      if(memberValuePair.binding != null) {
        addExpectedType(memberValuePair.binding.returnType, scope);
      }
    } else if (parent instanceof NormalAnnotation) {
      NormalAnnotation annotation = (NormalAnnotation) parent;
      MemberValuePair[] memberValuePairs = annotation.memberValuePairs();
      if(memberValuePairs == null || memberValuePairs.length == 0) {
        if(annotation.resolvedType instanceof ReferenceBinding) {
          MethodBinding[] methodBindings =
            ((ReferenceBinding)annotation.resolvedType).availableMethods();
          if (methodBindings != null &&
              methodBindings.length > 0 &&
              CharOperation.equals(methodBindings[0].selector, VALUE)) {
            boolean canBeSingleMemberAnnotation = true;
            done : for (int i = 1; i < methodBindings.length; i++) {
              if((methodBindings[i].modifiers & ClassFileConstants.AccAnnotationDefault) == 0) {
                canBeSingleMemberAnnotation = false;
                break done;
              }
            }
            if (canBeSingleMemberAnnotation) {
              this.assistNodeCanBeSingleMemberAnnotation = canBeSingleMemberAnnotation;
              addExpectedType(methodBindings[0].returnType, scope);
            }
          }
        }
      }
    } else if (parent instanceof TryStatement) {
      boolean isException = false;
      if (node instanceof CompletionOnSingleTypeReference) {
        isException = ((CompletionOnSingleTypeReference)node).isException();
      } else if (node instanceof CompletionOnQualifiedTypeReference) {
        isException = ((CompletionOnQualifiedTypeReference)node).isException();
      } else if (node instanceof CompletionOnParameterizedQualifiedTypeReference) {
        isException = ((CompletionOnParameterizedQualifiedTypeReference)node).isException();
      }
      if (isException) {
        ThrownExceptionFinder thrownExceptionFinder = new ThrownExceptionFinder();
        thrownExceptionFinder.processThrownExceptions((TryStatement) parent, (BlockScope)scope);
        ReferenceBinding[] bindings = thrownExceptionFinder.getThrownUncaughtExceptions();
        ReferenceBinding[] alreadyCaughtExceptions = thrownExceptionFinder.getAlreadyCaughtExceptions();
        ReferenceBinding[] discouragedExceptions = thrownExceptionFinder.getDiscouragedExceptions();
        if (bindings != null && bindings.length > 0) {
          for (int i = 0; i < bindings.length; i++) {
            addExpectedType(bindings[i], scope);
          }
          this.expectedTypesFilter = SUPERTYPE;
        }
        if (alreadyCaughtExceptions != null && alreadyCaughtExceptions.length > 0) {
          for (int i = 0; i < alreadyCaughtExceptions.length; i++) {
            addForbiddenBindings(alreadyCaughtExceptions[i]);
            this.knownTypes.put(CharOperation.concat(alreadyCaughtExceptions[i].qualifiedPackageName(), alreadyCaughtExceptions[i].qualifiedSourceName(), '.'), KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS);
          }
        }
        if (discouragedExceptions != null && discouragedExceptions.length > 0) {
          for (int i = 0; i < discouragedExceptions.length; i++) {
            addUninterestingBindings(discouragedExceptions[i]);
            // do not insert into known types. We do need these types to come from
            // searchAllTypes(..) albeit with lower relevance
          }
        }
      }
    } else if (parent instanceof SwitchStatement) {
      SwitchStatement switchStatement = (SwitchStatement) parent;
      this.assistNodeIsInsideCase = assistNodeIsInsideCase(node, parent);
      if (switchStatement.expression != null &&
          switchStatement.expression.resolvedType != null) {
        if (this.assistNodeIsInsideCase &&
            switchStatement.expression.resolvedType.id == TypeIds.T_JavaLangString &&
            this.compilerOptions.complianceLevel >= ClassFileConstants.JDK1_7) {
          // set the field to true even though the expected types array will contain String as
          // expected type to avoid traversing the array in every case later on.
          // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343476
          this.assistNodeIsString = true;
        }
        addExpectedType(switchStatement.expression.resolvedType, scope);
      }
    // https://bugs.eclipse.org/bugs/show_bug.cgi?id=253008, flag boolean as the expected
    // type if we are completing inside if(), for (; ;), while() and do while()
    } else if (parent instanceof WhileStatement) {  // covers both while and do-while loops
      addExpectedType(TypeBinding.BOOLEAN, scope);
    } else if (parent instanceof IfStatement) { 
      addExpectedType(TypeBinding.BOOLEAN, scope);
    } else if (parent instanceof AssertStatement) {
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=274466
      // If the assertExpression is same as the node , then the assistNode is the conditional part of the assert statement
      AssertStatement assertStatement = (AssertStatement) parent;
      if (assertStatement.assertExpression == node) {
        addExpectedType(TypeBinding.BOOLEAN, scope);
      }
    } else if (parent instanceof ForStatement) {   // astNodeParent set to ForStatement only for the condition 
      addExpectedType(TypeBinding.BOOLEAN, scope);

    // Expected types for javadoc
    } else if (parent instanceof Javadoc) {
      if (scope.kind == Scope.METHOD_SCOPE) {
        MethodScope methodScope = (MethodScope) scope;
        AbstractMethodDeclaration methodDecl = methodScope.referenceMethod();
        if (methodDecl != null && methodDecl.binding != null) {
          ReferenceBinding[] exceptions = methodDecl.binding.thrownExceptions;
          if (exceptions != null) {
            for (int i = 0; i < exceptions.length; i++) {
              addExpectedType(exceptions[i], scope);
            }
          }
        }
      }
    }

    if(this.expectedTypesPtr + 1 != this.expectedTypes.length) {
      System.arraycopy(this.expectedTypes, 0, this.expectedTypes = new TypeBinding[this.expectedTypesPtr + 1], 0, this.expectedTypesPtr + 1);
    }
  }

  private void computeExpectedTypesForAllocationExpression(
    ReferenceBinding binding,
    Expression[] arguments,
    Scope scope,
    InvocationSite invocationSite) {

    MethodBinding[] methods = binding.availableMethods();
    nextMethod : for (int i = 0; i < methods.length; i++) {
      MethodBinding method = methods[i];

      if (!method.isConstructor()) continue nextMethod;

      if (method.isSynthetic()) continue nextMethod;

      if (this.options.checkVisibility && !method.canBeSeenBy(invocationSite, scope)) continue nextMethod;

      TypeBinding[] parameters = method.parameters;
      if(parameters.length < arguments.length)
        continue nextMethod;

      int length = arguments.length - 1;

      for (int j = 0; j < length; j++) {
        Expression argument = arguments[j];
        TypeBinding argType = argument.resolvedType;
        if(argType != null && !argType.isCompatibleWith(parameters[j]))
          continue nextMethod;
      }

      TypeBinding expectedType = method.parameters[arguments.length - 1];
      if(expectedType != null) {
        addExpectedType(expectedType, scope);
      }
    }
  }
  private void computeExpectedTypesForMessageSend(
    ReferenceBinding binding,
    char[] selector,
    Expression[] arguments,
    ReferenceBinding receiverType,
    Scope scope,
    InvocationSite invocationSite,
    boolean isStatic) {

    MethodBinding[] methods = binding.availableMethods();
    nextMethod : for (int i = 0; i < methods.length; i++) {
      MethodBinding method = methods[i];

      if (method.isSynthetic()) continue nextMethod;

      if (method.isDefaultAbstract())  continue nextMethod;

      if (method.isConstructor()) continue nextMethod;

      if (isStatic && !method.isStatic()) continue nextMethod;

      if (this.options.checkVisibility && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue nextMethod;

      if(!CharOperation.equals(method.selector, selector)) continue nextMethod;

      TypeBinding[] parameters = method.parameters;
      if(parameters.length < arguments.length)
        continue nextMethod;

      int length = arguments.length - 1;

      for (int j = 0; j < length; j++) {
        Expression argument = arguments[j];
        TypeBinding argType = argument.resolvedType;
        if(argType != null && !argType.isCompatibleWith(parameters[j]))
          continue nextMethod;
      }

      TypeBinding expectedType = method.parameters[arguments.length - 1];
      if(expectedType != null) {
        addExpectedType(expectedType, scope);
      }
    }
  }
  private void computeExpectedTypesForMessageSendForInterface(
    ReferenceBinding binding,
    char[] selector,
    Expression[] arguments,
    ReferenceBinding receiverType,
    Scope scope,
    InvocationSite invocationSite,
    boolean isStatic) {

    ReferenceBinding[] itsInterfaces = binding.superInterfaces();
    if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
      ReferenceBinding[] interfacesToVisit = itsInterfaces;
      int nextPosition = interfacesToVisit.length;

      for (int i = 0; i < nextPosition; i++) {
        ReferenceBinding currentType = interfacesToVisit[i];
        computeExpectedTypesForMessageSend(
          currentType,
          selector,
          arguments,
          receiverType,
          scope,
          invocationSite,
          isStatic);

        if ((itsInterfaces = currentType.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;
          }
        }
      }
    }
  }

  private Scope computeForbiddenBindings(ASTNode astNode, ASTNode astNodeParent, Scope scope) {
    if(scope instanceof ClassScope) {
      TypeDeclaration typeDeclaration = ((ClassScope)scope).referenceContext;
      if(typeDeclaration.superclass == astNode) {
        addForbiddenBindings(typeDeclaration.binding);
        addForbiddenBindingsForMemberTypes(typeDeclaration);
        return scope.parent;
      }
      TypeReference[] superInterfaces = typeDeclaration.superInterfaces;
      int length = superInterfaces == null ? 0 : superInterfaces.length;
      int astNodeIndex = -1;
      for (int i = 0; i < length; i++) {
        if(superInterfaces[i] == astNode) {
          addForbiddenBindings(typeDeclaration.binding);
          addForbiddenBindingsForMemberTypes(typeDeclaration);
          astNodeIndex = i;
          break;
        }
      }
      if (astNodeIndex >= 0) {
        // Need to loop only up to astNodeIndex as the rest will be undefined.
        for (int i = 0; i < astNodeIndex; i++) {
          addForbiddenBindings(superInterfaces[i].resolvedType);
        }
        return scope.parent;
      }
    }
//    else if(scope instanceof MethodScope) {
//      MethodScope methodScope = (MethodScope) scope;
//      if(methodScope.insideTypeAnnotation) {
//        return methodScope.parent.parent;
//      }
//    }
    return scope;
  }

  // https://bugs.eclipse.org/bugs/show_bug.cgi?id=270437
  private void addForbiddenBindingsForMemberTypes(TypeDeclaration typeDeclaration) {
    TypeDeclaration[] memberTypes = typeDeclaration.memberTypes;
    int memberTypesLen = memberTypes == null ? 0 : memberTypes.length;
    for (int i = 0; i < memberTypesLen; i++) {
      addForbiddenBindings(memberTypes[i].binding);
      addForbiddenBindingsForMemberTypes(memberTypes[i]);
    }
  }

  private char[] computePrefix(SourceTypeBinding declarationType, SourceTypeBinding invocationType, boolean isStatic){

    StringBuffer completion = new StringBuffer(10);

    if (isStatic) {
      completion.append(declarationType.sourceName());

    } else if (declarationType == invocationType) {
      completion.append(THIS);

    } else {

      if (!declarationType.isNestedType()) {

        completion.append(declarationType.sourceName());
        completion.append('.');
        completion.append(THIS);

      } else if (!declarationType.isAnonymousType()) {

        completion.append(declarationType.sourceName());
        completion.append('.');
        completion.append(THIS);

      }
    }

    return completion.toString().toCharArray();
  }

  private int computeRelevanceForAnnotation(){
    if(this.assistNodeIsAnnotation) {
      return R_ANNOTATION;
    }
    return 0;
  }

  private int computeRelevanceForAnnotationTarget(TypeBinding typeBinding){
    if (this.assistNodeIsAnnotation &&
        (this.targetedElement & TagBits.AnnotationTargetMASK) != 0) {
      long target = typeBinding.getAnnotationTagBits() & TagBits.AnnotationTargetMASK;
      if(target == 0 || (target & this.targetedElement) != 0) {
        return R_TARGET;
      }
    }
    return 0;
  }
  int computeRelevanceForCaseMatching(char[] token, char[] proposalName){
    if (this.options.camelCaseMatch) {
      if(CharOperation.equals(token, proposalName, true /* do not ignore case */)) {
        return R_CASE + R_EXACT_NAME;
      } else if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) {
        return R_CASE;
      } else if (CharOperation.camelCaseMatch(token, proposalName)){
        return R_CAMEL_CASE;
      } else if(CharOperation.equals(token, proposalName, false /* ignore case */)) {
        return R_EXACT_NAME;
      }
    } else if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) {
      if(CharOperation.equals(token, proposalName, true /* do not ignore case */)) {
        return R_CASE + R_EXACT_NAME;
      } else {
        return R_CASE;
      }
    } else if(CharOperation.equals(token, proposalName, false /* ignore case */)) {
      return R_EXACT_NAME;
    }
    return 0;
  }

  private int computeRelevanceForClass(){
    if(this.assistNodeIsClass) {
      return R_CLASS;
    }
    return 0;
  }

  private int computeRelevanceForEnum(){
    if(this.assistNodeIsEnum) {
      return R_ENUM;
    }
    return 0;
  }

  private int computeRelevanceForEnumConstant(TypeBinding proposalType){
    if(this.assistNodeIsEnum &&
        proposalType != null &&
        this.expectedTypes != null) {
      for (int i = 0; i <= this.expectedTypesPtr; i++) {
        if (proposalType.isEnum() &&
            proposalType == this.expectedTypes[i]) {
          return R_ENUM + R_ENUM_CONSTANT;
        }

      }
    }
    return 0;
  }

  private int computeRelevanceForException(){
    if (this.assistNodeIsException) {
      return R_EXCEPTION;
    }
    return 0;
  }

  private int computeRelevanceForException(char[] proposalName){

    if((this.assistNodeIsException || (this.assistNodeInJavadoc & CompletionOnJavadoc.EXCEPTION) != 0 )&&
      (CharOperation.match(EXCEPTION_PATTERN, proposalName, false) ||
      CharOperation.match(ERROR_PATTERN, proposalName, false))) {
      return R_EXCEPTION;
    }
    return 0;
  }

  private int computeRelevanceForExpectingType(char[] packageName, char[] typeName){
    if(this.expectedTypes != null) {
      for (int i = 0; i <= this.expectedTypesPtr; i++) {
        if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), packageName) &&
          CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), typeName)) {
          return R_EXACT_EXPECTED_TYPE;
        }
      }
      if(this.hasJavaLangObjectAsExpectedType) {
        return R_EXPECTED_TYPE;
      }
    }
    return 0;
  }

  private int computeRelevanceForExpectingType(TypeBinding proposalType){
    if(this.expectedTypes != null && proposalType != null) {
      int relevance = 0;
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=271296
      // If there is at least one expected type, then void proposal types attract a degraded relevance. 
      if (proposalType == TypeBinding.VOID && this.expectedTypesPtr >=0) {
        return R_VOID;
     
      for (int i = 0; i <= this.expectedTypesPtr; i++) {
        if((this.expectedTypesFilter & SUBTYPE) != 0
            && proposalType.isCompatibleWith(this.expectedTypes[i])) {

          if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) &&
              CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) {
            return R_EXACT_EXPECTED_TYPE;
          }

          relevance = R_EXPECTED_TYPE;
        }
        if((this.expectedTypesFilter & SUPERTYPE) != 0
            && this.expectedTypes[i].isCompatibleWith(proposalType)) {

          if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) &&
              CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) {
            return R_EXACT_EXPECTED_TYPE;
          }

          relevance = R_EXPECTED_TYPE;
        }
        // Bug 84720 - [1.5][assist] proposal ranking by return value should consider auto(un)boxing
        // Just ensuring that the unitScope is not null, even though it's an unlikely case.
        if (this.unitScope != null && this.unitScope.isBoxingCompatibleWith(proposalType, this.expectedTypes[i])) {
          relevance = R_EXPECTED_TYPE;
        }
      }
      return relevance;
    }
    return 0;
  }

  private int computeRelevanceForInheritance(ReferenceBinding receiverType, ReferenceBinding declaringClass) {
    if (receiverType == declaringClass) return R_NON_INHERITED;
    return 0;
  }

  int computeRelevanceForInterestingProposal(){
    return computeRelevanceForInterestingProposal(null);
  }

  private int computeRelevanceForInterestingProposal(Binding binding){
    if(this.uninterestingBindings != null) {
      for (int i = 0; i <= this.uninterestingBindingsPtr; i++) {
        if(this.uninterestingBindings[i] == binding) {
          return 0;
        }
        if((this.uninterestingBindingsFilter & SUBTYPE) != 0) {
          if (binding instanceof TypeBinding &&
              this.uninterestingBindings[i] instanceof TypeBinding &&
              ((TypeBinding)binding).isCompatibleWith((TypeBinding)this.uninterestingBindings[i])) {
            return 0;
          }
        }
        if ((this.uninterestingBindingsFilter & SUPERTYPE) != 0) {
          if (binding instanceof TypeBinding &&
              this.uninterestingBindings[i] instanceof TypeBinding &&
              ((TypeBinding)this.uninterestingBindings[i]).isCompatibleWith((TypeBinding)binding)) {
            return 0;
          }
        }
      }
    }
    return R_INTERESTING;
  }
 
  private int computeRelevanceForInterestingProposal(char[] givenPkgName, char[] fullTypeName) {
    for (int i = 0; i <= this.uninterestingBindingsPtr; i++) {
      if (this.uninterestingBindings[i] instanceof TypeBinding) {
        TypeBinding typeBinding = (TypeBinding) this.uninterestingBindings[i];
        char[] currPkgName = typeBinding.qualifiedPackageName();
        if (CharOperation.equals(givenPkgName, currPkgName))  {
          char[] currTypeName = typeBinding.qualifiedSourceName();
          if (CharOperation.equals(fullTypeName, currTypeName)) {
            return 0;
          }
        }
      }
    }
    return R_INTERESTING;
  }

  private int computeRelevanceForInterface(){
    if(this.assistNodeIsInterface) {
      return R_INTERFACE;
    }
    return 0;
  }

  private int computeRelevanceForMissingElements(boolean hasProblems) {
    if (!hasProblems) {
      return R_NO_PROBLEMS;
    }
    return 0;
  }
  int computeRelevanceForQualification(boolean prefixRequired) {
    if(!prefixRequired && !this.insideQualifiedReference) {
      return R_UNQUALIFIED;
    }

    if(prefixRequired && this.insideQualifiedReference) {
      return R_QUALIFIED;
    }
    return 0;
  }

  int computeRelevanceForResolution(){
    return computeRelevanceForResolution(true);
  }

  int computeRelevanceForResolution(boolean isResolved){
    if (isResolved) {
      return R_RESOLVED;
    }
    return 0;
  }

  int computeRelevanceForRestrictions(int accessRuleKind) {
    if(accessRuleKind == IAccessRule.K_ACCESSIBLE) {
      return R_NON_RESTRICTED;
    }
    return 0;
  }

  private int computeRelevanceForStatic(boolean onlyStatic, boolean isStatic) {
    if(this.insideQualifiedReference && !onlyStatic && !isStatic) {
      return R_NON_STATIC;
    }
    return 0;
  }
 
  private int computeRelevanceForFinal(boolean onlyFinal, boolean isFinal) {
    if (onlyFinal && isFinal) {
      return R_FINAL;
    }
    return 0;
  }

  private long computeTargetedElement(CompletionOnAnnotationOfType fakeNode) {
    ASTNode annotatedElement = fakeNode.potentialAnnotatedNode;

    if (annotatedElement instanceof TypeDeclaration) {
      TypeDeclaration annotatedTypeDeclaration = (TypeDeclaration) annotatedElement;
      if (TypeDeclaration.kind(annotatedTypeDeclaration.modifiers) == TypeDeclaration.ANNOTATION_TYPE_DECL) {
        return TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType;
      }
      return TagBits.AnnotationForType;
    } else if (annotatedElement instanceof FieldDeclaration) {
      if (fakeNode.isParameter) {
        return TagBits.AnnotationForParameter;
      }
      return TagBits.AnnotationForField;
    } else if (annotatedElement instanceof MethodDeclaration) {
      return TagBits.AnnotationForMethod;
    } else if (annotatedElement instanceof Argument) {
      return TagBits.AnnotationForParameter;
    } else if (annotatedElement instanceof ConstructorDeclaration) {
      return TagBits.AnnotationForConstructor;
    } else if (annotatedElement instanceof LocalDeclaration) {
      return TagBits.AnnotationForLocalVariable;
    } else if (annotatedElement instanceof ImportReference) {
      return TagBits.AnnotationForPackage;
    }
    return 0;
  }
  private TypeBinding[] computeTypes(Expression[] arguments) {
    if (arguments == null) return null;
    int argsLength = arguments.length;
    TypeBinding[] argTypes = new TypeBinding[argsLength];
    for (int a = argsLength; --a >= 0;) {
      argTypes[a] = arguments[a].resolvedType;
    }
    return argTypes;
  }

  private TypeBinding[] computeTypesIfCorrect(Expression[] arguments) {
    if (arguments == null) return null;
    int argsLength = arguments.length;
    TypeBinding[] argTypes = new TypeBinding[argsLength];
    for (int a = argsLength; --a >= 0;) {
      TypeBinding typeBinding = arguments[a].resolvedType;
      if(typeBinding == null || !typeBinding.isValidBinding()) return null;
      argTypes[a] = typeBinding;
    }
    return argTypes;
  }

  private void computeUninterestingBindings(ASTNode astNode, ASTNode parent, Scope scope){
    this.uninterestingBindingsFilter = NONE;
    if(parent instanceof LocalDeclaration) {
      addUninterestingBindings(((LocalDeclaration)parent).binding);
    } else if (parent instanceof FieldDeclaration) {
      addUninterestingBindings(((FieldDeclaration)parent).binding);
    } else if (parent instanceof TryStatement) {
      boolean isException = false;
      if (astNode instanceof CompletionOnSingleTypeReference) {
        isException = ((CompletionOnSingleTypeReference)astNode).isException();
      } else if (astNode instanceof CompletionOnQualifiedTypeReference) {
        isException = ((CompletionOnQualifiedTypeReference)astNode).isException();
      } else if (astNode instanceof CompletionOnParameterizedQualifiedTypeReference) {
        isException = ((CompletionOnParameterizedQualifiedTypeReference)astNode).isException();
      }
      if (isException) {
        this.uninterestingBindingsFilter |= SUBTYPE;
        // super-types also need to be discouraged if we're in a union type (bug 350652)
        Argument[] args = ((TryStatement)parent).catchArguments;
        for (int i = 0; i < args.length; i++) {
          if (args[i].type instanceof UnionTypeReference) {
            CompletionNodeDetector detector = new CompletionNodeDetector(astNode, args[i]);
            if (detector.containsCompletionNode()) {
              this.uninterestingBindingsFilter |= SUPERTYPE;
              break;
            }
          }
        }
       
      }
    }
  }

  private char[] createImportCharArray(char[] importedElement, boolean isStatic, boolean onDemand) {
    char[] result = IMPORT;
    if (isStatic) {
      result = CharOperation.concat(result, STATIC, ' ');
    }
    result = CharOperation.concat(result, importedElement, ' ');
    if (onDemand) {
      result = CharOperation.concat(result, ON_DEMAND);
    }
    return CharOperation.concat(result, IMPORT_END);
  }

  private void createMethod(MethodBinding method, char[][] parameterPackageNames, char[][] parameterTypeNames, char[][] parameterNames, Scope scope, StringBuffer completion) {
    //// Modifiers
    // flush uninteresting modifiers
    int insertedModifiers = method.modifiers & ~(ClassFileConstants.AccNative | ClassFileConstants.AccAbstract);
    if(insertedModifiers != ClassFileConstants.AccDefault){
      ASTNode.printModifiers(insertedModifiers, completion);
    }

    //// Type parameters

    TypeVariableBinding[] typeVariableBindings = method.typeVariables;
    if(typeVariableBindings != null && typeVariableBindings.length != 0) {
      completion.append('<');
      for (int i = 0; i < typeVariableBindings.length; i++) {
        if(i != 0) {
          completion.append(',');
          completion.append(' ');
        }
        createTypeVariable(typeVariableBindings[i], scope, completion);
      }
      completion.append('>');
      completion.append(' ');
    }

    //// Return type
    createType(method.returnType, scope, completion);
    completion.append(' ');

    //// Selector
    completion.append(method.selector);

    completion.append('(');

    ////Parameters
    TypeBinding[] parameterTypes = method.parameters;
    int length = parameterTypes.length;
    for (int i = 0; i < length; i++) {
      if(i != 0) {
        completion.append(',');
        completion.append(' ');
      }
      createType(parameterTypes[i], scope, completion);
      completion.append(' ');
      if(parameterNames != null){
        completion.append(parameterNames[i]);
      } else {
        completion.append('%');
      }
    }

    completion.append(')');

    //// Exceptions
    ReferenceBinding[] exceptions = method.thrownExceptions;

    if (exceptions != null && exceptions.length > 0){
      completion.append(' ');
      completion.append(THROWS);
      completion.append(' ');
      for(int i = 0; i < exceptions.length ; i++){
        if(i != 0) {
          completion.append(' ');
          completion.append(',');
        }
        createType(exceptions[i], scope, completion);
      }
    }
  }

  protected InternalCompletionProposal createProposal(int kind, int completionOffset) {
    InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(kind, completionOffset - this.offset);
    proposal.nameLookup = this.nameEnvironment.nameLookup;
    proposal.completionEngine = this;
    return proposal;
  }

  private CompletionProposal createRequiredTypeProposal(Binding binding, int start, int end, int relevance) {
    InternalCompletionProposal proposal = null;
    if (binding instanceof ReferenceBinding) {
      ReferenceBinding typeBinding = (ReferenceBinding) binding;

      char[] packageName = typeBinding.qualifiedPackageName();
      char[] typeName = typeBinding.qualifiedSourceName();
      char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');

      proposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setDeclarationSignature(packageName);
      proposal.setSignature(getRequiredTypeSignature(typeBinding));
      proposal.setPackageName(packageName);
      proposal.setTypeName(typeName);
      proposal.setCompletion(fullyQualifiedName);
      proposal.setFlags(typeBinding.modifiers);
      proposal.setReplaceRange(start - this.offset, end - this.offset);
      proposal.setTokenRange(start - this.offset, end - this.offset);
      proposal.setRelevance(relevance);
    } else if (binding instanceof PackageBinding) {
      PackageBinding packageBinding = (PackageBinding) binding;

      char[] packageName = CharOperation.concatWith(packageBinding.compoundName, '.');

      proposal = createProposal(CompletionProposal.PACKAGE_REF, this.actualCompletionPosition);
      proposal.setDeclarationSignature(packageName);
      proposal.setPackageName(packageName);
      proposal.setCompletion(packageName);
      proposal.setReplaceRange(start - this.offset, end - this.offset);
      proposal.setTokenRange(start - this.offset, end - this.offset);
      proposal.setRelevance(relevance);
    }
    return proposal;
  }

  private void createType(TypeBinding type, Scope scope, StringBuffer completion) {
    switch (type.kind()) {
      case Binding.BASE_TYPE :
        completion.append(type.sourceName());
        break;
      case Binding.WILDCARD_TYPE :
      case Binding.INTERSECTION_TYPE : // TODO (david) need to handle intersection type specifically
        WildcardBinding wildcardBinding = (WildcardBinding) type;
        completion.append('?');
        switch (wildcardBinding.boundKind) {
          case Wildcard.EXTENDS:
            completion.append(' ');
            completion.append(EXTENDS);
            completion.append(' ');
            createType(wildcardBinding.bound, scope, completion);
            if(wildcardBinding.otherBounds != null) {

              int length = wildcardBinding.otherBounds.length;
              for (int i = 0; i < length; i++) {
                completion.append(' ');
                completion.append('&');
                completion.append(' ');
                createType(wildcardBinding.otherBounds[i], scope, completion);
              }
            }
            break;
          case Wildcard.SUPER:
            completion.append(' ');
            completion.append(SUPER);
            completion.append(' ');
            createType(wildcardBinding.bound, scope, completion);
            break;
        }
        break;
      case Binding.ARRAY_TYPE :
        createType(type.leafComponentType(), scope, completion);
        int dim = type.dimensions();
        for (int i = 0; i < dim; i++) {
          completion.append('[');
          completion.append(']');
        }
        break;
      case Binding.PARAMETERIZED_TYPE :
        ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding) type;
        if (type.isMemberType()) {
          createType(parameterizedType.enclosingType(), scope, completion);
          completion.append('.');
          completion.append(parameterizedType.sourceName);
        } else {
          completion.append(CharOperation.concatWith(parameterizedType.genericType().compoundName, '.'));
        }
        if (parameterizedType.arguments != null) {
          completion.append('<');
            for (int i = 0, length = parameterizedType.arguments.length; i < length; i++) {
                if (i != 0) completion.append(',');
                createType(parameterizedType.arguments[i], scope, completion);
            }
            completion.append('>');
        }
        break;
      default :
        char[] packageName = type.qualifiedPackageName();
      char[] typeName = type.qualifiedSourceName();
      if(mustQualifyType(
          (ReferenceBinding)type,
          packageName,
          scope)) {
        completion.append(CharOperation.concat(packageName, typeName,'.'));
      } else {
        completion.append(type.sourceName());
      }
      break;
    }
  }

  /*
   * Create a completion proposal for a member type.
   */
  private void createTypeParameterProposal(TypeParameter typeParameter, int relevance) {
    char[] completionName = typeParameter.name;

    // Create standard type proposal
    if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.TYPE_REF, this.actualCompletionPosition - this.offset);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setSignature(getSignature(typeParameter.binding));
      proposal.setTypeName(completionName);
      proposal.setCompletion(completionName);
      proposal.setFlags(typeParameter.modifiers);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }

    // Create javadoc text proposal if necessary
    if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)) {
      char[] javadocCompletion= inlineTagCompletion(completionName, JavadocTagConstants.TAG_LINK);
      InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.JAVADOC_TYPE_REF, this.actualCompletionPosition - this.offset);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setSignature(getSignature(typeParameter.binding));
      proposal.setTypeName(javadocCompletion);
      proposal.setCompletion(javadocCompletion);
      proposal.setFlags(typeParameter.modifiers);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance+R_INLINE_TAG);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }
  }

  /*
   * Create a completion proposal for a type.
   */
  private void createTypeProposal(char[] packageName, char[] typeName, int modifiers, int accessibility, char[] completionName, int relevance) {

    // Create standard type proposal
    if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF) && (this.assistNodeInJavadoc & CompletionOnJavadoc.ONLY_INLINE_TAG) == 0) {
      InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.TYPE_REF, this.actualCompletionPosition - this.offset);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setDeclarationSignature(packageName);
      proposal.setSignature(createNonGenericTypeSignature(packageName, typeName));
      proposal.setPackageName(packageName);
      proposal.setTypeName(typeName);
      proposal.setCompletion(completionName);
      proposal.setFlags(modifiers);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance);
      proposal.setAccessibility(accessibility);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }

    // Create javadoc text proposal if necessary
    if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)) {
      char[] javadocCompletion= inlineTagCompletion(completionName, JavadocTagConstants.TAG_LINK);
      InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.JAVADOC_TYPE_REF, this.actualCompletionPosition - this.offset);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setDeclarationSignature(packageName);
      proposal.setSignature(createNonGenericTypeSignature(packageName, typeName));
      proposal.setPackageName(packageName);
      proposal.setTypeName(typeName);
      proposal.setCompletion(javadocCompletion);
      proposal.setFlags(modifiers);
      int start = (this.assistNodeInJavadoc & CompletionOnJavadoc.REPLACE_TAG) != 0 ? this.javadocTagPosition : this.startPosition;
      proposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance+R_INLINE_TAG);
      proposal.setAccessibility(accessibility);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }
  }

  /*
   * Create a completion proposal for a member type.
   */
  private void createTypeProposal(
      ReferenceBinding refBinding,
      char[] typeName,
      int accessibility,
      char[] completionName,
      int relevance,
      Binding[] missingElements,
      int[] missingElementsStarts,
      int[] missingElementsEnds,
      boolean missingElementsHaveProblems) {

    // Create standard type proposal
    if(!this.isIgnored(CompletionProposal.TYPE_REF, missingElements != null) && (this.assistNodeInJavadoc & CompletionOnJavadoc.ONLY_INLINE_TAG) == 0) {
      InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.TYPE_REF, this.actualCompletionPosition - this.offset);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setDeclarationSignature(refBinding.qualifiedPackageName());
      proposal.setSignature(getCompletedTypeSignature(refBinding));
      proposal.setPackageName(refBinding.qualifiedPackageName());
      proposal.setTypeName(typeName);
      if (missingElements != null) {
        CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
        for (int i = 0; i < missingElements.length; i++) {
          subProposals[i] =
            createRequiredTypeProposal(
                missingElements[i],
                missingElementsStarts[i],
                missingElementsEnds[i],
                relevance);
        }
        proposal.setRequiredProposals(subProposals);
      }
      proposal.setCompletion(completionName);
      proposal.setFlags(refBinding.modifiers);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }

    // Create javadoc text proposal if necessary
    if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)) {
      char[] javadocCompletion= inlineTagCompletion(completionName, JavadocTagConstants.TAG_LINK);
      InternalCompletionProposal proposal = (InternalCompletionProposal) CompletionProposal.create(CompletionProposal.JAVADOC_TYPE_REF, this.actualCompletionPosition - this.offset);
      proposal.nameLookup = this.nameEnvironment.nameLookup;
      proposal.completionEngine = this;
      proposal.setDeclarationSignature(refBinding.qualifiedPackageName());
      proposal.setSignature(getCompletedTypeSignature(refBinding));
      proposal.setPackageName(refBinding.qualifiedPackageName());
      proposal.setTypeName(typeName);
      proposal.setCompletion(javadocCompletion);
      proposal.setFlags(refBinding.modifiers);
      int start = (this.assistNodeInJavadoc & CompletionOnJavadoc.REPLACE_TAG) != 0 ? this.javadocTagPosition : this.startPosition;
      proposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance+R_INLINE_TAG);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }
  }
  private void createTypeVariable(TypeVariableBinding typeVariable, Scope scope, StringBuffer completion) {
    completion.append(typeVariable.sourceName);

    if (typeVariable.superclass != null && typeVariable.firstBound == typeVariable.superclass) {
        completion.append(' ');
        completion.append(EXTENDS);
        completion.append(' ');
        createType(typeVariable.superclass, scope, completion);
    }
    if (typeVariable.superInterfaces != null && typeVariable.superInterfaces != Binding.NO_SUPERINTERFACES) {
       if (typeVariable.firstBound != typeVariable.superclass) {
         completion.append(' ');
         completion.append(EXTENDS);
         completion.append(' ');
       }
       for (int i = 0, length = typeVariable.superInterfaces.length; i < length; i++) {
         if (i > 0 || typeVariable.firstBound == typeVariable.superclass) {
           completion.append(' ');
           completion.append(EXTENDS);
           completion.append(' ');
         }
         createType(typeVariable.superInterfaces[i], scope, completion);
       }
    }
  }
  private void createVargsType(TypeBinding type, Scope scope, StringBuffer completion) {
    if (type.isArrayType()) {
      createType(type.leafComponentType(), scope, completion);
      int dim = type.dimensions() - 1;
      for (int i = 0; i < dim; i++) {
        completion.append('[');
        completion.append(']');
      }
      completion.append(VARARGS);
    } else {
      createType(type, scope, completion);
    }
  }
  private void findAnnotationAttributes(char[] token, MemberValuePair[] attributesFound, ReferenceBinding annotation) {
    MethodBinding[] methods = annotation.availableMethods();
    nextAttribute: for (int i = 0; i < methods.length; i++) {
      MethodBinding method = methods[i];

      if(!CharOperation.prefixEquals(token, method.selector, false)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, method.selector))) continue nextAttribute;

      int length = attributesFound == null ? 0 : attributesFound.length;
      for (int j = 0; j < length; j++) {
        if(CharOperation.equals(method.selector, attributesFound[j].name, false)) continue nextAttribute;
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal(method);
      relevance += computeRelevanceForCaseMatching(token, method.selector);
      relevance += computeRelevanceForQualification(false);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      this.noProposal = false;
      if(!this.requestor.isIgnored(CompletionProposal.ANNOTATION_ATTRIBUTE_REF)) {
        CompletionProposal proposal = createProposal(CompletionProposal.ANNOTATION_ATTRIBUTE_REF, this.actualCompletionPosition);
        proposal.setDeclarationSignature(getSignature(method.declaringClass));
        proposal.setSignature(getSignature(method.returnType));
        proposal.setName(method.selector);
        proposal.setCompletion(method.selector);
        proposal.setFlags(method.modifiers);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        this.requestor.accept(proposal);
        if(DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
  }
  void findAnonymousType(
      ReferenceBinding currentType,
      TypeBinding[] argTypes,
      Scope scope,
      InvocationSite invocationSite,
      Binding[] missingElements,
      int[] missingElementsStarts,
      int[] missingElementsEnds,
      boolean missingElementsHaveProblems) {
   
    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution();
    relevance += computeRelevanceForInterestingProposal(currentType);
    relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
   
    if (missingElements != null) {
      relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
    }
   
    findAnonymousType(
        currentType,
        argTypes,
        scope,
        invocationSite,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        true,
        false,
        relevance);
  }
  private void findAnonymousType(
    ReferenceBinding currentType,
    TypeBinding[] argTypes,
    Scope scope,
    InvocationSite invocationSite,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    boolean exactMatch,
    boolean isQualified,
    int relevance) {

    if (currentType.isInterface()) {
      char[] completion = CharOperation.NO_CHAR;
      char[] typeCompletion = null;
      if (!exactMatch) {
        typeCompletion =
          isQualified ?
              CharOperation.concat(currentType.qualifiedPackageName(), currentType.qualifiedSourceName(), '.') :
                currentType.sourceName();
        if (this.source != null
              && this.source.length > this.endPosition
              && this.source[this.endPosition] == '(') {
          completion = CharOperation.NO_CHAR;
        } else {
          completion = new char[] { '(', ')' };
        }
      }

      this.noProposal = false;
      if (!exactMatch) {
        if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
          char[] packageName = currentType.isLocalType() ? null : currentType.qualifiedPackageName();
          char[] typeName = currentType.qualifiedSourceName();
         
          InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(currentType));
          proposal.setDeclarationKey(currentType.computeUniqueKey());
          proposal.setSignature(
              createMethodSignature(
                  CharOperation.NO_CHAR_CHAR,
                  CharOperation.NO_CHAR_CHAR,
                  CharOperation.NO_CHAR,
                  CharOperation.NO_CHAR));
          //proposal.setOriginalSignature(null);
          //proposal.setUniqueKey(null);
          proposal.setDeclarationPackageName(packageName);
          proposal.setDeclarationTypeName(typeName);
          //proposal.setParameterPackageNames(null);
          //proposal.setParameterTypeNames(null);
          //proposal.setPackageName(null);
          //proposal.setTypeName(null);
          proposal.setName(currentType.sourceName());
         
          InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
          typeProposal.nameLookup = this.nameEnvironment.nameLookup;
          typeProposal.completionEngine = this;
          typeProposal.setDeclarationSignature(packageName);
          typeProposal.setSignature(getRequiredTypeSignature(currentType));
          typeProposal.setPackageName(packageName);
          typeProposal.setTypeName(typeName);
          typeProposal.setCompletion(typeCompletion);
          typeProposal.setFlags(currentType.modifiers);
          typeProposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
          typeProposal.setRelevance(relevance);
          proposal.setRequiredProposals( new CompletionProposal[]{typeProposal});
               
          proposal.setCompletion(completion);
          proposal.setFlags(Flags.AccPublic);
          proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }  else {
        if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, missingElements != null)) {
          InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(currentType));
          proposal.setDeclarationKey(currentType.computeUniqueKey());
          proposal.setSignature(
              createMethodSignature(
                  CharOperation.NO_CHAR_CHAR,
                  CharOperation.NO_CHAR_CHAR,
                  CharOperation.NO_CHAR,
                  CharOperation.NO_CHAR));
          //proposal.setOriginalSignature(null);
          //proposal.setUniqueKey(null);
          proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
          proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
          //proposal.setParameterPackageNames(null);
          //proposal.setParameterTypeNames(null);
          //proposal.setPackageName(null);
          //proposal.setTypeName(null);
          if (missingElements != null) {
            CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
            for (int i = 0; i < missingElements.length; i++) {
              subProposals[i] =
                createRequiredTypeProposal(
                    missingElements[i],
                    missingElementsStarts[i],
                    missingElementsEnds[i],
                    relevance);
            }
            proposal.setRequiredProposals(subProposals);
          }
          proposal.setCompletion(completion);
          proposal.setFlags(Flags.AccPublic);
          proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenEnd - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    } else {
      findConstructors(
        currentType,
        argTypes,
        scope,
        invocationSite,
        true,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        exactMatch,
        isQualified,
        relevance);
    }
  }
  private void findClassField(
      char[] token,
      TypeBinding receiverType,
      Scope scope,
      Binding[] missingElements,
      int[] missingElementsStarts,
      int[] missingElementsEnds,
      boolean missingElementsHaveProblems) {

    if (token == null) return;

    if (token.length <= classField.length
      && CharOperation.prefixEquals(token, classField, false /* ignore case */
    )) {
      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(token, classField);
      relevance += computeRelevanceForExpectingType(scope.getJavaLangClass());
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); //no access restriction for class field
      relevance += R_NON_INHERITED;

      if (missingElements != null) {
        relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
      }

      this.noProposal = false;
      if(!isIgnored(CompletionProposal.FIELD_REF, missingElements != null)) {
        InternalCompletionProposal proposal = createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
        //proposal.setDeclarationSignature(null);
        char[] signature =
          createNonGenericTypeSignature(
            CharOperation.concatWith(JAVA_LANG, '.'),
            CLASS);
        if (this.compilerOptions.sourceLevel > ClassFileConstants.JDK1_4) {
          // add type argument
          char[] typeArgument = getTypeSignature(receiverType);
          int oldLength = signature.length;
          int argumentLength = typeArgument.length;
          int newLength = oldLength + argumentLength + 2;
          System.arraycopy(signature, 0, signature = new char[newLength], 0, oldLength - 1);
          signature[oldLength - 1] = '<';
          System.arraycopy(typeArgument, 0, signature, oldLength , argumentLength);
          signature[newLength - 2] = '>';
          signature[newLength - 1] = ';';
        }
        proposal.setSignature(signature);
        //proposal.setDeclarationPackageName(null);
        //proposal.setDeclarationTypeName(null);
        proposal.setPackageName(CharOperation.concatWith(JAVA_LANG, '.'));
        proposal.setTypeName(CLASS);
        proposal.setName(classField);
        if (missingElements != null) {
          CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
          for (int i = 0; i < missingElements.length; i++) {
            subProposals[i] =
              createRequiredTypeProposal(
                  missingElements[i],
                  missingElementsStarts[i],
                  missingElementsEnds[i],
                  relevance);
          }
          proposal.setRequiredProposals(subProposals);
        }
        proposal.setCompletion(classField);
        proposal.setFlags(Flags.AccStatic | Flags.AccPublic);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        this.requestor.accept(proposal);
        if(DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
  }
 
  void findConstructors(
    ReferenceBinding currentType,
    TypeBinding[] argTypes,
    Scope scope,
    InvocationSite invocationSite,
    boolean forAnonymousType,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems) {
   
    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution();
    relevance += computeRelevanceForInterestingProposal();
    relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
   
    if (missingElements != null) {
      relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
    }
   
    findConstructors(
        currentType,
        argTypes,
        scope,
        invocationSite,
        forAnonymousType,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        true,
        false,
        relevance);
  }
 
 
  private void findConstructorsFromMissingType(
      TypeReference typeRef,
      final TypeBinding[] argTypes,
      final Scope scope,
      final InvocationSite invocationSite) {
    MissingTypesGuesser missingTypesConverter = new MissingTypesGuesser(this);
    MissingTypesGuesser.GuessedTypeRequestor substitutionRequestor =
      new MissingTypesGuesser.GuessedTypeRequestor() {
        public void accept(
            TypeBinding guessedType,
            Binding[] missingElements,
            int[] missingElementsStarts,
            int[] missingElementsEnds,
            boolean hasProblems) {
          if (guessedType instanceof ReferenceBinding) {
            ReferenceBinding ref = (ReferenceBinding) guessedType;
            if (!isIgnored(CompletionProposal.METHOD_REF, missingElements != null)
                && ref.isClass()
                && !ref.isAbstract()) {
                findConstructors(
                  ref,
                  argTypes,
                  scope,
                  invocationSite,
                  false,
                  missingElements,
                  missingElementsStarts,
                  missingElementsEnds,
                  hasProblems);
            }
               
            checkCancel();
     
            if (!isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, missingElements != null)
                && !ref.isFinal()
                && !ref.isEnum()){
              findAnonymousType(
                ref,
                argTypes,
                scope,
                invocationSite,
                missingElements,
                missingElementsStarts,
                missingElementsEnds,
                hasProblems);
            }
          }
        }
      };
    missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
  }
   
  private void findConstructors(
    ReferenceBinding currentType,
    TypeBinding[] argTypes,
    Scope scope,
    InvocationSite invocationSite,
    boolean forAnonymousType,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    boolean exactMatch,
    boolean isQualified,
    int relevance) {

    // No visibility checks can be performed without the scope & invocationSite
    MethodBinding[] methods = null;
    if (currentType instanceof ParameterizedTypeBinding && invocationSite instanceof CompletionOnQualifiedAllocationExpression) {
      CompletionOnQualifiedAllocationExpression alloc = (CompletionOnQualifiedAllocationExpression) invocationSite;
      if ((alloc.bits & ASTNode.IsDiamond) != 0) {
        // inference failed. So don't substitute type arguments. Just return the unsubstituted methods
        // and let the user decide what to substitute.
        ParameterizedTypeBinding binding = (ParameterizedTypeBinding) currentType;
        ReferenceBinding originalGenericType = binding.genericType();
        if (originalGenericType != null)
          methods = originalGenericType.methods();
      } else {
        methods = currentType.availableMethods();
      }
    } else {
      methods = currentType.availableMethods();
    }
    if(methods != null) {
      int minArgLength = argTypes == null ? 0 : argTypes.length;
      next : for (int f = methods.length; --f >= 0;) {
        MethodBinding constructor = methods[f];
        if (constructor.isConstructor()) {

          if (constructor.isSynthetic()) continue next;

          if (this.options.checkDeprecation &&
              constructor.isViewedAsDeprecated() &&
              !scope.isDefinedInSameUnit(constructor.declaringClass))
            continue next;

          if (this.options.checkVisibility
            && !constructor.canBeSeenBy(invocationSite, scope)) {
            if(!forAnonymousType || !constructor.isProtected())
              continue next;
          }

          TypeBinding[] parameters = constructor.parameters;
          int paramLength = parameters.length;
          if (minArgLength > paramLength)
            continue next;
          for (int a = minArgLength; --a >= 0;)
            if (argTypes[a] != null) { // can be null if it could not be resolved properly
              if (!argTypes[a].isCompatibleWith(constructor.parameters[a]))
                continue next;
            }

          char[][] parameterPackageNames = new char[paramLength][];
          char[][] parameterTypeNames = new char[paramLength][];
          for (int i = 0; i < paramLength; i++) {
            TypeBinding type = parameters[i];
            parameterPackageNames[i] = type.qualifiedPackageName();
            parameterTypeNames[i] = type.qualifiedSourceName();
          }
          char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames);

          char[] completion = CharOperation.NO_CHAR;
         
          if(forAnonymousType){
            char[] typeCompletion = null;
            if (!exactMatch) {
              typeCompletion =
                isQualified ?
                    CharOperation.concat(currentType.qualifiedPackageName(), currentType.qualifiedSourceName(), '.') :
                      currentType.sourceName();
              if (this.source != null
                    && this.source.length > this.endPosition
                    && this.source[this.endPosition] == '(') {
                completion = CharOperation.NO_CHAR;
              } else {
                completion = new char[] { '(', ')' };
              }
            }
           
            this.noProposal = false;
            if (!exactMatch) {
              if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
                char[] packageName = currentType.isLocalType() ? null : currentType.qualifiedPackageName();
                char[] typeName = currentType.qualifiedSourceName();
               
                InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
                proposal.setDeclarationSignature(getSignature(currentType));
                proposal.setDeclarationKey(currentType.computeUniqueKey());
                proposal.setSignature(getSignature(constructor));
                MethodBinding original = constructor.original();
                if(original != constructor) {
                  proposal.setOriginalSignature(getSignature(original));
                }
                proposal.setKey(constructor.computeUniqueKey());
                proposal.setDeclarationPackageName(packageName);
                proposal.setDeclarationTypeName(typeName);
                proposal.setParameterPackageNames(parameterPackageNames);
                proposal.setParameterTypeNames(parameterTypeNames);
                //proposal.setPackageName(null);
                //proposal.setTypeName(null);
                proposal.setName(currentType.sourceName());
               
                InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
                typeProposal.nameLookup = this.nameEnvironment.nameLookup;
                typeProposal.completionEngine = this;
                typeProposal.setDeclarationSignature(packageName);
                typeProposal.setSignature(getRequiredTypeSignature(currentType));
                typeProposal.setPackageName(packageName);
                typeProposal.setTypeName(typeName);
                typeProposal.setCompletion(typeCompletion);
                typeProposal.setFlags(currentType.modifiers);
                typeProposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
                typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
                typeProposal.setRelevance(relevance);
                proposal.setRequiredProposals( new CompletionProposal[]{typeProposal});
               
                proposal.setCompletion(completion);
                proposal.setFlags(constructor.modifiers);
                proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                if(parameterNames != null) proposal.setParameterNames(parameterNames);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            } else {
              if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, missingElements != null)) {
                InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, this.actualCompletionPosition);
                proposal.setDeclarationSignature(getSignature(currentType));
                proposal.setDeclarationKey(currentType.computeUniqueKey());
                proposal.setSignature(getSignature(constructor));
                MethodBinding original = constructor.original();
                if(original != constructor) {
                  proposal.setOriginalSignature(getSignature(original));
                }
                proposal.setKey(constructor.computeUniqueKey());
                proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
                proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
                proposal.setParameterPackageNames(parameterPackageNames);
                proposal.setParameterTypeNames(parameterTypeNames);
                //proposal.setPackageName(null);
                //proposal.setTypeName(null);
                if (missingElements != null) {
                  CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
                  for (int i = 0; i < missingElements.length; i++) {
                    subProposals[i] =
                      createRequiredTypeProposal(
                          missingElements[i],
                          missingElementsStarts[i],
                          missingElementsEnds[i],
                          relevance);
                  }
                  proposal.setRequiredProposals(subProposals);
                }
                proposal.setCompletion(completion);
                proposal.setFlags(constructor.modifiers);
                proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenEnd - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                if(parameterNames != null) proposal.setParameterNames(parameterNames);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            }
          } else {
            char[] typeCompletion = null;
            // Special case for completion in javadoc
            if (this.assistNodeInJavadoc > 0) {
              Expression receiver = null;
              char[] selector = null;
              if (invocationSite instanceof CompletionOnJavadocAllocationExpression) {
                CompletionOnJavadocAllocationExpression alloc = (CompletionOnJavadocAllocationExpression) invocationSite;
                receiver = alloc.type;
              } else if (invocationSite instanceof CompletionOnJavadocFieldReference) {
                CompletionOnJavadocFieldReference fieldRef = (CompletionOnJavadocFieldReference) invocationSite;
                receiver = fieldRef.receiver;
              }
              if (receiver != null) {
                StringBuffer javadocCompletion = new StringBuffer();
                if (receiver.isThis()) {
                  selector = (((JavadocImplicitTypeReference)receiver).token);
                  if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0) {
                    javadocCompletion.append('#');
                  }
                } else if (receiver instanceof JavadocSingleTypeReference) {
                  JavadocSingleTypeReference typeRef = (JavadocSingleTypeReference) receiver;
                  selector = typeRef.token;
                  if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0) {
                    javadocCompletion.append(typeRef.token);
                    javadocCompletion.append('#');
                  }
                } else if (receiver instanceof JavadocQualifiedTypeReference) {
                  JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) receiver;
                  selector = typeRef.tokens[typeRef.tokens.length-1];
                  if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0) {
                    javadocCompletion.append(CharOperation.concatWith(typeRef.tokens, '.'));
                    javadocCompletion.append('#');
                  }
                }
                // Append parameters types
                javadocCompletion.append(selector);
                javadocCompletion.append('(');
                if (constructor.parameters != null) {
                  boolean isVarargs = constructor.isVarargs();
                  for (int p=0, ln=constructor.parameters.length; p<ln; p++) {
                    if (p>0) javadocCompletion.append(", "); //$NON-NLS-1$
                    TypeBinding argTypeBinding = constructor.parameters[p];
                    if (isVarargs && p == ln - 1)  {
                      createVargsType(argTypeBinding.erasure(), scope, javadocCompletion);
                    } else {
                      createType(argTypeBinding.erasure(), scope, javadocCompletion);
                    }
                  }
                }
                javadocCompletion.append(')');
                completion = javadocCompletion.toString().toCharArray();
              }
            } else {
              if (!exactMatch) {
                typeCompletion =
                  isQualified ?
                      CharOperation.concat(currentType.qualifiedPackageName(), currentType.qualifiedSourceName(), '.') :
                        currentType.sourceName();
               
                if (this.source != null
                      && this.source.length > this.endPosition
                      && this.source[this.endPosition] == '(') {
                  completion = CharOperation.NO_CHAR;
                } else {
                  completion = new char[] { '(', ')' };
                }
              }
            }

            // Create standard proposal
            this.noProposal = false;
            if (!exactMatch) {
              if(!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
                char[] packageName = currentType.isLocalType() ? null : currentType.qualifiedPackageName();
                char[] typeName = currentType.qualifiedSourceName();
               
                InternalCompletionProposal proposal =  createProposal(CompletionProposal.CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
                proposal.setDeclarationSignature(getSignature(currentType));
                proposal.setSignature(getSignature(constructor));
                MethodBinding original = constructor.original();
                if(original != constructor) {
                  proposal.setOriginalSignature(getSignature(original));
                }
                proposal.setDeclarationPackageName(packageName);
                proposal.setDeclarationTypeName(typeName);
                proposal.setParameterPackageNames(parameterPackageNames);
                proposal.setParameterTypeNames(parameterTypeNames);
                //proposal.setPackageName(null);
                //proposal.setTypeName(null);
                proposal.setName(currentType.sourceName());
         
                InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
                typeProposal.nameLookup = this.nameEnvironment.nameLookup;
                typeProposal.completionEngine = this;
                typeProposal.setDeclarationSignature(packageName);
                typeProposal.setSignature(getRequiredTypeSignature(currentType));
                typeProposal.setPackageName(packageName);
                typeProposal.setTypeName(typeName);
                typeProposal.setCompletion(typeCompletion);
                typeProposal.setFlags(currentType.modifiers);
                typeProposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
                typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
                typeProposal.setRelevance(relevance);
                proposal.setRequiredProposals( new CompletionProposal[]{typeProposal});
               
                proposal.setIsContructor(true);
                proposal.setCompletion(completion);
                proposal.setFlags(constructor.modifiers);
                proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                if(parameterNames != null) proposal.setParameterNames(parameterNames);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            } else {
              if(!isIgnored(CompletionProposal.METHOD_REF, missingElements != null) && (this.assistNodeInJavadoc & CompletionOnJavadoc.ONLY_INLINE_TAG) == 0) {
                InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
                proposal.setDeclarationSignature(getSignature(currentType));
                proposal.setSignature(getSignature(constructor));
                MethodBinding original = constructor.original();
                if(original != constructor) {
                  proposal.setOriginalSignature(getSignature(original));
                }
                proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
                proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
                proposal.setParameterPackageNames(parameterPackageNames);
                proposal.setParameterTypeNames(parameterTypeNames);
                //proposal.setPackageName(null);
                //proposal.setTypeName(null);
                proposal.setName(currentType.sourceName());
                if (missingElements != null) {
                  CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
                  for (int i = 0; i < missingElements.length; i++) {
                    subProposals[i] =
                      createRequiredTypeProposal(
                          missingElements[i],
                          missingElementsStarts[i],
                          missingElementsEnds[i],
                          relevance);
                  }
                  proposal.setRequiredProposals(subProposals);
                }
                proposal.setIsContructor(true);
                proposal.setCompletion(completion);
                proposal.setFlags(constructor.modifiers);
                int start = (this.assistNodeInJavadoc > 0) ? this.startPosition : this.endPosition;
                proposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                if(parameterNames != null) proposal.setParameterNames(parameterNames);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
              if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_METHOD_REF)) {
                char[] javadocCompletion = inlineTagCompletion(completion, JavadocTagConstants.TAG_LINK);
                InternalCompletionProposal proposal =  createProposal(CompletionProposal.JAVADOC_METHOD_REF, this.actualCompletionPosition);
                proposal.setDeclarationSignature(getSignature(currentType));
                proposal.setSignature(getSignature(constructor));
                MethodBinding original = constructor.original();
                if(original != constructor) {
                  proposal.setOriginalSignature(getSignature(original));
                }
                proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
                proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
                proposal.setParameterPackageNames(parameterPackageNames);
                proposal.setParameterTypeNames(parameterTypeNames);
                //proposal.setPackageName(null);
                //proposal.setTypeName(null);
                proposal.setName(currentType.sourceName());
                proposal.setIsContructor(true);
                proposal.setCompletion(javadocCompletion);
                proposal.setFlags(constructor.modifiers);
                int start = (this.assistNodeInJavadoc & CompletionOnJavadoc.REPLACE_TAG) != 0 ? this.javadocTagPosition : this.startPosition;
                proposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance+R_INLINE_TAG);
                if(parameterNames != null) proposal.setParameterNames(parameterNames);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            }
          }
        }
      }
    }
  }
 
  private char[] getResolvedSignature(char[][] parameterTypes, char[] fullyQualifiedTypeName, int parameterCount, Scope scope) {
    char[][] cn = CharOperation.splitOn('.', fullyQualifiedTypeName);

    TypeReference ref;
    if (cn.length == 1) {
      ref = new SingleTypeReference(cn[0], 0);
    } else {
      ref = new QualifiedTypeReference(cn,new long[cn.length]);
    }
   
    TypeBinding guessedType = null;
    INameEnvironment oldNameEnvironment = this.lookupEnvironment.nameEnvironment;
    this.lookupEnvironment.nameEnvironment = getNoCacheNameEnvironment();
    try {
      switch (scope.kind) {
        case Scope.METHOD_SCOPE :
        case Scope.BLOCK_SCOPE :
          guessedType = ref.resolveType((BlockScope)scope);
          break;
        case Scope.CLASS_SCOPE :
          guessedType = ref.resolveType((ClassScope)scope);
          break;
      }
   

      if (guessedType != null && guessedType.isValidBinding()) {
        // the erasure must be used because guessedType can be a RawTypeBinding (https://bugs.eclipse.org/bugs/show_bug.cgi?id=276890)
        guessedType = guessedType.erasure();
       
        if (guessedType instanceof SourceTypeBinding) {
          SourceTypeBinding refBinding = (SourceTypeBinding) guessedType;
         
          if (refBinding.scope == null || refBinding.scope.referenceContext == null) return null;
         
          TypeDeclaration typeDeclaration = refBinding.scope.referenceContext;
          AbstractMethodDeclaration[] methods = typeDeclaration.methods;
         
          next : for (int i = 0; i < methods.length; i++) {
            AbstractMethodDeclaration method = methods[i];
           
            if (!method.isConstructor()) continue next;
           
            Argument[] arguments = method.arguments;
            int argumentsLength = arguments == null ? 0 : arguments.length;
           
            if (parameterCount != argumentsLength) continue next;
           
            for (int j = 0; j < argumentsLength; j++) {
              char[] argumentTypeName = getTypeName(arguments[j].type);
 
              if (!CharOperation.equals(argumentTypeName, parameterTypes[j])) {
                continue next;
              }
            }
           
            refBinding.resolveTypesFor(method.binding); // force resolution
            if (method.binding == null) continue next;
            return getSignature(method.binding);
          }
        }
      }
    } finally {
      this.lookupEnvironment.nameEnvironment = oldNameEnvironment;
    }
   
    return null;
  }
 
  private void findConstructorsOrAnonymousTypes(
      ReferenceBinding currentType,
      Scope scope,
      InvocationSite invocationSite,
      boolean isQualified,
      int relevance) {
   
    if (!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)
        && currentType.isClass()
        && !currentType.isAbstract()) {
        findConstructors(
          currentType,
          null,
          scope,
          invocationSite,
          false,
          null,
          null,
          null,
          false,
          false,
          isQualified,
          relevance);
    }
   
    // This code is disabled because there is too much proposals when constructors and anonymous are proposed
    if (!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)
        && !currentType.isFinal()
        && (currentType.isInterface() || (currentType.isClass() && currentType.isAbstract()))){
      findAnonymousType(
        currentType,
        null,
        scope,
        invocationSite,
        null,
        null,
        null,
        false,
        false,
        isQualified,
        relevance);
    }
  }
  private char[][] findEnclosingTypeNames(Scope scope){
    char[][] excludedNames = new char[10][];
    int excludedNameCount = 0;

    Scope currentScope = scope;
    while(currentScope != null) {
      switch (currentScope.kind) {
        case Scope.CLASS_SCOPE :
          ClassScope classScope = (ClassScope) currentScope;

          TypeDeclaration typeDeclaration = classScope.referenceContext;

          if(excludedNameCount == excludedNames.length) {
            System.arraycopy(excludedNames, 0, excludedNames = new char[excludedNameCount * 2][], 0, excludedNameCount);
          }
          excludedNames[excludedNameCount++] = typeDeclaration.name;

          TypeParameter[] classTypeParameters = typeDeclaration.typeParameters;
          if(classTypeParameters != null) {
            for (int i = 0; i < classTypeParameters.length; i++) {
              TypeParameter typeParameter = classTypeParameters[i];
              if(excludedNameCount == excludedNames.length) {
                System.arraycopy(excludedNames, 0, excludedNames = new char[excludedNameCount * 2][], 0, excludedNameCount);
              }
              excludedNames[excludedNameCount++] = typeParameter.name;
            }
          }
          break;
        case Scope.METHOD_SCOPE :
          MethodScope methodScope = (MethodScope) currentScope;
          if(methodScope.referenceContext instanceof AbstractMethodDeclaration) {
            TypeParameter[] methodTypeParameters = ((AbstractMethodDeclaration)methodScope.referenceContext).typeParameters();
            if(methodTypeParameters != null) {
              for (int i = 0; i < methodTypeParameters.length; i++) {
                TypeParameter typeParameter = methodTypeParameters[i];
                if(excludedNameCount == excludedNames.length) {
                  System.arraycopy(excludedNames, 0, excludedNames = new char[excludedNameCount * 2][], 0, excludedNameCount);
                }
                excludedNames[excludedNameCount++] = typeParameter.name;
              }
            }
          }
          break;
      }

      currentScope = currentScope.parent;
    }

    if(excludedNameCount == 0) {
      return CharOperation.NO_CHAR_CHAR;
    }
    System.arraycopy(excludedNames, 0, excludedNames = new char[excludedNameCount][], 0, excludedNameCount);
    return excludedNames;
  }
  private void findEnumConstants(
      char[] enumConstantName,
      ReferenceBinding enumType,
      Scope invocationScope,
      ObjectVector fieldsFound,
      char[][] alreadyUsedConstants,
      int alreadyUsedConstantCount,
      boolean needQualification) {

    FieldBinding[] fields = enumType.fields();

    int enumConstantLength = enumConstantName.length;
    next : for (int f = fields.length; --f >= 0;) {
      FieldBinding field = fields[f];

      if (field.isSynthetic()) continue next;

      if ((field.modifiers & Flags.AccEnum) == 0) continue next;

      if (enumConstantLength > field.name.length) continue next;

      if (!CharOperation.prefixEquals(enumConstantName, field.name, false /* ignore case */)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(enumConstantName, field.name)))  continue next;

      char[] fieldName = field.name;

      for (int i = 0; i < alreadyUsedConstantCount; i++) {
        if(CharOperation.equals(alreadyUsedConstants[i], fieldName)) continue next;
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal(field);
      relevance += computeRelevanceForCaseMatching(enumConstantName, field.name);
      relevance += computeRelevanceForExpectingType(field.type);
      relevance += computeRelevanceForEnumConstant(field.type);
      relevance += computeRelevanceForQualification(needQualification);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      this.noProposal = false;
      if (!needQualification) {
        char[] completion = fieldName;

        if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
          InternalCompletionProposal proposal = createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(field.declaringClass));
          proposal.setSignature(getSignature(field.type));
          proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          proposal.setPackageName(field.type.qualifiedPackageName());
          proposal.setTypeName(field.type.qualifiedSourceName());
          proposal.setName(field.name);
          proposal.setCompletion(completion);
          proposal.setFlags(field.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }

      } else {
        TypeBinding visibleType = invocationScope.getType(field.type.sourceName());
        boolean needImport = visibleType == null || !visibleType.isValidBinding();

        char[] completion = CharOperation.concat(field.type.sourceName(), field.name, '.');

        if (!needImport) {
          if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
            InternalCompletionProposal proposal = createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(field.declaringClass));
            proposal.setSignature(getSignature(field.type));
            proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
            proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
            proposal.setPackageName(field.type.qualifiedPackageName());
            proposal.setTypeName(field.type.qualifiedSourceName());
            proposal.setName(field.name);
            proposal.setCompletion(completion);
            proposal.setFlags(field.modifiers);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        } else {
          if (!this.isIgnored(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_IMPORT)) {
            CompilationUnitDeclaration cu = this.unitScope.referenceContext;
            int importStart = cu.types[0].declarationSourceStart;
            int importEnd = importStart;

            ReferenceBinding fieldType = (ReferenceBinding)field.type;

            InternalCompletionProposal proposal = createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(field.declaringClass));
            proposal.setSignature(getSignature(field.type));
            proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
            proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
            proposal.setPackageName(field.type.qualifiedPackageName());
            proposal.setTypeName(field.type.qualifiedSourceName());
            proposal.setName(field.name);
            proposal.setCompletion(completion);
            proposal.setFlags(field.modifiers);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);

            char[] typeImportCompletion = createImportCharArray(CharOperation.concatWith(fieldType.compoundName, '.'), false, false);

            InternalCompletionProposal typeImportProposal = createProposal(CompletionProposal.TYPE_IMPORT, this.actualCompletionPosition);
            typeImportProposal.nameLookup = this.nameEnvironment.nameLookup;
            typeImportProposal.completionEngine = this;
            char[] packageName = fieldType.qualifiedPackageName();
            typeImportProposal.setDeclarationSignature(packageName);
            typeImportProposal.setSignature(getSignature(fieldType));
            typeImportProposal.setPackageName(packageName);
            typeImportProposal.setTypeName(fieldType.qualifiedSourceName());
            typeImportProposal.setCompletion(typeImportCompletion);
            typeImportProposal.setFlags(fieldType.modifiers);
            typeImportProposal.setAdditionalFlags(CompletionFlags.Default);
            typeImportProposal.setReplaceRange(importStart - this.offset, importEnd - this.offset);
            typeImportProposal.setTokenRange(importStart - this.offset, importEnd - this.offset);
            typeImportProposal.setRelevance(relevance);

            proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal});

            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
      }
    }
  }
  private void findEnumConstantsFromExpectedTypes(
      char[] token,
      Scope invocationScope,
      ObjectVector fieldsFound) {
    int length = this.expectedTypesPtr + 1;
    for (int i = 0; i < length; i++) {
      if (this.expectedTypes[i].isEnum()) {
        findEnumConstants(
            token,
            (ReferenceBinding)this.expectedTypes[i],
            invocationScope,
            fieldsFound,
            CharOperation.NO_CHAR_CHAR,
            0,
            true);
      }
    }

  }
  private void findEnumConstantsFromSwithStatement(char[] enumConstantName, SwitchStatement switchStatement) {
    TypeBinding expressionType = switchStatement.expression.resolvedType;
    if(expressionType != null && expressionType.isEnum()) {
      ReferenceBinding enumType = (ReferenceBinding) expressionType;

      CaseStatement[] cases = switchStatement.cases;

      char[][] alreadyUsedConstants = new char[switchStatement.caseCount][];
      int alreadyUsedConstantCount = 0;
      for (int i = 0; i < switchStatement.caseCount; i++) {
        Expression caseExpression = cases[i].constantExpression;
        if((caseExpression instanceof SingleNameReference)
            && (caseExpression.resolvedType != null && caseExpression.resolvedType.isEnum())) {
          alreadyUsedConstants[alreadyUsedConstantCount++] = ((SingleNameReference)cases[i].constantExpression).token;
        }
      }

      findEnumConstants(
          enumConstantName,
          enumType,
          null /* doesn't need invocation scope */,
          new ObjectVector(),
          alreadyUsedConstants,
          alreadyUsedConstantCount,
          false);
    }
  }
  private void findExceptionFromTryStatement(
      char[] typeName,
      ReferenceBinding exceptionType,
      ReferenceBinding receiverType,
      SourceTypeBinding invocationType,
      BlockScope scope,
      ObjectVector typesFound,
      boolean searchSuperClasses) {

    if (searchSuperClasses) {
      ReferenceBinding javaLangThrowable = scope.getJavaLangThrowable();
      if (exceptionType != javaLangThrowable) {
        ReferenceBinding superClass = exceptionType.superclass();
        while(superClass != null && superClass != javaLangThrowable) {
          findExceptionFromTryStatement(typeName, superClass, receiverType, invocationType, scope, typesFound, false);
          superClass = superClass.superclass();
        }
      }
    }

    if (typeName.length > exceptionType.sourceName.length)
      return;

    if (!CharOperation.prefixEquals(typeName, exceptionType.sourceName, false/* ignore case */)
        && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, exceptionType.sourceName)))
      return;

    if (this.options.checkDeprecation &&
        exceptionType.isViewedAsDeprecated() &&
        !scope.isDefinedInSameUnit(exceptionType))
      return;

    if (this.options.checkVisibility) {
      if (invocationType != null) {
        if (receiverType != null) {
          if (!exceptionType.canBeSeenBy(receiverType, invocationType)) return;
        } else {
          if (!exceptionType.canBeSeenBy(exceptionType, invocationType)) return;
        }
      } else if(!exceptionType.canBeSeenBy(this.unitScope.fPackage)) {
        return;
      }
    }
   
    if (isForbidden(exceptionType)) return;

    for (int j = typesFound.size; --j >= 0;) {
      ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j);

      if (exceptionType == otherType)
        return;

      if (CharOperation.equals(exceptionType.sourceName, otherType.sourceName, true)) {

        if (exceptionType.enclosingType().isSuperclassOf(otherType.enclosingType()))
          return;

        if (otherType.enclosingType().isInterface())
          if (exceptionType.enclosingType()
            .implementsInterface(otherType.enclosingType(), true))
            return;

        if (exceptionType.enclosingType().isInterface())
          if (otherType.enclosingType()
            .implementsInterface(exceptionType.enclosingType(), true))
            return;
      }
    }

    typesFound.add(exceptionType);

    char[] completionName = exceptionType.sourceName();

    boolean isQualified = false;

    if(!this.insideQualifiedReference) {
      isQualified = true;

      char[] memberPackageName = exceptionType.qualifiedPackageName();
      char[] memberTypeName = exceptionType.sourceName();
      char[] memberEnclosingTypeNames = null;

      ReferenceBinding enclosingType = exceptionType.enclosingType();
      if (enclosingType != null) {
        memberEnclosingTypeNames = exceptionType.enclosingType().qualifiedSourceName();
      }

      Scope currentScope = scope;
      done : while (currentScope != null) { // done when a COMPILATION_UNIT_SCOPE is found

        switch (currentScope.kind) {

          case Scope.METHOD_SCOPE :
          case Scope.BLOCK_SCOPE :
            BlockScope blockScope = (BlockScope) currentScope;

            for (int j = 0, length = blockScope.subscopeCount; j < length; j++) {

              if (blockScope.subscopes[j] instanceof ClassScope) {
                SourceTypeBinding localType =
                  ((ClassScope) blockScope.subscopes[j]).referenceContext.binding;

                if (localType == exceptionType) {
                  isQualified = false;
                  break done;
                }
              }
            }
            break;

          case Scope.CLASS_SCOPE :
            SourceTypeBinding type = ((ClassScope)currentScope).referenceContext.binding;
            ReferenceBinding[] memberTypes = type.memberTypes();
            if (memberTypes != null) {
              for (int j = 0; j < memberTypes.length; j++) {
                if (memberTypes[j] == exceptionType) {
                  isQualified = false;
                  break done;
                }
              }
            }


            break;

          case Scope.COMPILATION_UNIT_SCOPE :
            SourceTypeBinding[] types = ((CompilationUnitScope)currentScope).topLevelTypes;
            if (types != null) {
              for (int j = 0; j < types.length; j++) {
                if (types[j] == exceptionType) {
                  isQualified = false;
                  break done;
                }
              }
            }
            break done;
        }
        currentScope = currentScope.parent;
      }

      if (isQualified && mustQualifyType(memberPackageName, memberTypeName, memberEnclosingTypeNames, exceptionType.modifiers)) {
        if (memberPackageName == null || memberPackageName.length == 0)
          if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
            return; // ignore types from the default package from outside it
      } else {
        isQualified = false;
      }

      if (isQualified) {
        completionName =
          CharOperation.concat(
              memberPackageName,
              CharOperation.concat(
                  memberEnclosingTypeNames,
                  memberTypeName,
                  '.'),
              '.');
      }
    }

    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution();
    relevance += computeRelevanceForInterestingProposal(exceptionType);
    relevance += computeRelevanceForCaseMatching(typeName, exceptionType.sourceName);
    relevance += computeRelevanceForExpectingType(exceptionType);
    relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
    if(!this.insideQualifiedReference) {
      relevance += computeRelevanceForQualification(isQualified);
    }
    relevance += computeRelevanceForClass();
    relevance += computeRelevanceForException();

    this.noProposal = false;
    if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      createTypeProposal(
          exceptionType,
          exceptionType.qualifiedSourceName(),
          IAccessRule.K_ACCESSIBLE,
          completionName,
          relevance,
          null,
          null,
          null,
          false);
    }
  }
  private void findExceptionFromTryStatement(
      char[] typeName,
      ReferenceBinding receiverType,
      SourceTypeBinding invocationType,
      BlockScope scope,
      ObjectVector typesFound) {

    for (int i = 0; i <= this.expectedTypesPtr; i++) {
      ReferenceBinding exceptionType = (ReferenceBinding)this.expectedTypes[i];

      findExceptionFromTryStatement(typeName, exceptionType, receiverType, invocationType, scope, typesFound, true);
    }
  }
  private void findExplicitConstructors(
    char[] name,
    ReferenceBinding currentType,
    MethodScope scope,
    InvocationSite invocationSite) {

    ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration)scope.referenceContext;
    MethodBinding enclosingConstructor = constructorDeclaration.binding;

    // No visibility checks can be performed without the scope & invocationSite
    MethodBinding[] methods = currentType.availableMethods();
    if(methods != null) {
      next : for (int f = methods.length; --f >= 0;) {
        MethodBinding constructor = methods[f];
        if (constructor != enclosingConstructor && constructor.isConstructor()) {

          if (constructor.isSynthetic()) continue next;

          if (this.options.checkDeprecation &&
              constructor.isViewedAsDeprecated() &&
              !scope.isDefinedInSameUnit(constructor.declaringClass))
            continue next;

          if (this.options.checkVisibility
            && !constructor.canBeSeenBy(invocationSite, scope))  continue next;

          TypeBinding[] parameters = constructor.parameters;
          int paramLength = parameters.length;

          char[][] parameterPackageNames = new char[paramLength][];
          char[][] parameterTypeNames = new char[paramLength][];
          for (int i = 0; i < paramLength; i++) {
            TypeBinding type = parameters[i];
            parameterPackageNames[i] = type.qualifiedPackageName();
            parameterTypeNames[i] = type.qualifiedSourceName();
          }
          char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames);

          char[] completion = CharOperation.NO_CHAR;
          if (this.source != null
            && this.source.length > this.endPosition
            && this.source[this.endPosition] == '(')
            completion = name;
          else
            completion = CharOperation.concat(name, new char[] { '(', ')' });

          int relevance = computeBaseRelevance();
          relevance += computeRelevanceForResolution();
          relevance += computeRelevanceForInterestingProposal();
          relevance += computeRelevanceForCaseMatching(this.completionToken, name);
          relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

          this.noProposal = false;
          if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(currentType));
            proposal.setSignature(getSignature(constructor));
            MethodBinding original = constructor.original();
            if(original != constructor) {
              proposal.setOriginalSignature(getSignature(original));
            }
            proposal.setDeclarationPackageName(currentType.qualifiedPackageName());
            proposal.setDeclarationTypeName(currentType.qualifiedSourceName());
            proposal.setParameterPackageNames(parameterPackageNames);
            proposal.setParameterTypeNames(parameterTypeNames);
            //proposal.setPackageName(null);
            //proposal.setTypeName(null);
            proposal.setName(name);
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(constructor.modifiers);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            if(parameterNames != null) proposal.setParameterNames(parameterNames);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
      }
    }
  }
  // Helper method for findFields(char[], ReferenceBinding, Scope, ObjectVector, boolean)
  private void findFields(
    char[] fieldName,
    FieldBinding[] fields,
    Scope scope,
    ObjectVector fieldsFound,
    ObjectVector localsFound,
    boolean onlyStaticFields,
    ReferenceBinding receiverType,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean implicitCall,
    boolean canBePrefixed,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    char[] castedReceiver,
    int receiverStart,
    int receiverEnd) {

    ObjectVector newFieldsFound = new ObjectVector();
    // if the proposal is being asked inside a field's initialization, we'll record its id
    int fieldBeingCompletedId = -1;
    boolean isFieldBeingCompletedStatic = false;
    for (int f = fields.length; --f >=0;) {
      FieldBinding field = fields[f];
      FieldDeclaration fieldDeclaration = field.sourceField();
      // We maybe asking for a proposal inside this field's initialization. So record its id
      ASTNode astNode = this.parser.assistNode;
      if (fieldDeclaration != null && fieldDeclaration.initialization != null && astNode != null) {
        if (fieldDeclaration.initialization.sourceEnd > 0) {
          if (fieldDeclaration.initialization.sourceStart <= astNode.sourceStart &&
            astNode.sourceEnd <= fieldDeclaration.initialization.sourceEnd) {
            // completion is inside a field initializer
            fieldBeingCompletedId = field.id;
            isFieldBeingCompletedStatic = field.isStatic();
            break;
          }
        } else { // The sourceEnd may not yet be set
          CompletionNodeDetector detector = new CompletionNodeDetector(astNode, fieldDeclaration.initialization);
          if (detector.containsCompletionNode()) {  // completion is inside a field initializer
            fieldBeingCompletedId = field.id;
            isFieldBeingCompletedStatic = field.isStatic();
            break;
          }
        }
      }
    }
    // Inherited fields which are hidden by subclasses are filtered out
    // No visibility checks can be performed without the scope & invocationSite

    int fieldLength = fieldName.length;
    next : for (int f = fields.length; --f >= 0;) {
      FieldBinding field = fields[f];
     
      // Content assist invoked inside some field's initialization.
      // bug 310427 and 325481
      if (fieldBeingCompletedId >= 0 && field.id >= fieldBeingCompletedId) {
        // Don't propose field which is being declared currently
        // Don't propose fields declared after the current field declaration statement
        // Though, if field is static, then it can be still be proposed
        if (!field.isStatic()) {
          continue next;
        } else if (isFieldBeingCompletedStatic) {
          // static fields can't be proposed before they are actually declared if the
          // field currently being declared is also static
          continue next;
        }
      }
     
      if (field.isSynthetic())  continue next;

      if (onlyStaticFields && !field.isStatic()) continue next;

      if (fieldLength > field.name.length) continue next;

      if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name)))  continue next;

      if (this.options.checkDeprecation &&
          field.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(field.declaringClass))
        continue next;

      if (this.options.checkVisibility
        && !field.canBeSeenBy(receiverType, invocationSite, scope))  continue next;
     
      // don't propose non constant fields or strings (1.6 or below) in case expression
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343342
      if (this.assistNodeIsInsideCase) {
        if (field.isFinal() && field.isStatic()) {
          if (this.assistNodeIsString){
            if (field.type == null || field.type.id != TypeIds.T_JavaLangString)
              continue next;
          } else if (!(field.type instanceof BaseTypeBinding))
            continue next;
        } else {
          continue next; // non-constants not allowed in case. 
        }
      }

      boolean prefixRequired = false;

      for (int i = fieldsFound.size; --i >= 0;) {
        Object[] other = (Object[])fieldsFound.elementAt(i);
        FieldBinding otherField = (FieldBinding) other[0];
        ReferenceBinding otherReceiverType = (ReferenceBinding) other[1];
        if (field == otherField && receiverType == otherReceiverType)
          continue next;
        if (CharOperation.equals(field.name, otherField.name, true)) {
          if (field.declaringClass.isSuperclassOf(otherField.declaringClass))
            continue next;
          if (otherField.declaringClass.isInterface()) {
            if (field.declaringClass == scope.getJavaLangObject())
              continue next;
            if (field.declaringClass.implementsInterface(otherField.declaringClass, true))
              continue next;
          }
          if (field.declaringClass.isInterface())
            if (otherField.declaringClass.implementsInterface(field.declaringClass, true))
              continue next;
          if(canBePrefixed) {
            prefixRequired = true;
          } else {
            continue next;
          }
        }
      }

      for (int l = localsFound.size; --l >= 0;) {
        LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l);

        if (CharOperation.equals(field.name, local.name, true)) {
          SourceTypeBinding declarationType = scope.enclosingSourceType();
          if (declarationType.isAnonymousType() && declarationType != invocationScope.enclosingSourceType()) {
            continue next;
          }
          if(canBePrefixed) {
            prefixRequired = true;
          } else {
            continue next;
          }
          break;
        }
      }

      newFieldsFound.add(new Object[]{field, receiverType});

      char[] completion = field.name;

      if(prefixRequired || this.options.forceImplicitQualification){
        char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), field.isStatic());
        completion = CharOperation.concat(prefix,completion,'.');
      }


      if (castedReceiver != null) {
        completion = CharOperation.concat(castedReceiver, completion);
      }

      // Special case for javadoc completion
      if (this.assistNodeInJavadoc > 0) {
        if (invocationSite instanceof CompletionOnJavadocFieldReference) {
          CompletionOnJavadocFieldReference fieldRef = (CompletionOnJavadocFieldReference) invocationSite;
          if (fieldRef.receiver.isThis()) {
            if (fieldRef.completeInText()) {
              completion = CharOperation.concat(new char[] { '#' }, field.name);
            }
          } else if (fieldRef.completeInText()) {
            if (fieldRef.receiver instanceof JavadocSingleTypeReference) {
              JavadocSingleTypeReference typeRef = (JavadocSingleTypeReference) fieldRef.receiver;
              completion = CharOperation.concat(typeRef.token, field.name, '#');
            } else if (fieldRef.receiver instanceof JavadocQualifiedTypeReference) {
              JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) fieldRef.receiver;
              completion = CharOperation.concat(CharOperation.concatWith(typeRef.tokens, '.'), field.name, '#');
            }
          }
        }
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal(field);
      relevance += computeRelevanceForCaseMatching(fieldName, field.name);
      relevance += computeRelevanceForExpectingType(field.type);
      relevance += computeRelevanceForEnumConstant(field.type);
      relevance += computeRelevanceForStatic(onlyStaticFields, field.isStatic());
      relevance += computeRelevanceForFinal(this.assistNodeIsInsideCase, field.isFinal());
      relevance += computeRelevanceForQualification(prefixRequired);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
      if (onlyStaticFields && this.insideQualifiedReference) {
        relevance += computeRelevanceForInheritance(receiverType, field.declaringClass);
      }
      if (missingElements != null) {
        relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
      }

      this.noProposal = false;
      if (castedReceiver == null) {
        // Standard proposal
        if (!this.isIgnored(CompletionProposal.FIELD_REF, missingElements != null) && (this.assistNodeInJavadoc & CompletionOnJavadoc.ONLY_INLINE_TAG) == 0) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(field.declaringClass));
          proposal.setSignature(getSignature(field.type));
          proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          proposal.setPackageName(field.type.qualifiedPackageName());
          proposal.setTypeName(field.type.qualifiedSourceName());
          proposal.setName(field.name);
          if (missingElements != null) {
            CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
            for (int i = 0; i < missingElements.length; i++) {
              subProposals[i] =
                createRequiredTypeProposal(
                    missingElements[i],
                    missingElementsStarts[i],
                    missingElementsEnds[i],
                    relevance);
            }
            proposal.setRequiredProposals(subProposals);
          }
          proposal.setCompletion(completion);
          proposal.setFlags(field.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }

        // Javadoc completions
        if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_FIELD_REF)) {
          char[] javadocCompletion = inlineTagCompletion(completion, JavadocTagConstants.TAG_LINK);
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.JAVADOC_FIELD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(field.declaringClass));
          proposal.setSignature(getSignature(field.type));
          proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          proposal.setPackageName(field.type.qualifiedPackageName());
          proposal.setTypeName(field.type.qualifiedSourceName());
          proposal.setName(field.name);
          proposal.setCompletion(javadocCompletion);
          proposal.setFlags(field.modifiers);
          int start = (this.assistNodeInJavadoc & CompletionOnJavadoc.REPLACE_TAG) != 0 ? this.javadocTagPosition : this.startPosition;
          proposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance+R_INLINE_TAG);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
          // Javadoc value completion for static fields
          if (field.isStatic() && !this.requestor.isIgnored(CompletionProposal.JAVADOC_VALUE_REF)) {
            javadocCompletion = inlineTagCompletion(completion, JavadocTagConstants.TAG_VALUE);
            InternalCompletionProposal valueProposal = createProposal(CompletionProposal.JAVADOC_VALUE_REF, this.actualCompletionPosition);
            valueProposal.setDeclarationSignature(getSignature(field.declaringClass));
            valueProposal.setSignature(getSignature(field.type));
            valueProposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
            valueProposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
            valueProposal.setPackageName(field.type.qualifiedPackageName());
            valueProposal.setTypeName(field.type.qualifiedSourceName());
            valueProposal.setName(field.name);
            valueProposal.setCompletion(javadocCompletion);
            valueProposal.setFlags(field.modifiers);
            valueProposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
            valueProposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            valueProposal.setRelevance(relevance+R_VALUE_TAG);
            this.requestor.accept(valueProposal);
            if(DEBUG) {
              this.printDebug(valueProposal);
            }
          }
        }
      } else {
        if(!this.isIgnored(CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER, missingElements != null)) {
          InternalCompletionProposal proposal = createProposal(CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(field.declaringClass));
          proposal.setSignature(getSignature(field.type));
          proposal.setReceiverSignature(getSignature(receiverType));
          proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          proposal.setPackageName(field.type.qualifiedPackageName());
          proposal.setTypeName(field.type.qualifiedSourceName());
          proposal.setName(field.name);
          if (missingElements != null) {
            CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
            for (int i = 0; i < missingElements.length; i++) {
              subProposals[i] =
                createRequiredTypeProposal(
                    missingElements[i],
                    missingElementsStarts[i],
                    missingElementsEnds[i],
                    relevance);
            }
            proposal.setRequiredProposals(subProposals);
          }
          proposal.setCompletion(completion);
          proposal.setFlags(field.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setReceiverRange(receiverStart - this.offset, receiverEnd - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    }

    fieldsFound.addAll(newFieldsFound);
  }
  private void findFields(
    char[] fieldName,
    ReferenceBinding receiverType,
    Scope scope,
    ObjectVector fieldsFound,
    ObjectVector localsFound,
    boolean onlyStaticFields,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean implicitCall,
    boolean canBePrefixed,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    char[] castedReceiver,
    int receiverStart,
    int receiverEnd) {

    boolean notInJavadoc = this.assistNodeInJavadoc == 0;
    if (fieldName == null && notInJavadoc)
      return;

    ReferenceBinding currentType = receiverType;
    ReferenceBinding[] interfacesToVisit = null;
    int nextPosition = 0;
    do {
      ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
      if (notInJavadoc && itsInterfaces != Binding.NO_SUPERINTERFACES) {
        if (interfacesToVisit == null) {
          interfacesToVisit = itsInterfaces;
          nextPosition = interfacesToVisit.length;
        } else {
          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;
          }
        }
      }

      FieldBinding[] fields = currentType.availableFields();
      if(fields != null && fields.length > 0) {
        findFields(
          fieldName,
          fields,
          scope,
          fieldsFound,
          localsFound,
          onlyStaticFields,
          receiverType,
          invocationSite,
          invocationScope,
          implicitCall,
          canBePrefixed,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems,
          castedReceiver,
          receiverStart,
          receiverEnd);
      }
      currentType = currentType.superclass();
    } while (notInJavadoc && currentType != null);

    if (notInJavadoc && interfacesToVisit != null) {
      for (int i = 0; i < nextPosition; i++) {
        ReferenceBinding anInterface = interfacesToVisit[i];
        FieldBinding[] fields = anInterface.availableFields();
        if(fields !=  null) {
          findFields(
            fieldName,
            fields,
            scope,
            fieldsFound,
            localsFound,
            onlyStaticFields,
            receiverType,
            invocationSite,
            invocationScope,
            implicitCall,
            canBePrefixed,
            missingElements,
            missingElementsStarts,
            missingElementsEnds,
            missingElementsHaveProblems,
            castedReceiver,
            receiverStart,
            receiverEnd);
        }

        ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
        if (itsInterfaces != 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;
          }
        }
      }
    }
  }

  protected void findFieldsAndMethods(
    char[] token,
    TypeBinding receiverType,
    Scope scope,
    ObjectVector fieldsFound,
    ObjectVector methodsFound,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean implicitCall,
    boolean superCall,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    char[] castedReceiver,
    int receiverStart,
    int receiverEnd) {

    if (token == null)
      return;

    if (receiverType.isBaseType())
      return; // nothing else is possible with base types

    boolean proposeField =
      castedReceiver == null ?
          !this.isIgnored(CompletionProposal.FIELD_REF, missingElements != null) :
          !this.isIgnored(CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER, missingElements != null) ;
    boolean proposeMethod =
      castedReceiver == null ?
          !this.isIgnored(CompletionProposal.METHOD_REF, missingElements != null) :
          !this.isIgnored(CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER, missingElements != null);

    if (receiverType.isArrayType()) {
      if (proposeField
        && token.length <= lengthField.length
        && CharOperation.prefixEquals(token, lengthField, false /* ignore case */
      )) {

        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal();
        relevance += computeRelevanceForCaseMatching(token,lengthField);
        relevance += computeRelevanceForExpectingType(TypeBinding.INT);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for length field
        if (missingElements != null) {
          relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
        }
        this.noProposal = false;
        if (castedReceiver == null) {
          if(!isIgnored(CompletionProposal.FIELD_REF, missingElements != null)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(receiverType));
            proposal.setSignature(INT_SIGNATURE);
            proposal.setTypeName(INT);
            proposal.setName(lengthField);
            if (missingElements != null) {
              CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
              for (int i = 0; i < missingElements.length; i++) {
                subProposals[i] =
                  createRequiredTypeProposal(
                      missingElements[i],
                      missingElementsStarts[i],
                      missingElementsEnds[i],
                      relevance);
              }
              proposal.setRequiredProposals(subProposals);
            }
            proposal.setCompletion(lengthField);
            proposal.setFlags(Flags.AccPublic);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        } else {
          char[] completion = CharOperation.concat(castedReceiver, lengthField);

          if(!this.isIgnored(CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER, missingElements != null)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(receiverType));
            proposal.setSignature(INT_SIGNATURE);
            proposal.setReceiverSignature(getSignature(receiverType));
            proposal.setTypeName(INT);
            proposal.setName(lengthField);
            if (missingElements != null) {
              CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
              for (int i = 0; i < missingElements.length; i++) {
                subProposals[i] =
                  createRequiredTypeProposal(
                      missingElements[i],
                      missingElementsStarts[i],
                      missingElementsEnds[i],
                      relevance);
              }
              proposal.setRequiredProposals(subProposals);
            }
            proposal.setCompletion(completion);
            proposal.setFlags(Flags.AccPublic);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setReceiverRange(receiverStart - this.offset, receiverEnd - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
      }
      if (proposeMethod
        && token.length <= cloneMethod.length
        && CharOperation.prefixEquals(token, cloneMethod, false /* ignore case */)
      ) {
        ReferenceBinding objectRef = scope.getJavaLangObject();

        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal();
        relevance += computeRelevanceForCaseMatching(token, cloneMethod);
        relevance += computeRelevanceForExpectingType(objectRef);
        relevance += computeRelevanceForStatic(false, false);
        relevance += computeRelevanceForQualification(false);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for clone() method
        if (missingElements != null) {
          relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
        }
        char[] completion;
        if (this.source != null
          && this.source.length > this.endPosition
          && this.source[this.endPosition] == '(') {
          completion = cloneMethod;
          } else {
          completion = CharOperation.concat(cloneMethod, new char[] { '(', ')' });
        }

        if (castedReceiver != null) {
          completion = CharOperation.concat(castedReceiver, completion);
        }

        this.noProposal = false;
        if (castedReceiver == null) {
          if (!this.isIgnored(CompletionProposal.METHOD_REF, missingElements != null)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(receiverType));
            proposal.setSignature(
                this.compilerOptions.sourceLevel > ClassFileConstants.JDK1_4 && receiverType.isArrayType() ?
                    createMethodSignature(
                        CharOperation.NO_CHAR_CHAR,
                        CharOperation.NO_CHAR_CHAR,
                        getSignature(receiverType)) :
                    createMethodSignature(
                        CharOperation.NO_CHAR_CHAR,
                        CharOperation.NO_CHAR_CHAR,
                        CharOperation.concatWith(JAVA_LANG, '.'),
                        OBJECT));
            //proposal.setOriginalSignature(null);
            //proposal.setDeclarationPackageName(null);
            //proposal.setDeclarationTypeName(null);
            //proposal.setParameterPackageNames(null);
            //proposal.setParameterTypeNames(null);
            proposal.setPackageName(CharOperation.concatWith(JAVA_LANG, '.'));
            proposal.setTypeName(OBJECT);
            proposal.setName(cloneMethod);
            if (missingElements != null) {
              CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
              for (int i = 0; i < missingElements.length; i++) {
                subProposals[i] =
                  createRequiredTypeProposal(
                      missingElements[i],
                      missingElementsStarts[i],
                      missingElementsEnds[i],
                      relevance);
              }
              proposal.setRequiredProposals(subProposals);
            }
            proposal.setCompletion(completion);
            proposal.setFlags(Flags.AccPublic);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
          methodsFound.add(new Object[]{objectRef.getMethods(cloneMethod)[0], objectRef});
        } else {
          if(!this.isIgnored(CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER, missingElements != null)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(receiverType));
            proposal.setSignature(
                this.compilerOptions.sourceLevel > ClassFileConstants.JDK1_4 && receiverType.isArrayType() ?
                    createMethodSignature(
                        CharOperation.NO_CHAR_CHAR,
                        CharOperation.NO_CHAR_CHAR,
                        getSignature(receiverType)) :
                    createMethodSignature(
                        CharOperation.NO_CHAR_CHAR,
                        CharOperation.NO_CHAR_CHAR,
                        CharOperation.concatWith(JAVA_LANG, '.'),
                        OBJECT));
            proposal.setReceiverSignature(getSignature(receiverType));
            proposal.setPackageName(CharOperation.concatWith(JAVA_LANG, '.'));
            proposal.setTypeName(OBJECT);
            proposal.setName(cloneMethod);
            if (missingElements != null) {
              CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
              for (int i = 0; i < missingElements.length; i++) {
                subProposals[i] =
                  createRequiredTypeProposal(
                      missingElements[i],
                      missingElementsStarts[i],
                      missingElementsEnds[i],
                      relevance);
              }
              proposal.setRequiredProposals(subProposals);
            }
            proposal.setCompletion(completion);
            proposal.setFlags(Flags.AccPublic);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setReceiverRange(receiverStart - this.offset, receiverEnd - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
      }

      receiverType = scope.getJavaLangObject();
    }
   
    checkCancel();
   
    if(proposeField) {
      findFields(
        token,
        (ReferenceBinding) receiverType,
        scope,
        fieldsFound,
        new ObjectVector(),
        false,
        invocationSite,
        invocationScope,
        implicitCall,
        false,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        castedReceiver,
        receiverStart,
        receiverEnd);
    }

    if(proposeMethod) {
      findMethods(
        token,
        null,
        null,
        (ReferenceBinding) receiverType,
        scope,
        methodsFound,
        false,
        false,
        invocationSite,
        invocationScope,
        implicitCall,
        superCall,
        false,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        castedReceiver,
        receiverStart,
        receiverEnd);
    }
  }

  protected void findFieldsAndMethodsFromAnotherReceiver(
      char[] token,
      TypeReference receiverType,
      Scope scope,
      ObjectVector fieldsFound,
      ObjectVector methodsFound,
      InvocationSite invocationSite,
      Scope invocationScope,
      boolean implicitCall,
      boolean superCall,
      Binding[] missingElements,
      int[] missingElementsStarts,
      int[] missingElementsEnds,
      boolean missingElementsHaveProblems,
      char[][] receiverName,
      int receiverStart,
      int receiverEnd) {

    if (receiverType.resolvedType == null) return;

    TypeBinding receiverTypeBinding = receiverType.resolvedType;
    char[] castedReceiver = null;

    char[] castedTypeChars = CharOperation.concatWith(receiverType.getTypeName(), '.');
    if(this.source != null) {
      int memberRefStart = this.startPosition;

      char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd);
      char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart);

      castedReceiver =
        CharOperation.concat(
          CharOperation.concat(
            '(',
            CharOperation.concat(
              CharOperation.concat('(', castedTypeChars, ')'),
              receiverChars),
            ')'),
          dotChars);
    } else {
      castedReceiver =
        CharOperation.concat(
          CharOperation.concat(
            '(',
            CharOperation.concat(
              CharOperation.concat('(', castedTypeChars, ')'),
              CharOperation.concatWith(receiverName, '.')),
            ')'),
          DOT);
    }

    if (castedReceiver == null) return;

    int oldStartPosition = this.startPosition;
    this.startPosition = receiverStart;

    findFieldsAndMethods(
        token,
        receiverTypeBinding,
        scope,
        fieldsFound,
        methodsFound,
        invocationSite,
        invocationScope,
        implicitCall,
        superCall,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        castedReceiver,
        receiverStart,
        receiverEnd);

    this.startPosition = oldStartPosition;
  }
  private void findFieldsAndMethodsFromCastedReceiver(
      ASTNode enclosingNode,
      Binding qualifiedBinding,
      Scope scope,
      ObjectVector fieldsFound,
      ObjectVector methodsFound,
      InvocationSite invocationSite,
      Scope invocationScope,
      Expression receiver) {

    if (enclosingNode == null || !(enclosingNode instanceof IfStatement)) return;

    IfStatement ifStatement = (IfStatement)enclosingNode;
    while (true) {
      if (!(ifStatement.condition instanceof InstanceOfExpression)) return;
 
      InstanceOfExpression instanceOfExpression = (InstanceOfExpression) ifStatement.condition;
 
      TypeReference instanceOfType = instanceOfExpression.type;
 
      if (instanceOfType.resolvedType == null) return;
 
      boolean findFromAnotherReceiver = false;
 
      char[][] receiverName = null;
      int receiverStart = -1;
      int receiverEnd = -1;
 
      if (receiver instanceof QualifiedNameReference) {
        QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) receiver;
 
        receiverName = qualifiedNameReference.tokens;
 
        if (receiverName.length != 1) return;
 
        receiverStart = (int) (qualifiedNameReference.sourcePositions[0] >>> 32);
        receiverEnd = (int) qualifiedNameReference.sourcePositions[qualifiedNameReference.tokens.length - 1] + 1;
 
        // if (local instanceof X) local.|
        // if (field instanceof X) field.|
        if (instanceOfExpression.expression instanceof SingleNameReference &&
            ((SingleNameReference)instanceOfExpression.expression).binding == qualifiedBinding &&
            (qualifiedBinding instanceof LocalVariableBinding || qualifiedBinding instanceof FieldBinding)) {
          findFromAnotherReceiver = true;
        }
 
        // if (this.field instanceof X) field.|
        if (instanceOfExpression.expression instanceof FieldReference) {
          FieldReference fieldReference = (FieldReference)instanceOfExpression.expression;
 
          if (fieldReference.receiver instanceof ThisReference &&
              qualifiedBinding instanceof FieldBinding &&
              fieldReference.binding == qualifiedBinding) {
                findFromAnotherReceiver = true;
          }
        }
      } else if (receiver instanceof FieldReference) {
        FieldReference fieldReference1 = (FieldReference) receiver;
 
        receiverStart = fieldReference1.sourceStart;
        receiverEnd = fieldReference1.sourceEnd + 1;
 
        if (fieldReference1.receiver instanceof ThisReference) {
 
          receiverName = new char[][] {THIS, fieldReference1.token};
 
          // if (field instanceof X) this.field.|
          if (instanceOfExpression.expression instanceof SingleNameReference &&
              ((SingleNameReference)instanceOfExpression.expression).binding == fieldReference1.binding) {
            findFromAnotherReceiver = true;
          }
 
          // if (this.field instanceof X) this.field.|
          if (instanceOfExpression.expression instanceof FieldReference) {
            FieldReference fieldReference2 = (FieldReference)instanceOfExpression.expression;
 
            if (fieldReference2.receiver instanceof ThisReference &&
                fieldReference2.binding == fieldReference1.binding) {
                  findFromAnotherReceiver = true;
            }
          }
        }
      }
 
      if (findFromAnotherReceiver) {
        TypeBinding receiverTypeBinding = instanceOfType.resolvedType;
        char[] castedReceiver = null;
 
        char[] castedTypeChars = CharOperation.concatWith(instanceOfType.getTypeName(), '.');
        if(this.source != null) {
          int memberRefStart = this.startPosition;
 
          char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd);
          char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart);
 
          castedReceiver =
            CharOperation.concat(
              CharOperation.concat(
                '(',
                CharOperation.concat(
                  CharOperation.concat('(', castedTypeChars, ')'),
                  receiverChars),
                ')'),
              dotChars);
        } else {
          castedReceiver =
            CharOperation.concat(
              CharOperation.concat(
                '(',
                CharOperation.concat(
                  CharOperation.concat('(', castedTypeChars, ')'),
                  CharOperation.concatWith(receiverName, '.')),
                ')'),
              DOT);
        }
 
        if (castedReceiver == null) return;
 
        int oldStartPosition = this.startPosition;
        this.startPosition = receiverStart;
 
        findFieldsAndMethods(
            this.completionToken,
            receiverTypeBinding,
            scope,
            fieldsFound,
            methodsFound,
            invocationSite,
            invocationScope,
            false,
            false,
            null,
            null,
            null,
            false,
            castedReceiver,
            receiverStart,
            receiverEnd);
 
        this.startPosition = oldStartPosition;
      }
      // traverse the enclosing node to find the instanceof expression corresponding
      // to the completion node (if any)
      // https://bugs.eclipse.org/bugs/show_bug.cgi?id=304006
      if (ifStatement.thenStatement instanceof IfStatement) {
        ifStatement = (IfStatement) ifStatement.thenStatement;
      } else {
        break;
      }
    }
  }
  private void findFieldsAndMethodsFromFavorites(
      char[] token,
      Scope scope,
      InvocationSite invocationSite,
      Scope invocationScope,
      ObjectVector localsFound,
      ObjectVector fieldsFound,
      ObjectVector methodsFound) {

    ObjectVector methodsFoundFromFavorites = new ObjectVector();

    ImportBinding[] favoriteBindings = getFavoriteReferenceBindings(invocationScope);

    if (favoriteBindings != null && favoriteBindings.length > 0) {
      for (int i = 0; i < favoriteBindings.length; i++) {
        ImportBinding favoriteBinding = favoriteBindings[i];
        switch (favoriteBinding.resolvedImport.kind()) {
          case Binding.FIELD:
            FieldBinding fieldBinding = (FieldBinding) favoriteBinding.resolvedImport;
            findFieldsFromFavorites(
                token,
                new FieldBinding[]{fieldBinding},
                scope,
                fieldsFound,
                localsFound,
                fieldBinding.declaringClass,
                invocationSite,
                invocationScope);
            break;
          case Binding.METHOD:
            MethodBinding methodBinding = (MethodBinding) favoriteBinding.resolvedImport;
            MethodBinding[] methods = methodBinding.declaringClass.availableMethods();
            long range;
            if ((range = ReferenceBinding.binarySearch(methodBinding.selector, methods)) >= 0) {
              int start = (int) range, end = (int) (range >> 32);
              int length = end - start + 1;
              System.arraycopy(methods, start, methods = new MethodBinding[length], 0, length);
            } else {
              methods = Binding.NO_METHODS;
            }
            findLocalMethodsFromFavorites(
                token,
                methods,
                scope,
                methodsFound,
                methodsFoundFromFavorites,
                methodBinding.declaringClass,
                invocationSite,
                invocationScope);
            break;
          case Binding.TYPE:
            ReferenceBinding referenceBinding = (ReferenceBinding) favoriteBinding.resolvedImport;
            if(favoriteBinding.onDemand) {
              findFieldsFromFavorites(
                  token,
                  referenceBinding.availableFields(),
                  scope,
                  fieldsFound,
                  localsFound,
                  referenceBinding,
                  invocationSite,
                  invocationScope);

              findLocalMethodsFromFavorites(
                  token,
                  referenceBinding.availableMethods(),
                  scope,
                  methodsFound,
                  methodsFoundFromFavorites,
                  referenceBinding,
                  invocationSite,
                  invocationScope);
            }
            break;
        }
      }
    }

    methodsFound.addAll(methodsFoundFromFavorites);
  }

  private boolean findFieldsAndMethodsFromMissingFieldType(
    char[] token,
    Scope scope,
    InvocationSite invocationSite,
    boolean insideTypeAnnotation) {

    boolean foundSomeFields = false;

    Scope currentScope = scope;

    done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found

      switch (currentScope.kind) {

        case Scope.CLASS_SCOPE :
          ClassScope classScope = (ClassScope) currentScope;
          if(!insideTypeAnnotation) {

            FieldDeclaration[] fields = classScope.referenceContext.fields;

            int fieldsCount = fields == null ? 0 : fields.length;
            for (int i = 0; i < fieldsCount; i++) {
              FieldDeclaration fieldDeclaration = fields[i];
              if (CharOperation.equals(fieldDeclaration.name, token)) {
                FieldBinding fieldBinding = fieldDeclaration.binding;
                if (fieldBinding == null || fieldBinding.type == null  || (fieldBinding.type.tagBits & TagBits.HasMissingType) != 0) {
                  foundSomeFields = true;
                  findFieldsAndMethodsFromMissingType(
                      fieldDeclaration.type,
                      currentScope,
                      invocationSite,
                      scope);
                }
                break done;
              }
            }
          }
          insideTypeAnnotation = false;
          break;
        case Scope.COMPILATION_UNIT_SCOPE :
          break done;
      }
      currentScope = currentScope.parent;
    }
    return foundSomeFields;
  }

  private void findFieldsAndMethodsFromMissingReturnType(
    char[] token,
    TypeBinding[] arguments,
    Scope scope,
    InvocationSite invocationSite,
    boolean insideTypeAnnotation) {

    Scope currentScope = scope;

    done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found

      switch (currentScope.kind) {

        case Scope.CLASS_SCOPE :
          ClassScope classScope = (ClassScope) currentScope;
          if(!insideTypeAnnotation) {

            AbstractMethodDeclaration[] methods = classScope.referenceContext.methods;

            int methodsCount = methods == null ? 0 : methods.length;
            for (int i = 0; i < methodsCount; i++) {
              AbstractMethodDeclaration methodDeclaration = methods[i];
              if (methodDeclaration instanceof MethodDeclaration &&
                  CharOperation.equals(methodDeclaration.selector, token)) {
                MethodDeclaration method = (MethodDeclaration) methodDeclaration;
                MethodBinding methodBinding = method.binding;
                if (methodBinding == null || methodBinding.returnType == null  || (methodBinding.returnType.tagBits & TagBits.HasMissingType) != 0) {
                  Argument[] parameters = method.arguments;
                  int parametersLength = parameters == null ? 0 : parameters.length;
                  int argumentsLength = arguments == null ? 0 : arguments.length;

                  if (parametersLength == 0) {
                    if (argumentsLength == 0) {
                      findFieldsAndMethodsFromMissingType(
                          method.returnType,
                          currentScope,
                          invocationSite,
                          scope);
                      break done;
                    }
                  } else {
                    TypeBinding[] parametersBindings;
                    if (methodBinding == null) { // since no binding, extra types from type references
                      parametersBindings = new TypeBinding[parametersLength];
                      for (int j = 0; j < parametersLength; j++) {
                        TypeBinding parameterType = parameters[j].type.resolvedType;
                        if (!parameterType.isValidBinding() && parameterType.closestMatch() != null) {
                          parameterType = parameterType.closestMatch();
                        }
                        parametersBindings[j] = parameterType;
                      }
                    } else {
                      parametersBindings = methodBinding.parameters;
                    }
                    if(areParametersCompatibleWith(parametersBindings, arguments, parameters[parametersLength - 1].isVarArgs())) {
                      findFieldsAndMethodsFromMissingType(
                          method.returnType,
                          currentScope,
                          invocationSite,
                          scope);
                      break done;
                    }
                  }
                }

              }
            }
          }
          insideTypeAnnotation = false;
          break;
        case Scope.COMPILATION_UNIT_SCOPE :
          break done;
      }
      currentScope = currentScope.parent;
    }
  }

  private void findFieldsAndMethodsFromMissingType(
      TypeReference typeRef,
      final Scope scope,
      final InvocationSite invocationSite,
      final Scope invocationScope) {
    MissingTypesGuesser missingTypesConverter = new MissingTypesGuesser(this);
    MissingTypesGuesser.GuessedTypeRequestor substitutionRequestor =
      new MissingTypesGuesser.GuessedTypeRequestor() {
        public void accept(
            TypeBinding guessedType,
            Binding[] missingElements,
            int[] missingElementsStarts,
            int[] missingElementsEnds,
            boolean hasProblems) {
          findFieldsAndMethods(
            CompletionEngine.this.completionToken,
            guessedType,
            scope,
            new ObjectVector(),
            new ObjectVector(),
            invocationSite,
            invocationScope,
            false,
            false,
            missingElements,
            missingElementsStarts,
            missingElementsEnds,
            hasProblems,
            null,
            -1,
            -1);

        }
      };
    missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
  }

  private void findFieldsAndMethodsFromStaticImports(
      char[] token,
      Scope scope,
      InvocationSite invocationSite,
      Scope invocationScope,
      boolean exactMatch,
      boolean insideAnnotationAttribute,
      ObjectVector localsFound,
      ObjectVector fieldsFound,
      ObjectVector methodsFound,
      boolean proposeField,
      boolean proposeMethod) {
    // search in static import
    ImportBinding[] importBindings = scope.compilationUnitScope().imports;
    for (int i = 0; i < importBindings.length; i++) {
      ImportBinding importBinding = importBindings[i];
      if(importBinding.isValidBinding() && importBinding.isStatic()) {
        Binding binding = importBinding.resolvedImport;
        if(binding != null && binding.isValidBinding()) {
          if(importBinding.onDemand) {
            if((binding.kind() & Binding.TYPE) != 0) {
              if(proposeField) {
                findFields(
                  token,
                  (ReferenceBinding)binding,
                  scope,
                  fieldsFound,
                  localsFound,
                  true,
                  invocationSite,
                  invocationScope,
                  true,
                  false,
                  null,
                  null,
                  null,
                  false,
                  null,
                  -1,
                  -1);
              }
              if(proposeMethod && !insideAnnotationAttribute) {
                findMethods(
                  token,
                  null,
                  null,
                  (ReferenceBinding)binding,
                  scope,
                  methodsFound,
                  true,
                  exactMatch,
                  invocationSite,
                  invocationScope,
                  true,
                  false,
                  false,
                  null,
                  null,
                  null,
                  false,
                  null,
                  -1,
                  -1);
              }
            }
          } else {
            if ((binding.kind() & Binding.FIELD) != 0) {
              if(proposeField) {
                  findFields(
                      token,
                      new FieldBinding[]{(FieldBinding)binding},
                      scope,
                      fieldsFound,
                      localsFound,
                      true,
                      ((FieldBinding)binding).declaringClass,
                      invocationSite,
                      invocationScope,
                      true,
                      false,
                      null,
                      null,
                      null,
                      false,
                      null,
                      -1,
                      -1);
              }
            } else if ((binding.kind() & Binding.METHOD) != 0) {
              if(proposeMethod && !insideAnnotationAttribute) {
                MethodBinding methodBinding = (MethodBinding)binding;
                if ((exactMatch && CharOperation.equals(token, methodBinding.selector)) ||
                    !exactMatch && CharOperation.prefixEquals(token, methodBinding.selector) ||
                    (this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, methodBinding.selector))) {
                  findLocalMethodsFromStaticImports(
                      token,
                      methodBinding.declaringClass.getMethods(methodBinding.selector),
                      scope,
                      exactMatch,
                      methodsFound,
                      methodBinding.declaringClass,
                      invocationSite);
                }
              }
            }
          }
        }
      }
    }
  }

  private void findFieldsFromFavorites(
      char[] fieldName,
      FieldBinding[] fields,
      Scope scope,
      ObjectVector fieldsFound,
      ObjectVector localsFound,
      ReferenceBinding receiverType,
      InvocationSite invocationSite,
      Scope invocationScope) {

    char[] typeName = CharOperation.concatWith(receiverType.compoundName, '.');

    int fieldLength = fieldName.length;
    next : for (int f = fields.length; --f >= 0;) {
      FieldBinding field = fields[f];

      if (field.isSynthetic())  continue next;

      // only static fields must be proposed
      if (!field.isStatic()) continue next;

      if (fieldLength > field.name.length) continue next;

      if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name)))  continue next;

      if (this.options.checkDeprecation &&
          field.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(field.declaringClass))
        continue next;

      if (this.options.checkVisibility
        && !field.canBeSeenBy(receiverType, invocationSite, scope))  continue next;

      for (int i = fieldsFound.size; --i >= 0;) {
        Object[] other = (Object[])fieldsFound.elementAt(i);
        FieldBinding otherField = (FieldBinding) other[0];

        if (field == otherField) continue next;
      }

      fieldsFound.add(new Object[]{field, receiverType});

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal(field);
      relevance += computeRelevanceForCaseMatching(fieldName, field.name);
      relevance += computeRelevanceForExpectingType(field.type);
      relevance += computeRelevanceForEnumConstant(field.type);
      relevance += computeRelevanceForStatic(true, true);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      CompilationUnitDeclaration cu = this.unitScope.referenceContext;
      int importStart = cu.types[0].declarationSourceStart;
      int importEnd = importStart;

      this.noProposal = false;

      if (this.compilerOptions.complianceLevel < ClassFileConstants.JDK1_5 ||
          !this.options.suggestStaticImport) {
        if (!this.isIgnored(CompletionProposal.FIELD_REF, CompletionProposal.TYPE_IMPORT)) {
          char[] completion = CharOperation.concat(receiverType.sourceName, field.name, '.');

          InternalCompletionProposal proposal =  createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(field.declaringClass));
          proposal.setSignature(getSignature(field.type));
          proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          proposal.setPackageName(field.type.qualifiedPackageName());
          proposal.setTypeName(field.type.qualifiedSourceName());
          proposal.setName(field.name);
          proposal.setCompletion(completion);
          proposal.setFlags(field.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);

          char[] typeImportCompletion = createImportCharArray(typeName, false, false);

          InternalCompletionProposal typeImportProposal = createProposal(CompletionProposal.TYPE_IMPORT, this.actualCompletionPosition);
          typeImportProposal.nameLookup = this.nameEnvironment.nameLookup;
          typeImportProposal.completionEngine = this;
          char[] packageName = receiverType.qualifiedPackageName();
          typeImportProposal.setDeclarationSignature(packageName);
          typeImportProposal.setSignature(getSignature(receiverType));
          typeImportProposal.setPackageName(packageName);
          typeImportProposal.setTypeName(receiverType.qualifiedSourceName());
          typeImportProposal.setCompletion(typeImportCompletion);
          typeImportProposal.setFlags(receiverType.modifiers);
          typeImportProposal.setAdditionalFlags(CompletionFlags.Default);
          typeImportProposal.setReplaceRange(importStart - this.offset, importEnd - this.offset);
          typeImportProposal.setTokenRange(importStart - this.offset, importEnd - this.offset);
          typeImportProposal.setRelevance(relevance);

          proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal});

          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      } else {
        if (!this.isIgnored(CompletionProposal.FIELD_REF, CompletionProposal.FIELD_IMPORT)) {
          char[] completion = field.name;

          InternalCompletionProposal proposal =  createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(field.declaringClass));
          proposal.setSignature(getSignature(field.type));
          proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          proposal.setPackageName(field.type.qualifiedPackageName());
          proposal.setTypeName(field.type.qualifiedSourceName());
          proposal.setName(field.name);
          proposal.setCompletion(completion);
          proposal.setFlags(field.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);

          char[] fieldImportCompletion = createImportCharArray(CharOperation.concat(typeName, field.name, '.'), true, false);

          InternalCompletionProposal fieldImportProposal = createProposal(CompletionProposal.FIELD_IMPORT, this.actualCompletionPosition);
          fieldImportProposal.setDeclarationSignature(getSignature(field.declaringClass));
          fieldImportProposal.setSignature(getSignature(field.type));
          fieldImportProposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
          fieldImportProposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
          fieldImportProposal.setPackageName(field.type.qualifiedPackageName());
          fieldImportProposal.setTypeName(field.type.qualifiedSourceName());
          fieldImportProposal.setName(field.name);
          fieldImportProposal.setCompletion(fieldImportCompletion);
          fieldImportProposal.setFlags(field.modifiers);
          fieldImportProposal.setAdditionalFlags(CompletionFlags.StaticImport);
          fieldImportProposal.setReplaceRange(importStart - this.offset, importEnd - this.offset);
          fieldImportProposal.setTokenRange(importStart - this.offset, importEnd - this.offset);
          fieldImportProposal.setRelevance(relevance);

          proposal.setRequiredProposals(new CompletionProposal[]{fieldImportProposal});

          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    }
  }
  private void findImplicitMessageSends(
    char[] token,
    TypeBinding[] argTypes,
    Scope scope,
    InvocationSite invocationSite,
    Scope invocationScope,
    ObjectVector methodsFound) {

    if (token == null)
      return;

    boolean staticsOnly = false;
    // need to know if we're in a static context (or inside a constructor)

    done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found

      switch (scope.kind) {

        case Scope.METHOD_SCOPE :
          // handle the error case inside an explicit constructor call (see MethodScope>>findField)
          MethodScope methodScope = (MethodScope) scope;
          staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;
          break;

        case Scope.CLASS_SCOPE :
          ClassScope classScope = (ClassScope) scope;
          SourceTypeBinding enclosingType = classScope.referenceContext.binding;
          findMethods(
            token,
            null,
            argTypes,
            enclosingType,
            classScope,
            methodsFound,
            staticsOnly,
            true,
            invocationSite,
            invocationScope,
            true,
            false,
            true,
            null,
            null,
            null,
            false,
            null,
            -1,
            -1);
          staticsOnly |= enclosingType.isStatic();
          break;

        case Scope.COMPILATION_UNIT_SCOPE :
          break done;
      }
      scope = scope.parent;
    }
  }
  private void findImports(CompletionOnImportReference importReference, boolean findMembers) {
    char[][] tokens = importReference.tokens;

    char[] importName = CharOperation.concatWith(tokens, '.');

    if (importName.length == 0)
      return;

    char[] lastToken = tokens[tokens.length - 1];
    if(lastToken != null && lastToken.length == 0)
      importName = CharOperation.concat(importName, new char[]{'.'});

    this.resolvingImports = true;
    this.resolvingStaticImports = importReference.isStatic();

    this.completionToken =  lastToken;
    this.qualifiedCompletionToken = importName;

    // want to replace the existing .*;
    if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
      int oldStart = this.startPosition;
      int oldEnd = this.endPosition;
      setSourceRange(
        importReference.sourceStart,
        importReference.declarationSourceEnd);
      this.nameEnvironment.findPackages(importName, this);
      setSourceRange(
        oldStart,
        oldEnd - 1,
        false);
    }
    if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      this.foundTypesCount = 0;
      this.nameEnvironment.findTypes(
          importName,
          findMembers,
          this.options.camelCaseMatch,
          IJavaSearchConstants.TYPE,
          this,
          this.monitor);
      acceptTypes(null);
    }
  }

  private void findImportsOfMemberTypes(char[] typeName,  ReferenceBinding ref, boolean onlyStatic) {
    ReferenceBinding[] memberTypes = ref.memberTypes();

    int typeLength = typeName.length;
    next : for (int m = memberTypes.length; --m >= 0;) {
      ReferenceBinding memberType = memberTypes[m];
      //    if (!wantClasses && memberType.isClass()) continue next;
      //    if (!wantInterfaces && memberType.isInterface()) continue next;

      if (onlyStatic && !memberType.isStatic())
        continue next;

      if (typeLength > memberType.sourceName.length)
        continue next;

      if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName)))
        continue next;

      if (this.options.checkDeprecation && memberType.isViewedAsDeprecated()) continue next;

      if (this.options.checkVisibility
        && !memberType.canBeSeenBy(this.unitScope.fPackage))
        continue next;

      char[] completionName = CharOperation.concat(memberType.sourceName, SEMICOLON);

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      if (memberType.isClass()) {
        relevance += computeRelevanceForClass();
      } else if(memberType.isEnum()) {
        relevance += computeRelevanceForEnum();
      } else if (memberType.isInterface()) {
        relevance += computeRelevanceForInterface();
      }
      this.noProposal = false;
      if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
        createTypeProposal(
            memberType,
            memberType.qualifiedSourceName(),
            IAccessRule.K_ACCESSIBLE,
            completionName,
            relevance,
            null,
            null,
            null,
            false);
      }
    }
  }

  private void findImportsOfStaticFields(char[] fieldName, ReferenceBinding ref) {
    FieldBinding[] fields = ref.availableFields();

    int fieldLength = fieldName.length;
    next : for (int m = fields.length; --m >= 0;) {
      FieldBinding field = fields[m];

      if (fieldLength > field.name.length)
        continue next;

      if (field.isSynthetic())
        continue next;

      if (!field.isStatic())
        continue next;

      if (!CharOperation.prefixEquals(fieldName, field.name, false/* ignore case */)
        && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name)))
        continue next;

      if (this.options.checkDeprecation && field.isViewedAsDeprecated()) continue next;

      if (this.options.checkVisibility
        && !field.canBeSeenBy(this.unitScope.fPackage))
        continue next;

      char[] completionName = CharOperation.concat(field.name, SEMICOLON);

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(fieldName, field.name);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      this.noProposal = false;
      if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
        InternalCompletionProposal proposal =  createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition);
        proposal.setDeclarationSignature(getSignature(field.declaringClass));
        proposal.setSignature(getSignature(field.type));
        proposal.setDeclarationPackageName(field.declaringClass.qualifiedPackageName());
        proposal.setDeclarationTypeName(field.declaringClass.qualifiedSourceName());
        proposal.setPackageName(field.type.qualifiedPackageName());
        proposal.setTypeName(field.type.qualifiedSourceName());
        proposal.setName(field.name);
        proposal.setCompletion(completionName);
        proposal.setFlags(field.modifiers);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        this.requestor.accept(proposal);
        if(DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
  }

  private void findImportsOfStaticMethods(char[] methodName, ReferenceBinding ref) {
    MethodBinding[] methods = ref.availableMethods();

    int methodLength = methodName.length;
    next : for (int m = methods.length; --m >= 0;) {
      MethodBinding method = methods[m];

      if (method.isSynthetic()) continue next;

      if (method.isDefaultAbstract())  continue next;

      if (method.isConstructor()) continue next;

      if (!method.isStatic()) continue next;

      if (this.options.checkDeprecation && method.isViewedAsDeprecated()) continue next;

      if (this.options.checkVisibility
        && !method.canBeSeenBy(this.unitScope.fPackage)) continue next;

      if (methodLength > method.selector.length)
        continue next;

      if (!CharOperation.prefixEquals(methodName, method.selector, false/* ignore case */)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector)))
        continue next;

      int length = method.parameters.length;
      char[][] parameterPackageNames = new char[length][];
      char[][] parameterTypeNames = new char[length][];

      for (int i = 0; i < length; i++) {
        TypeBinding type = method.original().parameters[i];
        parameterPackageNames[i] = type.qualifiedPackageName();
        parameterTypeNames[i] = type.qualifiedSourceName();
      }
      char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);

      char[] completionName = CharOperation.concat(method.selector, SEMICOLON);

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(methodName, method.selector);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      this.noProposal = false;
      if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) {
        InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_NAME_REFERENCE, this.actualCompletionPosition);
        proposal.setDeclarationSignature(getSignature(method.declaringClass));
        proposal.setSignature(getSignature(method));
        proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
        proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
        proposal.setParameterPackageNames(parameterPackageNames);
        proposal.setParameterTypeNames(parameterTypeNames);
        proposal.setPackageName(method.returnType.qualifiedPackageName());
        proposal.setTypeName(method.returnType.qualifiedSourceName());
        proposal.setName(method.selector);
        proposal.setCompletion(completionName);
        proposal.setFlags(method.modifiers);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        if(parameterNames != null) proposal.setParameterNames(parameterNames);
        this.requestor.accept(proposal);
        if(DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
  }
 
  private void findInterfacesMethodDeclarations(
    char[] selector,
    ReferenceBinding receiverType,
    ReferenceBinding[] itsInterfaces,
    Scope scope,
    ObjectVector methodsFound,
    Binding[] missingElements,
    int[] missingElementssStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems) {

    if (selector == null)
      return;

    if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
      ReferenceBinding[] interfacesToVisit = itsInterfaces;
      int nextPosition = interfacesToVisit.length;

      for (int i = 0; i < nextPosition; i++) {
        ReferenceBinding currentType = interfacesToVisit[i];
        MethodBinding[] methods = currentType.availableMethods();
        if(methods != null) {
          findLocalMethodDeclarations(
            selector,
            methods,
            scope,
            methodsFound,
            false,
            receiverType);
        }

        itsInterfaces = currentType.superInterfaces();
        if (itsInterfaces != null && itsInterfaces != 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;
          }
        }
      }
    }
  }
 
  private void findInterfacesMethods(
    char[] selector,
    TypeBinding[] typeArgTypes,
    TypeBinding[] argTypes,
    ReferenceBinding receiverType,
    ReferenceBinding[] itsInterfaces,
    Scope scope,
    ObjectVector methodsFound,
    boolean onlyStaticMethods,
    boolean exactMatch,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean implicitCall,
    boolean superCall,
    boolean canBePrefixed,
    Binding[] missingElements,
    int[] missingElementssStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    char[] castedReceiver,
    int receiverStart,
    int receiverEnd) {

    if (selector == null)
      return;

    if (itsInterfaces != Binding.NO_SUPERINTERFACES) {
      ReferenceBinding[] interfacesToVisit = itsInterfaces;
      int nextPosition = interfacesToVisit.length;

      for (int i = 0; i < nextPosition; i++) {
        ReferenceBinding currentType = interfacesToVisit[i];
        MethodBinding[] methods = currentType.availableMethods();
        if(methods != null) {
          findLocalMethods(
            selector,
            typeArgTypes,
            argTypes,
            methods,
            scope,
            methodsFound,
            onlyStaticMethods,
            exactMatch,
            receiverType,
            invocationSite,
            invocationScope,
            implicitCall,
            superCall,
            canBePrefixed,
            missingElements,
            missingElementssStarts,
            missingElementsEnds,
            missingElementsHaveProblems,
            castedReceiver,
            receiverStart,
            receiverEnd);
        }

        itsInterfaces = currentType.superInterfaces();
        if (itsInterfaces != null && itsInterfaces != 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;
          }
        }
      }
    }
  }
  /*
   * Find javadoc block tags for a given completion javadoc tag node
   */
  private void findJavadocBlockTags(CompletionOnJavadocTag javadocTag) {
    char[][] possibleTags = javadocTag.getPossibleBlockTags();
    if (possibleTags == null) return;
    int length = possibleTags.length;
    for (int i=0; i<length; i++) {
      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywors

      this.noProposal = false;
      if (!this.requestor.isIgnored(CompletionProposal.JAVADOC_BLOCK_TAG)) {
        char[] possibleTag = possibleTags[i];
        InternalCompletionProposal proposal =  createProposal(CompletionProposal.JAVADOC_BLOCK_TAG, this.actualCompletionPosition);
        proposal.setName(possibleTag);
        int tagLength = possibleTag.length;
        char[] completion = new char[1+tagLength];
        completion[0] = '@';
        System.arraycopy(possibleTag, 0, completion, 1, tagLength);
        proposal.setCompletion(completion);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        this.requestor.accept(proposal);
        if (DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
  }

  /*
   * Find javadoc inline tags for a given completion javadoc tag node
   */
  private void findJavadocInlineTags(CompletionOnJavadocTag javadocTag) {
    char[][] possibleTags = javadocTag.getPossibleInlineTags();
    if (possibleTags == null) return;
    int length = possibleTags.length;
    for (int i=0; i<length; i++) {
      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywors

      this.noProposal = false;
      if (!this.requestor.isIgnored(CompletionProposal.JAVADOC_INLINE_TAG)) {
        char[] possibleTag = possibleTags[i];
        InternalCompletionProposal proposal =  createProposal(CompletionProposal.JAVADOC_INLINE_TAG, this.actualCompletionPosition);
        proposal.setName(possibleTag);
        int tagLength = possibleTag.length;
//        boolean inlineTagStarted = javadocTag.completeInlineTagStarted();
        char[] completion = new char[2+tagLength+1];
        completion[0] = '{';
        completion[1] = '@';
        System.arraycopy(possibleTag, 0, completion, 2, tagLength);
        // do not add space at end of inline tag (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=121026)
        //completion[tagLength+2] = ' ';
        completion[tagLength+2] = '}';
        proposal.setCompletion(completion);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        this.requestor.accept(proposal);
        if (DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
  }

  /*
   * Find javadoc parameter names.
   */
  private void findJavadocParamNames(char[] token, char[][] missingParams, boolean isTypeParam) {

    if (missingParams == null) return;

    // Get relevance
    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForInterestingProposal();
    relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for param name
    if (!isTypeParam) relevance += R_INTERESTING;

    // Propose missing param
    int length = missingParams.length;
    relevance += length;
    for (int i=0; i<length; i++) {
      char[] argName = missingParams[i];
      if (token == null || CharOperation.prefixEquals(token, argName)) {

        this.noProposal = false;
        if (!this.requestor.isIgnored(CompletionProposal.JAVADOC_PARAM_REF)) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.JAVADOC_PARAM_REF, this.actualCompletionPosition);
          proposal.setName(argName);
          char[] completion = isTypeParam ? CharOperation.concat('<', argName, '>') : argName;
          proposal.setCompletion(completion);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(--relevance);
          this.requestor.accept(proposal);
          if (DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    }
  }

  // what about onDemand types? Ignore them since it does not happen!
  // import p1.p2.A.*;
  private void findKeywords(char[] keyword, char[][] choices, boolean canCompleteEmptyToken, boolean staticFieldsAndMethodOnly) {
    if(choices == null || choices.length == 0) return;

    int length = keyword.length;
    if (canCompleteEmptyToken || length > 0)
      for (int i = 0; i < choices.length; i++)
        if (length <= choices[i].length
          && CharOperation.prefixEquals(keyword, choices[i], false /* ignore case */
        )){
          int relevance = computeBaseRelevance();
          relevance += computeRelevanceForResolution();
          relevance += computeRelevanceForInterestingProposal();
          relevance += computeRelevanceForCaseMatching(keyword, choices[i]);
          relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywords
          if (staticFieldsAndMethodOnly && this.insideQualifiedReference) relevance += R_NON_INHERITED;

          if(CharOperation.equals(choices[i], Keywords.TRUE) || CharOperation.equals(choices[i], Keywords.FALSE)) {
            relevance += computeRelevanceForExpectingType(TypeBinding.BOOLEAN);
            relevance += computeRelevanceForQualification(false);
          }
          this.noProposal = false;
          if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition);
            proposal.setName(choices[i]);
            proposal.setCompletion(choices[i]);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
  }
  private void findKeywordsForMember(char[] token, int modifiers) {
    char[][] keywords = new char[Keywords.COUNT][];
    int count = 0;

    // visibility
    if((modifiers & ClassFileConstants.AccPrivate) == 0
      && (modifiers & ClassFileConstants.AccProtected) == 0
      && (modifiers & ClassFileConstants.AccPublic) == 0) {
      keywords[count++] = Keywords.PROTECTED;
      keywords[count++] = Keywords.PUBLIC;
      if((modifiers & ClassFileConstants.AccAbstract) == 0) {
        keywords[count++] = Keywords.PRIVATE;
      }
    }

    if((modifiers & ClassFileConstants.AccAbstract) == 0) {
      // abtract
      if((modifiers & ~(ExtraCompilerModifiers.AccVisibilityMASK | ClassFileConstants.AccStatic)) == 0) {
        keywords[count++] = Keywords.ABSTRACT;
      }

      // final
      if((modifiers & ClassFileConstants.AccFinal) == 0) {
        keywords[count++] = Keywords.FINAL;
      }

      // static
      if((modifiers & ClassFileConstants.AccStatic) == 0) {
        keywords[count++] = Keywords.STATIC;
      }

      boolean canBeField = true;
      boolean canBeMethod = true;
      boolean canBeType = true;
      if((modifiers & ClassFileConstants.AccNative) != 0
        || (modifiers & ClassFileConstants.AccStrictfp) != 0
        || (modifiers & ClassFileConstants.AccSynchronized) != 0) {
        canBeField = false;
        canBeType = false;
      }

      if((modifiers & ClassFileConstants.AccTransient) != 0
        || (modifiers & ClassFileConstants.AccVolatile) != 0) {
        canBeMethod = false;
        canBeType = false;
      }

      if(canBeField) {
        // transient
        if((modifiers & ClassFileConstants.AccTransient) == 0) {
          keywords[count++] = Keywords.TRANSIENT;
        }

        // volatile
        if((modifiers & ClassFileConstants.AccVolatile) == 0) {
          keywords[count++] = Keywords.VOLATILE;
        }
      }

      if(canBeMethod) {
        // native
        if((modifiers & ClassFileConstants.AccNative) == 0) {
          keywords[count++] = Keywords.NATIVE;
        }

        // strictfp
        if((modifiers & ClassFileConstants.AccStrictfp) == 0) {
          keywords[count++] = Keywords.STRICTFP;
        }

        // synchronized
        if((modifiers & ClassFileConstants.AccSynchronized) == 0) {
          keywords[count++] = Keywords.SYNCHRONIZED;
        }
      }

      if(canBeType) {
        keywords[count++] = Keywords.CLASS;
        keywords[count++] = Keywords.INTERFACE;

        if((modifiers & ClassFileConstants.AccFinal) == 0) {
          keywords[count++] = Keywords.ENUM;
        }
      }
    } else {
      // class
      keywords[count++] = Keywords.CLASS;
      keywords[count++] = Keywords.INTERFACE;
    }
    System.arraycopy(keywords, 0, keywords = new char[count][], 0, count);

    findKeywords(token, keywords, false, false);
  }
  private void findLabels(char[] label, char[][] choices) {
    if(choices == null || choices.length == 0) return;

    int length = label.length;
    for (int i = 0; i < choices.length; i++) {
      if (length <= choices[i].length
        && CharOperation.prefixEquals(label, choices[i], false /* ignore case */
      )){
        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal();
        relevance += computeRelevanceForCaseMatching(label, choices[i]);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywors

        this.noProposal = false;
        if(!this.requestor.isIgnored(CompletionProposal.LABEL_REF)) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.LABEL_REF, this.actualCompletionPosition);
          proposal.setName(choices[i]);
          proposal.setCompletion(choices[i]);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    }
  }

  // Helper method for findMethods(char[], MethodBinding[], Scope, ObjectVector, boolean, boolean, boolean, TypeBinding)
  private void findLocalMethodDeclarations(
    char[] methodName,
    MethodBinding[] methods,
    Scope scope,
    ObjectVector methodsFound,
    //  boolean noVoidReturnType, how do you know?
    boolean exactMatch,
    ReferenceBinding receiverType) {

    ObjectVector newMethodsFound =  new ObjectVector();
    // Inherited methods which are hidden by subclasses are filtered out
    // No visibility checks can be performed without the scope & invocationSite
    int methodLength = methodName.length;
    next : for (int f = methods.length; --f >= 0;) {

      MethodBinding method = methods[f];
      if (method.isSynthetic())  continue next;

      if (method.isDefaultAbstract()) continue next;

      if (method.isConstructor()) continue next;

      if (method.isFinal()) {
                newMethodsFound.add(method);
                continue next;
            }

      if (this.options.checkDeprecation &&
          method.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(method.declaringClass))
        continue next;

      //    if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
      if(method.isStatic()) continue next;

      if (!method.canBeSeenBy(receiverType, FakeInvocationSite , scope)) continue next;

      if (exactMatch) {
        if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
          ))
          continue next;

      } else {

        if (methodLength > method.selector.length)
          continue next;

        if (!CharOperation.prefixEquals(methodName, method.selector, false/* ignore case */)
            && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector)))
          continue next;
      }

      for (int i = methodsFound.size; --i >= 0;) {
        MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i);
        if (method == otherMethod)
          continue next;

        if (CharOperation.equals(method.selector, otherMethod.selector, true)
            && this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) {
          continue next;
        }
      }

      newMethodsFound.add(method);

      int length = method.parameters.length;
      char[][] parameterPackageNames = new char[length][];
      char[][] parameterFullTypeNames = new char[length][];

      for (int i = 0; i < length; i++) {
        TypeBinding type = method.parameters[i];
        parameterPackageNames[i] = type.qualifiedPackageName();
        parameterFullTypeNames[i] = type.qualifiedSourceName();
      }

      char[][] parameterNames = findMethodParameterNames(method, parameterFullTypeNames);

      if(method.typeVariables != null && method.typeVariables.length > 0) {
        char[][] excludedNames = findEnclosingTypeNames(scope);
        char[][] substituedParameterNames = substituteMethodTypeParameterNames(method.typeVariables, excludedNames);
        if(substituedParameterNames != null) {
          method = new ParameterizedMethodBinding(
                method.declaringClass,
                method,
                substituedParameterNames,
                scope.environment());
        }
      }

      StringBuffer completion = new StringBuffer(10);
      if (!exactMatch) {
        createMethod(method, parameterPackageNames, parameterFullTypeNames, parameterNames, scope, completion);
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(methodName, method.selector);
      relevance += R_METHOD_OVERIDE;
      if(method.isAbstract()) relevance += R_ABSTRACT_METHOD;
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      this.noProposal = false;
      if(!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) {
        InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_DECLARATION, this.actualCompletionPosition);
        proposal.setDeclarationSignature(getSignature(method.declaringClass));
        proposal.setDeclarationKey(method.declaringClass.computeUniqueKey());
        proposal.setSignature(getSignature(method));
        MethodBinding original = method.original();
        if(original != method) {
          proposal.setOriginalSignature(getSignature(original));
        }
        proposal.setKey(method.computeUniqueKey());
        proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
        proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
        proposal.setParameterPackageNames(parameterPackageNames);
        proposal.setParameterTypeNames(parameterFullTypeNames);
        proposal.setPackageName(method.returnType.qualifiedPackageName());
        proposal.setTypeName(method.returnType.qualifiedSourceName());
        proposal.setCompletion(completion.toString().toCharArray());
        proposal.setName(method.selector);
        proposal.setFlags(method.modifiers);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        if(parameterNames != null) proposal.setParameterNames(parameterNames);
        this.requestor.accept(proposal);
        if(DEBUG) {
          this.printDebug(proposal);
        }
      }
    }
    methodsFound.addAll(newMethodsFound);
  }

  // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean)
  private void findLocalMethods(
    char[] methodName,
    TypeBinding[] typeArgTypes,
    TypeBinding[] argTypes,
    MethodBinding[] methods,
    Scope scope,
    ObjectVector methodsFound,
    boolean onlyStaticMethods,
    boolean exactMatch,
    ReferenceBinding receiverType,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean implicitCall,
    boolean superCall,
    boolean canBePrefixed,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    char[] castedReceiver,
    int receiverStart,
    int receiverEnd) {

    ObjectVector newMethodsFound =  new ObjectVector();
    // Inherited methods which are hidden by subclasses are filtered out
    // No visibility checks can be performed without the scope & invocationSite

    int methodLength = methodName.length;
    int minTypeArgLength = typeArgTypes == null ? 0 : typeArgTypes.length;
    int minArgLength = argTypes == null ? 0 : argTypes.length;

    next : for (int f = methods.length; --f >= 0;) {
      MethodBinding method = methods[f];

      if (method.isSynthetic()) continue next;

      if (method.isDefaultAbstract())  continue next;

      if (method.isConstructor()) continue next;

      if (this.options.checkDeprecation &&
          method.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(method.declaringClass))
        continue next;

      //TODO (david) perhaps the relevance of a void method must be lesser than other methods
      //if (expectedTypesPtr > -1 && method.returnType == BaseTypes.VoidBinding) continue next;

      if (onlyStaticMethods && !method.isStatic()) continue next;

      if (this.options.checkVisibility
        && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next;

      if(superCall && method.isAbstract()) {
        methodsFound.add(new Object[]{method, receiverType});
        continue next;
      }

      if (exactMatch) {
        if (!CharOperation.equals(methodName, method.selector, false /* ignore case */)) {
          continue next;
        }
      } else {
        if (methodLength > method.selector.length) continue next;
        if (!CharOperation.prefixEquals(methodName, method.selector, false /* ignore case */)
            && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) {
          continue next;
        }
      }

      if (minTypeArgLength != 0 && minTypeArgLength != method.typeVariables.length)
        continue next;

      if (minTypeArgLength != 0) {
        method = scope.environment().createParameterizedGenericMethod(method, typeArgTypes);
      }

      if (minArgLength > method.parameters.length)
        continue next;

      for (int a = minArgLength; --a >= 0;){
        if (argTypes[a] != null) { // can be null if it could not be resolved properly
          if (!argTypes[a].isCompatibleWith(method.parameters[a])) {
            continue next;
          }
        }
      }

      boolean prefixRequired = false;

      for (int i = methodsFound.size; --i >= 0;) {
        Object[] other = (Object[]) methodsFound.elementAt(i);
        MethodBinding otherMethod = (MethodBinding) other[0];
        ReferenceBinding otherReceiverType = (ReferenceBinding) other[1];
        if (method == otherMethod && receiverType == otherReceiverType)
          continue next;

        if (CharOperation.equals(method.selector, otherMethod.selector, true)) {
          if (receiverType == otherReceiverType) {
            if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) {
              if (!superCall || !otherMethod.declaringClass.isInterface()) {
                continue next;
              }
            }
          } else {
            if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) {
              if(receiverType.isAnonymousType()) continue next;

              if(!superCall) {
                if(!canBePrefixed) continue next;

                prefixRequired = true;
              }
            }
          }
        }
      }

      newMethodsFound.add(new Object[]{method, receiverType});

      ReferenceBinding superTypeWithSameErasure = (ReferenceBinding)receiverType.findSuperTypeOriginatingFrom(method.declaringClass);
      if (method.declaringClass != superTypeWithSameErasure) {
        MethodBinding[] otherMethods = superTypeWithSameErasure.getMethods(method.selector);
        for (int i = 0; i < otherMethods.length; i++) {
          if(otherMethods[i].original() == method.original()) {
            method = otherMethods[i];
          }
        }
      }

      int length = method.parameters.length;
      char[][] parameterPackageNames = new char[length][];
      char[][] parameterTypeNames = new char[length][];

      for (int i = 0; i < length; i++) {
        TypeBinding type = method.original().parameters[i];
        parameterPackageNames[i] = type.qualifiedPackageName();
        parameterTypeNames[i] = type.qualifiedSourceName();
      }
      char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);

      char[] completion = CharOperation.NO_CHAR;

      int previousStartPosition = this.startPosition;
      int previousTokenStart = this.tokenStart;

      // Special case for completion in javadoc
      if (this.assistNodeInJavadoc > 0) {
        Expression receiver = null;
        if (invocationSite instanceof CompletionOnJavadocMessageSend) {
          CompletionOnJavadocMessageSend msg = (CompletionOnJavadocMessageSend) invocationSite;
          receiver = msg.receiver;
        } else if (invocationSite instanceof CompletionOnJavadocFieldReference) {
          CompletionOnJavadocFieldReference fieldRef = (CompletionOnJavadocFieldReference) invocationSite;
          receiver = fieldRef.receiver;
        }
        if (receiver != null) {
          StringBuffer javadocCompletion = new StringBuffer();
          if (receiver.isThis()) {
            if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0) {
              javadocCompletion.append('#');
            }
          } else if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0) {
            if (receiver instanceof JavadocSingleTypeReference) {
              JavadocSingleTypeReference typeRef = (JavadocSingleTypeReference) receiver;
              javadocCompletion.append(typeRef.token);
              javadocCompletion.append('#');
            } else if (receiver instanceof JavadocQualifiedTypeReference) {
              JavadocQualifiedTypeReference typeRef = (JavadocQualifiedTypeReference) receiver;
              completion = CharOperation.concat(CharOperation.concatWith(typeRef.tokens, '.'), method.selector, '#');
              for (int t=0,nt =typeRef.tokens.length; t<nt; t++) {
                if (t>0) javadocCompletion.append('.');
                javadocCompletion.append(typeRef.tokens[t]);
              }
              javadocCompletion.append('#');
            }
          }
          javadocCompletion.append(method.selector);
          // Append parameters types
          javadocCompletion.append('(');
          if (method.parameters != null) {
            boolean isVarargs = method.isVarargs();
            for (int p=0, ln=method.parameters.length; p<ln; p++) {
              if (p>0) javadocCompletion.append(", "); //$NON-NLS-1$
              TypeBinding argTypeBinding = method.parameters[p];
              if (isVarargs && p == ln - 1)  {
                createVargsType(argTypeBinding.erasure(), scope, javadocCompletion);
              } else {
                createType(argTypeBinding.erasure(), scope,javadocCompletion);
              }
            }
          }
          javadocCompletion.append(')');
          completion = javadocCompletion.toString().toCharArray();
        }
      } else {
        // nothing to insert - do not want to replace the existing selector & arguments
        if (!exactMatch) {
          if (this.source != null
            && this.source.length > this.endPosition
            && this.source[this.endPosition] == '(')
            completion = method.selector;
          else
            completion = CharOperation.concat(method.selector, new char[] { '(', ')' });

          if (castedReceiver != null) {
            completion = CharOperation.concat(castedReceiver, completion);
          }
        } else {
          if(prefixRequired && (this.source != null)) {
            completion = CharOperation.subarray(this.source, this.startPosition, this.endPosition);
          } else {
            this.startPosition = this.endPosition;
          }
          this.tokenStart = this.tokenEnd;
        }

        if(prefixRequired || this.options.forceImplicitQualification){
          char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), method.isStatic());
          completion = CharOperation.concat(prefix,completion,'.');
        }
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(methodName, method.selector);
      relevance += computeRelevanceForExpectingType(method.returnType);
      relevance += computeRelevanceForEnumConstant(method.returnType);
      relevance += computeRelevanceForStatic(onlyStaticMethods, method.isStatic());
      relevance += computeRelevanceForQualification(prefixRequired);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
      if (onlyStaticMethods && this.insideQualifiedReference) {
        relevance += computeRelevanceForInheritance(receiverType, method.declaringClass);
      }
      if (missingElements != null) {
        relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
      }

      this.noProposal = false;

      if (castedReceiver == null) {
        // Standard proposal
        if(!this.isIgnored(CompletionProposal.METHOD_REF, missingElements != null) && (this.assistNodeInJavadoc & CompletionOnJavadoc.ONLY_INLINE_TAG) == 0) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(method.declaringClass));
          proposal.setSignature(getSignature(method));
          MethodBinding original = method.original();
          if(original != method) {
            proposal.setOriginalSignature(getSignature(original));
          }
          proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
          proposal.setParameterPackageNames(parameterPackageNames);
          proposal.setParameterTypeNames(parameterTypeNames);
          proposal.setPackageName(method.returnType.qualifiedPackageName());
          proposal.setTypeName(method.returnType.qualifiedSourceName());
          proposal.setName(method.selector);
          if (missingElements != null) {
            CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
            for (int i = 0; i < missingElements.length; i++) {
              subProposals[i] =
                createRequiredTypeProposal(
                    missingElements[i],
                    missingElementsStarts[i],
                    missingElementsEnds[i],
                    relevance);
            }
            proposal.setRequiredProposals(subProposals);
          }
          proposal.setCompletion(completion);
          proposal.setFlags(method.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          if(parameterNames != null) proposal.setParameterNames(parameterNames);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }

        // Javadoc proposal
        if ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_METHOD_REF)) {
          char[] javadocCompletion = inlineTagCompletion(completion, JavadocTagConstants.TAG_LINK);
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.JAVADOC_METHOD_REF, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(method.declaringClass));
          proposal.setSignature(getSignature(method));
          MethodBinding original = method.original();
          if(original != method) {
            proposal.setOriginalSignature(getSignature(original));
          }
          proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
          proposal.setParameterPackageNames(parameterPackageNames);
          proposal.setParameterTypeNames(parameterTypeNames);
          proposal.setPackageName(method.returnType.qualifiedPackageName());
          proposal.setTypeName(method.returnType.qualifiedSourceName());
          proposal.setName(method.selector);
          proposal.setCompletion(javadocCompletion);
          proposal.setFlags(method.modifiers);
          int start = (this.assistNodeInJavadoc & CompletionOnJavadoc.REPLACE_TAG) != 0 ? this.javadocTagPosition : this.startPosition;
          proposal.setReplaceRange(start - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance+R_INLINE_TAG);
          if(parameterNames != null) proposal.setParameterNames(parameterNames);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      } else {
        if(!this.isIgnored(CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER, missingElements != null)) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER, this.actualCompletionPosition);
          proposal.setDeclarationSignature(getSignature(method.declaringClass));
          proposal.setSignature(getSignature(method));
          MethodBinding original = method.original();
          if(original != method) {
            proposal.setOriginalSignature(getSignature(original));
          }
          proposal.setReceiverSignature(getSignature(receiverType));
          proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
          proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
          proposal.setParameterPackageNames(parameterPackageNames);
          proposal.setParameterTypeNames(parameterTypeNames);
          proposal.setPackageName(method.returnType.qualifiedPackageName());
          proposal.setTypeName(method.returnType.qualifiedSourceName());
          proposal.setName(method.selector);
          if (missingElements != null) {
            CompletionProposal[] subProposals = new CompletionProposal[missingElements.length];
            for (int i = 0; i < missingElements.length; i++) {
              subProposals[i] =
                createRequiredTypeProposal(
                    missingElements[i],
                    missingElementsStarts[i],
                    missingElementsEnds[i],
                    relevance);
            }
            proposal.setRequiredProposals(subProposals);
          }
          proposal.setCompletion(completion);
          proposal.setFlags(method.modifiers);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setReceiverRange(receiverStart - this.offset, receiverEnd - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          if(parameterNames != null) proposal.setParameterNames(parameterNames);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
      this.startPosition = previousStartPosition;
      this.tokenStart = previousTokenStart;
    }

    methodsFound.addAll(newMethodsFound);
  }
  private void findLocalMethodsFromFavorites(
      char[] methodName,
      MethodBinding[] methods,
      Scope scope,
      ObjectVector methodsFound,
      ObjectVector methodsFoundFromFavorites,
      ReferenceBinding receiverType,
      InvocationSite invocationSite,
      Scope invocationScope) {

      char[] typeName = CharOperation.concatWith(receiverType.compoundName, '.');

      int methodLength = methodName.length;

      next : for (int f = methods.length; --f >= 0;) {
        MethodBinding method = methods[f];

        if (method.isSynthetic()) continue next;

        if (method.isDefaultAbstract())  continue next;

        if (method.isConstructor()) continue next;

        if (this.options.checkDeprecation &&
            method.isViewedAsDeprecated() &&
            !scope.isDefinedInSameUnit(method.declaringClass))
          continue next;

        if (!method.isStatic()) continue next;

        if (this.options.checkVisibility
          && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next;

        if (methodLength > method.selector.length) continue next;

        if (!CharOperation.prefixEquals(methodName, method.selector, false /* ignore case */)
            && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) {
          continue next;
        }

        for (int i = methodsFoundFromFavorites.size; --i >= 0;) {
          Object[] other = (Object[]) methodsFoundFromFavorites.elementAt(i);
          MethodBinding otherMethod = (MethodBinding) other[0];

          if (method == otherMethod) continue next;

          if (CharOperation.equals(method.selector, otherMethod.selector, true)) {
            if (otherMethod.declaringClass == method.declaringClass &&
                this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) {
              continue next;
            }
          }
        }

        for (int i = methodsFound.size; --i >= 0;) {
          Object[] other = (Object[]) methodsFound.elementAt(i);
          MethodBinding otherMethod = (MethodBinding) other[0];

          if (method == otherMethod) continue next;

          if (CharOperation.equals(method.selector, otherMethod.selector, true)) {
            if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) {
              continue next;
            }
          }
        }

        boolean proposeStaticImport = !(this.compilerOptions.complianceLevel < ClassFileConstants.JDK1_5) &&
          this.options.suggestStaticImport;

        boolean isAlreadyImported = false;
        if (!proposeStaticImport) {
          if(!this.importCachesInitialized) {
            initializeImportCaches();
          }
          for (int j = 0; j < this.importCacheCount; j++) {
            char[][] importName = this.importsCache[j];
            if(CharOperation.equals(receiverType.sourceName, importName[0])) {
              if (!CharOperation.equals(typeName, importName[1])) {
                continue next;
              } else {
                isAlreadyImported = true;
              }
            }
          }
        }

        methodsFoundFromFavorites.add(new Object[]{method, receiverType});

        ReferenceBinding superTypeWithSameErasure = (ReferenceBinding)receiverType.findSuperTypeOriginatingFrom(method.declaringClass);
        if (method.declaringClass != superTypeWithSameErasure) {
          MethodBinding[] otherMethods = superTypeWithSameErasure.getMethods(method.selector);
          for (int i = 0; i < otherMethods.length; i++) {
            if(otherMethods[i].original() == method.original()) {
              method = otherMethods[i];
            }
          }
        }

        int length = method.parameters.length;
        char[][] parameterPackageNames = new char[length][];
        char[][] parameterTypeNames = new char[length][];

        for (int i = 0; i < length; i++) {
          TypeBinding type = method.original().parameters[i];
          parameterPackageNames[i] = type.qualifiedPackageName();
          parameterTypeNames[i] = type.qualifiedSourceName();
        }
        char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);

        char[] completion = CharOperation.NO_CHAR;

        int previousStartPosition = this.startPosition;
        int previousTokenStart = this.tokenStart;

        if (this.source != null
          && this.source.length > this.endPosition
          && this.source[this.endPosition] == '(') {
          completion = method.selector;
        } else {
          completion = CharOperation.concat(method.selector, new char[] { '(', ')' });
        }

        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal();
        relevance += computeRelevanceForCaseMatching(methodName, method.selector);
        relevance += computeRelevanceForExpectingType(method.returnType);
        relevance += computeRelevanceForEnumConstant(method.returnType);
        relevance += computeRelevanceForStatic(true, method.isStatic());
        relevance += computeRelevanceForQualification(true);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

        CompilationUnitDeclaration cu = this.unitScope.referenceContext;
        int importStart = cu.types[0].declarationSourceStart;
        int importEnd = importStart;

        this.noProposal = false;

        if (!proposeStaticImport) {
          if (isAlreadyImported) {
            if (!isIgnored(CompletionProposal.METHOD_REF)) {
              completion = CharOperation.concat(receiverType.sourceName, completion, '.');

              InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
              proposal.setDeclarationSignature(getSignature(method.declaringClass));
              proposal.setSignature(getSignature(method));
              MethodBinding original = method.original();
              if(original != method) {
                proposal.setOriginalSignature(getSignature(original));
              }
              proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
              proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
              proposal.setParameterPackageNames(parameterPackageNames);
              proposal.setParameterTypeNames(parameterTypeNames);
              proposal.setPackageName(method.returnType.qualifiedPackageName());
              proposal.setTypeName(method.returnType.qualifiedSourceName());
              proposal.setName(method.selector);
              proposal.setCompletion(completion);
              proposal.setFlags(method.modifiers);
              proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
              proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
              proposal.setRelevance(relevance);
              if(parameterNames != null) proposal.setParameterNames(parameterNames);

              this.requestor.accept(proposal);
              if(DEBUG) {
                this.printDebug(proposal);
              }
            }
          } else if (!this.isIgnored(CompletionProposal.METHOD_REF, CompletionProposal.TYPE_IMPORT)) {
            completion = CharOperation.concat(receiverType.sourceName, completion, '.');

            InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(method.declaringClass));
            proposal.setSignature(getSignature(method));
            MethodBinding original = method.original();
            if(original != method) {
              proposal.setOriginalSignature(getSignature(original));
            }
            proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
            proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
            proposal.setParameterPackageNames(parameterPackageNames);
            proposal.setParameterTypeNames(parameterTypeNames);
            proposal.setPackageName(method.returnType.qualifiedPackageName());
            proposal.setTypeName(method.returnType.qualifiedSourceName());
            proposal.setName(method.selector);
            proposal.setCompletion(completion);
            proposal.setFlags(method.modifiers);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            if(parameterNames != null) proposal.setParameterNames(parameterNames);

            char[] typeImportCompletion = createImportCharArray(typeName, false, false);

            InternalCompletionProposal typeImportProposal = createProposal(CompletionProposal.TYPE_IMPORT, this.actualCompletionPosition);
            typeImportProposal.nameLookup = this.nameEnvironment.nameLookup;
            typeImportProposal.completionEngine = this;
            char[] packageName = receiverType.qualifiedPackageName();
            typeImportProposal.setDeclarationSignature(packageName);
            typeImportProposal.setSignature(getSignature(receiverType));
            typeImportProposal.setPackageName(packageName);
            typeImportProposal.setTypeName(receiverType.qualifiedSourceName());
            typeImportProposal.setCompletion(typeImportCompletion);
            typeImportProposal.setFlags(receiverType.modifiers);
            typeImportProposal.setAdditionalFlags(CompletionFlags.Default);
            typeImportProposal.setReplaceRange(importStart - this.offset, importEnd - this.offset);
            typeImportProposal.setTokenRange(importStart - this.offset, importEnd - this.offset);
            typeImportProposal.setRelevance(relevance);

            proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal});

            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        } else {
          if (!this.isIgnored(CompletionProposal.METHOD_REF, CompletionProposal.METHOD_IMPORT)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
            proposal.setDeclarationSignature(getSignature(method.declaringClass));
            proposal.setSignature(getSignature(method));
            MethodBinding original = method.original();
            if(original != method) {
              proposal.setOriginalSignature(getSignature(original));
            }
            proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
            proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
            proposal.setParameterPackageNames(parameterPackageNames);
            proposal.setParameterTypeNames(parameterTypeNames);
            proposal.setPackageName(method.returnType.qualifiedPackageName());
            proposal.setTypeName(method.returnType.qualifiedSourceName());
            proposal.setName(method.selector);
            proposal.setCompletion(completion);
            proposal.setFlags(method.modifiers);
            proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            if(parameterNames != null) proposal.setParameterNames(parameterNames);

            char[] methodImportCompletion = createImportCharArray(CharOperation.concat(typeName, method.selector, '.'), true, false);

            InternalCompletionProposal methodImportProposal = createProposal(CompletionProposal.METHOD_IMPORT, this.actualCompletionPosition);
            methodImportProposal.setDeclarationSignature(getSignature(method.declaringClass));
            methodImportProposal.setSignature(getSignature(method));
            if(original != method) {
              proposal.setOriginalSignature(getSignature(original));
            }
            methodImportProposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
            methodImportProposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
            methodImportProposal.setParameterPackageNames(parameterPackageNames);
            methodImportProposal.setParameterTypeNames(parameterTypeNames);
            methodImportProposal.setPackageName(method.returnType.qualifiedPackageName());
            methodImportProposal.setTypeName(method.returnType.qualifiedSourceName());
            methodImportProposal.setName(method.selector);
            methodImportProposal.setCompletion(methodImportCompletion);
            methodImportProposal.setFlags(method.modifiers);
            methodImportProposal.setAdditionalFlags(CompletionFlags.StaticImport);
            methodImportProposal.setReplaceRange(importStart - this.offset, importEnd - this.offset);
            methodImportProposal.setTokenRange(importStart - this.offset, importEnd - this.offset);
            methodImportProposal.setRelevance(relevance);
            if(parameterNames != null) methodImportProposal.setParameterNames(parameterNames);

            proposal.setRequiredProposals(new CompletionProposal[]{methodImportProposal});

            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }

        this.startPosition = previousStartPosition;
        this.tokenStart = previousTokenStart;
      }
    }

  /**
   * Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean)
   * Note that the method doesn't do a comparison of the method names and expects the client to handle the same.
   *
   * @methodName method as entered by the user, the one to completed
   * @param methods a resultant array of MethodBinding, whose names should match methodName. The calling client must ensure that this check is handled.
   */
  private void findLocalMethodsFromStaticImports(
    char[] methodName,
    MethodBinding[] methods,
    Scope scope,
    boolean exactMatch,
    ObjectVector methodsFound,
    ReferenceBinding receiverType,
    InvocationSite invocationSite) {

    ObjectVector newMethodsFound =  new ObjectVector();

    next : for (int f = methods.length; --f >= 0;) {
      MethodBinding method = methods[f];

      if (method.isSynthetic()) continue next;

      if (method.isDefaultAbstract())  continue next;

      if (method.isConstructor()) continue next;

      if (!method.isStatic()) continue next;

      if (this.options.checkDeprecation &&
          method.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(method.declaringClass))
        continue next;

      if (this.options.checkVisibility
        && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next;

      for (int i = methodsFound.size; --i >= 0;) {
        Object[] other = (Object[]) methodsFound.elementAt(i);
        MethodBinding otherMethod = (MethodBinding) other[0];
        ReferenceBinding otherReceiverType = (ReferenceBinding) other[1];
        if (method == otherMethod && receiverType == otherReceiverType)
          continue next;

        if (CharOperation.equals(method.selector, otherMethod.selector, true)) {
          if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) {
            continue next;
          }
        }
      }

      newMethodsFound.add(new Object[]{method, receiverType});

      int length = method.parameters.length;
      char[][] parameterPackageNames = new char[length][];
      char[][] parameterTypeNames = new char[length][];

      for (int i = 0; i < length; i++) {
        TypeBinding type = method.original().parameters[i];
        parameterPackageNames[i] = type.qualifiedPackageName();
        parameterTypeNames[i] = type.qualifiedSourceName();
      }
      char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);

      char[] completion = CharOperation.NO_CHAR;

      int previousStartPosition = this.startPosition;
      int previousTokenStart = this.tokenStart;

      if (!exactMatch) {
        if (this.source != null
          && this.source.length > this.endPosition
          && this.source[this.endPosition] == '(') {
          completion = method.selector;
        } else {
          completion = CharOperation.concat(method.selector, new char[] { '(', ')' });
        }
      } else {
        this.startPosition = this.endPosition;
        this.tokenStart = this.tokenEnd;
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(methodName, method.selector);
      relevance += computeRelevanceForExpectingType(method.returnType);
      relevance += computeRelevanceForEnumConstant(method.returnType);
      relevance += computeRelevanceForStatic(true, method.isStatic());
      relevance += computeRelevanceForQualification(false);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

      this.noProposal = false;
      if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
        InternalCompletionProposal proposal =  createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition);
        proposal.setDeclarationSignature(getSignature(method.declaringClass));
        proposal.setSignature(getSignature(method));
        MethodBinding original = method.original();
        if(original != method) {
          proposal.setOriginalSignature(getSignature(original));
        }
        proposal.setDeclarationPackageName(method.declaringClass.qualifiedPackageName());
        proposal.setDeclarationTypeName(method.declaringClass.qualifiedSourceName());
        proposal.setParameterPackageNames(parameterPackageNames);
        proposal.setParameterTypeNames(parameterTypeNames);
        proposal.setPackageName(method.returnType.qualifiedPackageName());
        proposal.setTypeName(method.returnType.qualifiedSourceName());
        proposal.setName(method.selector);
        proposal.setCompletion(completion);
        proposal.setFlags(method.modifiers);
        proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
        proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
        proposal.setRelevance(relevance);
        if(parameterNames != null) proposal.setParameterNames(parameterNames);
        this.requestor.accept(proposal);
        if(DEBUG) {
          this.printDebug(proposal);
        }
      }
      this.startPosition = previousStartPosition;
      this.tokenStart = previousTokenStart;
    }

    methodsFound.addAll(newMethodsFound);
  }

  private void findLocalMethodsFromStaticImports(
      char[] token,
      Scope scope,
      InvocationSite invocationSite,
      Scope invocationScope,
      boolean exactMatch,
      ObjectVector methodsFound,
      boolean proposeMethod) {
    findFieldsAndMethodsFromStaticImports(
        token,
        scope,
        invocationSite,
        invocationScope,
        exactMatch,
        false,
        new ObjectVector(),
        new ObjectVector(),
        methodsFound,
        false,
        proposeMethod);
  }
  protected void findMembers(
      char[] token,
      ReferenceBinding receiverType,
      Scope scope,
      InvocationSite invocationSite,
      boolean isInsideAnnotationAttribute,
      Binding[] missingElements,
      int[] missingElementsStarts,
      int[] missingElementsEnds,
      boolean missingElementsHaveProblems) {

    if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      findMemberTypes(
          token,
          receiverType,
          scope,
          scope.enclosingSourceType(),
          false,
          true,
          new ObjectVector(),
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems);
    }
    if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
      findClassField(
          token,
          receiverType,
          scope,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems);
    }

    MethodScope methodScope = null;
    if (!isInsideAnnotationAttribute &&
        !this.requestor.isIgnored(CompletionProposal.KEYWORD) &&
        ((scope instanceof MethodScope && !((MethodScope)scope).isStatic)
        || ((methodScope = scope.enclosingMethodScope()) != null && !methodScope.isStatic))) {
      if (token.length > 0) {
        findKeywords(token, new char[][]{Keywords.THIS}, false, true);
      } else {
        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal();
        relevance += computeRelevanceForCaseMatching(this.completionToken, Keywords.THIS);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywords
        relevance += R_NON_INHERITED;

        this.noProposal = false;
        if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition);
          proposal.setName(Keywords.THIS);
          proposal.setCompletion(Keywords.THIS);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if (DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    }

    if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) {
      findFields(
        token,
        receiverType,
        scope,
        new ObjectVector(),
        new ObjectVector(),
        true,
        invocationSite,
        scope,
        false,
        false,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        null,
        -1,
        -1);
    }

    if (!isInsideAnnotationAttribute && !this.requestor.isIgnored(CompletionProposal.METHOD_REF)) {
      findMethods(
        token,
        null,
        null,
        receiverType,
        scope,
        new ObjectVector(),
        true,
        false,
        invocationSite,
        scope,
        false,
        false,
        false,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems,
        null,
        -1,
        -1);
    }
  }

  private void findMembersFromMissingType(
      final char[] token,
      final long pos,
      TypeBinding resolveType,
      final Scope scope,
      final InvocationSite invocationSite,
      final boolean isInsideAnnotationAttribute) {
    MissingTypesGuesser missingTypesConverter = new MissingTypesGuesser(this);
    MissingTypesGuesser.GuessedTypeRequestor substitutionRequestor =
      new MissingTypesGuesser.GuessedTypeRequestor() {
        public void accept(
            TypeBinding guessedType,
            Binding[] missingElements,
            int[] missingElementsStarts,
            int[] missingElementsEnds,
            boolean hasProblems) {
          if (guessedType instanceof ReferenceBinding) {
            findMembers(
                CompletionEngine.this.completionToken,
                (ReferenceBinding)guessedType,
                scope,
                invocationSite,
                isInsideAnnotationAttribute,
                missingElements,
                missingElementsStarts,
                missingElementsEnds,
                hasProblems);
          }
        }
      };
    SingleTypeReference typeRef = new SingleTypeReference(token, pos);
    typeRef.resolvedType = new ProblemReferenceBinding(new char[][]{ token }, null, ProblemReasons.NotFound);
    missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
  }

  private void findMemberTypes(
    char[] typeName,
    ReferenceBinding receiverType,
    Scope scope,
    SourceTypeBinding typeInvocation,
    boolean staticOnly,
    boolean staticFieldsAndMethodOnly,
    boolean fromStaticImport,
    boolean checkQualification,
    boolean proposeAllMemberTypes,
    SourceTypeBinding typeToIgnore,
    ObjectVector typesFound,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems) {

    ReferenceBinding currentType = receiverType;
    if (typeName == null)
      return;

    if (this.insideQualifiedReference
      || typeName.length == 0) { // do not search up the hierarchy

      findMemberTypes(
        typeName,
        currentType.memberTypes(),
        typesFound,
        receiverType,
        typeInvocation,
        staticOnly,
        staticFieldsAndMethodOnly,
        fromStaticImport,
        checkQualification,
        scope,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems);
      return;
    }

    ReferenceBinding[] interfacesToVisit = null;
    int nextPosition = 0;

    do {
      ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
      if (itsInterfaces != null && itsInterfaces != Binding.NO_SUPERINTERFACES) {
        if (interfacesToVisit == null) {
          interfacesToVisit = itsInterfaces;
          nextPosition = interfacesToVisit.length;
        } else {
          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;
          }
        }
      }

      findMemberTypes(
        typeName,
        currentType.memberTypes(),
        typesFound,
        receiverType,
        typeInvocation,
        staticOnly,
        staticFieldsAndMethodOnly,
        fromStaticImport,
        checkQualification,
        scope,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems);

      currentType = currentType.superclass();
    } while (currentType != null);

    if(proposeAllMemberTypes) {
      ReferenceBinding[] memberTypes = receiverType.memberTypes();
      for (int i = 0; i < memberTypes.length; i++) {
        if(memberTypes[i] != typeToIgnore) {
          findSubMemberTypes(
            typeName,
            memberTypes[i],
            scope,
            typeInvocation,
            staticOnly,
            staticFieldsAndMethodOnly,
            fromStaticImport,
            typesFound);
        }
      }
    }

    if (interfacesToVisit != null) {
      for (int i = 0; i < nextPosition; i++) {
        ReferenceBinding anInterface = interfacesToVisit[i];
        findMemberTypes(
          typeName,
          anInterface.memberTypes(),
          typesFound,
          receiverType,
          typeInvocation,
          staticOnly,
          staticFieldsAndMethodOnly,
          fromStaticImport,
          checkQualification,
          scope,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems);

        ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
        if (itsInterfaces != null && itsInterfaces != 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;
          }
        }
      }
    }
  }

  protected void findMemberTypes(
    char[] typeName,
    ReferenceBinding receiverType,
    Scope scope,
    SourceTypeBinding typeInvocation,
    boolean staticOnly,
    boolean staticFieldsAndMethodOnly,
    ObjectVector typesFound,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems)  {
    findMemberTypes(
        typeName,
        receiverType,
        scope,
        typeInvocation,
        staticOnly,
        staticFieldsAndMethodOnly,
        false,
        false,
        false,
        null,
        typesFound,
        missingElements,
        missingElementsStarts,
        missingElementsEnds,
        missingElementsHaveProblems);
  }
    // Helper method for findMemberTypes(char[], ReferenceBinding, Scope)
  private void findMemberTypes(
    char[] typeName,
    ReferenceBinding[] memberTypes,
    ObjectVector typesFound,
    ReferenceBinding receiverType,
    SourceTypeBinding invocationType,
    boolean staticOnly,
    boolean staticFieldsAndMethodOnly,
    boolean fromStaticImport,
    boolean checkQualification,
    Scope scope,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems) {

    // Inherited member types which are hidden by subclasses are filtered out
    // No visibility checks can be performed without the scope & invocationSite
    int typeLength = typeName.length;
    next : for (int m = memberTypes.length; --m >= 0;) {
      ReferenceBinding memberType = memberTypes[m];
      //    if (!wantClasses && memberType.isClass()) continue next;
      //    if (!wantInterfaces && memberType.isInterface()) continue next;

      if (staticOnly && !memberType.isStatic()) continue next;

      if (isForbidden(memberType)) continue next;

      if (typeLength > memberType.sourceName.length)
        continue next;

      if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */)
          && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName)))
        continue next;

      if (this.options.checkDeprecation &&
          memberType.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(memberType))
        continue next;

      if (this.options.checkVisibility) {
        if (invocationType != null && !memberType.canBeSeenBy(receiverType, invocationType)) {
          continue next;
        } else if(invocationType == null && !memberType.canBeSeenBy(this.unitScope.fPackage)) {
          continue next;
        }
      }

      if (this.insideQualifiedReference &&
          receiverType.isParameterizedType() &&
          memberType.isStatic()) {
        continue next;
      }

      for (int i = typesFound.size; --i >= 0;) {
        ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i);

        if (memberType == otherType)
          continue next;

        if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) {

          if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType()))
            continue next;

          if (otherType.enclosingType().isInterface())
            if (memberType.enclosingType()
              .implementsInterface(otherType.enclosingType(), true))
              continue next;

          if (memberType.enclosingType().isInterface())
            if (otherType.enclosingType()
              .implementsInterface(memberType.enclosingType(), true))
              continue next;
        }
      }

      typesFound.add(memberType);

      if (this.assistNodeIsExtendedType && memberType.isFinal()) continue next;
      if (this.assistNodeIsInterfaceExcludingAnnotation && memberType.isAnnotationType()) continue next;
      if(!this.insideQualifiedReference) {
        if(this.assistNodeIsClass || this.assistNodeIsException) {
          if(!memberType.isClass()) continue next;
        } else if(this.assistNodeIsInterface) {
          if(!memberType.isInterface() && !memberType.isAnnotationType()) continue next;
        } else if (this.assistNodeIsAnnotation) {
          if(!memberType.isAnnotationType()) continue next;
        }
      }

      char[] completionName = memberType.sourceName();

      boolean isQualified = false;
      if(checkQualification && !fromStaticImport) {
        char[] memberPackageName = memberType.qualifiedPackageName();
        char[] memberTypeName = memberType.sourceName();
        char[] memberEnclosingTypeNames = memberType.enclosingType().qualifiedSourceName();
        if (mustQualifyType(memberPackageName, memberTypeName, memberEnclosingTypeNames, memberType.modifiers)) {
          if (memberPackageName == null || memberPackageName.length == 0)
            if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
              break next; // ignore types from the default package from outside it
          isQualified = true;
          completionName =
            CharOperation.concat(
                memberPackageName,
                CharOperation.concat(
                    memberEnclosingTypeNames,
                    memberTypeName,
                    '.'),
                '.');
        }
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal(memberType);
      relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName);
      relevance += computeRelevanceForExpectingType(memberType);
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);
      if(!this.insideQualifiedReference) {
        relevance += computeRelevanceForQualification(isQualified);
      }
      if (staticFieldsAndMethodOnly && this.insideQualifiedReference) relevance += R_NON_INHERITED; // This criterion doesn't concern types and is added to be balanced with field and method relevance.

      if (memberType.isAnnotationType()) {
        relevance += computeRelevanceForAnnotation();
        relevance += computeRelevanceForAnnotationTarget(memberType);
      } else if (memberType.isClass()) {
        relevance += computeRelevanceForClass();
        relevance += computeRelevanceForException(memberType.sourceName);
      } else if(memberType.isEnum()) {
        relevance += computeRelevanceForEnum();
      } else if(memberType.isInterface()) {
        relevance += computeRelevanceForInterface();
      }

      if (missingElements != null) {
        relevance += computeRelevanceForMissingElements(missingElementsHaveProblems);
      }

      boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
     
      this.noProposal = false;
      if (!this.assistNodeIsConstructor ||
          !allowingLongComputationProposals ||
          hasStaticMemberTypes(memberType, invocationType, this.unitScope) ||
          (memberType instanceof SourceTypeBinding && hasMemberTypesInEnclosingScope((SourceTypeBinding)memberType, scope)) ||
          hasArrayTypeAsExpectedSuperTypes()) {
        createTypeProposal(
            memberType,
            memberType.qualifiedSourceName(),
            IAccessRule.K_ACCESSIBLE,
            completionName,
            relevance,
            missingElements,
            missingElementsStarts,
            missingElementsEnds,
            missingElementsHaveProblems);
      }
     
      if (this.assistNodeIsConstructor && allowingLongComputationProposals) {
        findConstructorsOrAnonymousTypes(
            memberType,
            scope,
            FakeInvocationSite,
            isQualified,
            relevance);
      }
    }
  }
  private void findMemberTypesFromMissingType(
      char[] typeName,
      final long pos,
      final Scope scope)  {
    MissingTypesGuesser missingTypesConverter = new MissingTypesGuesser(this);
    MissingTypesGuesser.GuessedTypeRequestor substitutionRequestor =
      new MissingTypesGuesser.GuessedTypeRequestor() {
        public void accept(
            TypeBinding guessedType,
            Binding[] missingElements,
            int[] missingElementsStarts,
            int[] missingElementsEnds,
            boolean hasProblems) {
          if (guessedType instanceof ReferenceBinding) {
            findMemberTypes(
                CompletionEngine.this.completionToken,
                (ReferenceBinding)guessedType,
                scope,
                scope.enclosingSourceType(),
                false,
                false,
                new ObjectVector(),
                missingElements,
                missingElementsStarts,
                missingElementsEnds,
                hasProblems);
          }
        }
      };
    SingleTypeReference typeRef = new SingleTypeReference(typeName, pos);
    typeRef.resolvedType = new ProblemReferenceBinding(new char[][]{ typeName }, null, ProblemReasons.NotFound);
    missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
  }
 
  private void findMemberTypesFromMissingType(
      TypeReference typeRef,
      final long pos,
      final Scope scope)  {
    MissingTypesGuesser missingTypesConverter = new MissingTypesGuesser(this);
    MissingTypesGuesser.GuessedTypeRequestor substitutionRequestor =
      new MissingTypesGuesser.GuessedTypeRequestor() {
        public void accept(
            TypeBinding guessedType,
            Binding[] missingElements,
            int[] missingElementsStarts,
            int[] missingElementsEnds,
            boolean hasProblems) {
          if (guessedType instanceof ReferenceBinding) {
            findMemberTypes(
                CompletionEngine.this.completionToken,
                (ReferenceBinding)guessedType,
                scope,
                scope.enclosingSourceType(),
                false,
                false,
                new ObjectVector(),
                missingElements,
                missingElementsStarts,
                missingElementsEnds,
                hasProblems);
          }
        }
      };
    missingTypesConverter.guess(typeRef, scope, substitutionRequestor);
  }

  private void findMethodDeclarations(
    char[] selector,
    ReferenceBinding receiverType,
    Scope scope,
    ObjectVector methodsFound,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems) {

    if (selector == null) {
      return;
    }

    MethodBinding[] receiverTypeMethods = receiverType.availableMethods();
    if (receiverTypeMethods != null){
      for (int i = 0; i < receiverTypeMethods.length; i++) {
        if(!receiverTypeMethods[i].isDefaultAbstract()) {
          methodsFound.add(receiverTypeMethods[i]);
        }
      }
    }

    ReferenceBinding currentType = receiverType;
   
    findInterfacesMethodDeclarations(
      selector,
      receiverType,
      currentType.superInterfaces(),
      scope,
      methodsFound,
      missingElements,
      missingElementsStarts,
      missingElementsEnds,
      missingElementsHaveProblems);
   
    if (receiverType.isInterface()) {
      currentType = scope.getJavaLangObject();
    } else {
      currentType = receiverType.superclass();
    }
   
    boolean hasPotentialDefaultAbstractMethods = true;
    while (currentType != null) {

      MethodBinding[] methods = currentType.availableMethods();
      if (methods != null) {
        findLocalMethodDeclarations(
          selector,
          methods,
          scope,
          methodsFound,
          false,
          receiverType);
      }

      if (hasPotentialDefaultAbstractMethods &&
          (currentType.isAbstract() ||
              currentType.isTypeVariable() ||
              currentType.isIntersectionType() ||
              currentType.isEnum())){

        ReferenceBinding[] superInterfaces = currentType.superInterfaces();

        findInterfacesMethodDeclarations(
          selector,
          receiverType,
          superInterfaces,
          scope,
          methodsFound,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems);
      } else {
        hasPotentialDefaultAbstractMethods = false;
      }
      currentType = currentType.superclass();
    }
  }
 
  private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){
    TypeBinding erasure =  method.declaringClass.erasure();
    if(!(erasure instanceof ReferenceBinding)) return null;

    char[][] parameterNames = null;

    int length = parameterTypeNames.length;

    if (length == 0){
      return CharOperation.NO_CHAR_CHAR;
    }
    // look into the corresponding unit if it is available
    if (erasure instanceof SourceTypeBinding){
      SourceTypeBinding sourceType = (SourceTypeBinding) erasure;

      if (sourceType.scope != null){
        TypeDeclaration parsedType;

        if ((parsedType = sourceType.scope.referenceContext) != null){
          AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method.original());

          if (methodDecl != null){
            Argument[] arguments = methodDecl.arguments;
            parameterNames = new char[length][];

            for(int i = 0 ; i < length ; i++){
              parameterNames[i] = arguments[i].name;
            }
          }
        }
      }
    }
    // look into the model
    if(parameterNames == null){

      ReferenceBinding bindingType = (ReferenceBinding)erasure;

      char[] compoundName = CharOperation.concatWith(bindingType.compoundName, '.');
      Object type = this.typeCache.get(compoundName);

      ISourceType sourceType = null;
      if(type != null) {
        if(type instanceof ISourceType) {
          sourceType = (ISourceType) type;
        }
      } else {
        NameEnvironmentAnswer answer = this.nameEnvironment.findType(bindingType.compoundName);
        if(answer != null && answer.isSourceType()) {
          sourceType = answer.getSourceTypes()[0];
          this.typeCache.put(compoundName, sourceType);
        }
      }

      if(sourceType != null) {
        IType typeHandle = ((SourceTypeElementInfo) sourceType).getHandle();

        String[] parameterTypeSignatures = new String[length];
        for (int i = 0; i < length; i++) {
          parameterTypeSignatures[i] = Signature.createTypeSignature(parameterTypeNames[i], false);
        }
        IMethod searchedMethod = typeHandle.getMethod(String.valueOf(method.selector), parameterTypeSignatures);
        IMethod[] foundMethods = typeHandle.findMethods(searchedMethod);

        if(foundMethods != null) {
          int len = foundMethods.length;
          if(len == 1) {
            try {
              SourceMethod sourceMethod = (SourceMethod) foundMethods[0];
              parameterNames = ((SourceMethodElementInfo) sourceMethod.getElementInfo()).getArgumentNames();
            } catch (JavaModelException e) {
              // method doesn't exist: ignore
            }
          }
        }
      }
    }
    return parameterNames;
  }

  private void findMethods(
    char[] selector,
    TypeBinding[] typeArgTypes,
    TypeBinding[] argTypes,
    ReferenceBinding receiverType,
    Scope scope,
    ObjectVector methodsFound,
    boolean onlyStaticMethods,
    boolean exactMatch,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean implicitCall,
    boolean superCall,
    boolean canBePrefixed,
    Binding[] missingElements,
    int[] missingElementsStarts,
    int[] missingElementsEnds,
    boolean missingElementsHaveProblems,
    char[] castedReceiver,
    int receiverStart,
    int receiverEnd) {

    boolean notInJavadoc = this.assistNodeInJavadoc == 0;
    if (selector == null && notInJavadoc) {
      return;
    }
   
    if (this.assistNodeIsInsideCase)
      return;    // no methods should be proposed inside case expression

    ReferenceBinding currentType = receiverType;
    if (notInJavadoc) {
      if (receiverType.isInterface()) {
        findInterfacesMethods(
          selector,
          typeArgTypes,
          argTypes,
          receiverType,
          new ReferenceBinding[]{currentType},
          scope,
          methodsFound,
          onlyStaticMethods,
          exactMatch,
          invocationSite,
          invocationScope,
          implicitCall,
          superCall,
          canBePrefixed,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems,
          castedReceiver,
          receiverStart,
          receiverEnd);

        currentType = scope.getJavaLangObject();
      }
    }
    boolean hasPotentialDefaultAbstractMethods = true;
    while (currentType != null) {

      MethodBinding[] methods = currentType.availableMethods();
      if (methods != null) {
        findLocalMethods(
          selector,
          typeArgTypes,
          argTypes,
          methods,
          scope,
          methodsFound,
          onlyStaticMethods,
          exactMatch,
          receiverType,
          invocationSite,
          invocationScope,
          implicitCall,
          superCall,
          canBePrefixed,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems,
          castedReceiver,
          receiverStart,
          receiverEnd);
      }

      if (hasPotentialDefaultAbstractMethods &&
          (currentType.isAbstract() ||
              currentType.isTypeVariable() ||
              currentType.isIntersectionType() ||
              currentType.isEnum())){

        ReferenceBinding[] superInterfaces = currentType.superInterfaces();
        if (superInterfaces != null && currentType.isIntersectionType()) {
          for (int i = 0; i < superInterfaces.length; i++) {
            superInterfaces[i] = (ReferenceBinding)superInterfaces[i].capture(invocationScope, invocationSite.sourceEnd());
          }
        }

        findInterfacesMethods(
          selector,
          typeArgTypes,
          argTypes,
          receiverType,
          superInterfaces,
          scope,
          methodsFound,
          onlyStaticMethods,
          exactMatch,
          invocationSite,
          invocationScope,
          implicitCall,
          superCall,
          canBePrefixed,
          missingElements,
          missingElementsStarts,
          missingElementsEnds,
          missingElementsHaveProblems,
          castedReceiver,
          receiverStart,
          receiverEnd);
      } else {
        hasPotentialDefaultAbstractMethods = false;
      }
      currentType = currentType.superclass();
    }
  }

  private void findNestedTypes(
    char[] typeName,
    SourceTypeBinding currentType,
    Scope scope,
    boolean proposeAllMemberTypes,
    ObjectVector typesFound) {
   
    if (typeName == null)
      return;

    int typeLength = typeName.length;

    SourceTypeBinding nextTypeToIgnore = null;
    while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found

      switch (scope.kind) {

        case Scope.METHOD_SCOPE :
        case Scope.BLOCK_SCOPE :
          BlockScope blockScope = (BlockScope) scope;

          next : for (int i = 0, length = blockScope.subscopeCount; i < length; i++) {

            if (blockScope.subscopes[i] instanceof ClassScope) {
              SourceTypeBinding localType =
                ((ClassScope) blockScope.subscopes[i]).referenceContext.binding;

              if (!localType.isAnonymousType()) {
                if (isForbidden(localType))
                  continue next;

                if (typeLength > localType.sourceName.length)
                  continue next;
                if (!CharOperation.prefixEquals(typeName, localType.sourceName, false/* ignore case */)
                    && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, localType.sourceName)))
                  continue next;

                for (int j = typesFound.size; --j >= 0;) {
                  ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j);

                  if (localType == otherType)
                    continue next;
                }

                if (this.assistNodeIsExtendedType && localType.isFinal()) continue next;
                if (this.assistNodeIsInterfaceExcludingAnnotation && localType.isAnnotationType()) continue next;
                if(this.assistNodeIsClass) {
                  if(!localType.isClass()) continue next;
                } else if(this.assistNodeIsInterface) {
                  if(!localType.isInterface() && !localType.isAnnotationType()) continue next;
                } else if (this.assistNodeIsAnnotation) {
                  if(!localType.isAnnotationType()) continue next;
                }

                int relevance = computeBaseRelevance();
                relevance += computeRelevanceForResolution();
                relevance += computeRelevanceForInterestingProposal(localType);
                relevance += computeRelevanceForCaseMatching(typeName, localType.sourceName);
                relevance += computeRelevanceForExpectingType(localType);
                relevance += computeRelevanceForException(localType.sourceName);
                relevance += computeRelevanceForClass();
                relevance += computeRelevanceForQualification(false);
                relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for nested type
                relevance += computeRelevanceForAnnotationTarget(localType);

                boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
                if (!this.assistNodeIsConstructor || !allowingLongComputationProposals || hasArrayTypeAsExpectedSuperTypes()) {
                  this.noProposal = false;
                  if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
                    createTypeProposal(
                        localType,
                        localType.sourceName,
                        IAccessRule.K_ACCESSIBLE,
                        localType.sourceName,
                        relevance,
                        null,
                        null,
                        null,
                        false);
                  }
                }
               
                if (this.assistNodeIsConstructor && allowingLongComputationProposals) {
                  findConstructorsOrAnonymousTypes(
                      localType,
                      blockScope,
                      FakeInvocationSite,
                      false,
                      relevance);
                }
              }
            }
          }
          break;

        case Scope.CLASS_SCOPE :
          SourceTypeBinding enclosingSourceType = scope.enclosingSourceType();
          findMemberTypes(
              typeName,
              enclosingSourceType,
              scope,
              currentType,
              false,
              false,
              false,
              false,
              proposeAllMemberTypes,
              nextTypeToIgnore,
              typesFound,
              null,
              null,
              null,
              false);
          nextTypeToIgnore = enclosingSourceType;
          if (typeLength == 0)
            return; // do not search outside the class scope if no prefix was provided
          break;

        case Scope.COMPILATION_UNIT_SCOPE :
          return;
      }
      scope = scope.parent;
    }
  }

  private void findPackages(CompletionOnPackageReference packageStatement) {

    this.completionToken = CharOperation.concatWith(packageStatement.tokens, '.');
    if (this.completionToken.length == 0)
      return;

    setSourceRange(packageStatement.sourceStart, packageStatement.sourceEnd);
    long completionPosition = packageStatement.sourcePositions[packageStatement.sourcePositions.length - 1];
    setTokenRange((int) (completionPosition >>> 32), (int) completionPosition);
    this.nameEnvironment.findPackages(CharOperation.toLowerCase(this.completionToken), this);
  }

  private void findParameterizedType(TypeReference ref, Scope scope) {
    ReferenceBinding refBinding = (ReferenceBinding) ref.resolvedType;
    if(refBinding != null) {
      if (this.options.checkDeprecation &&
          refBinding.isViewedAsDeprecated() &&
          !scope.isDefinedInSameUnit(refBinding))
        return;

      int accessibility = IAccessRule.K_ACCESSIBLE;
      if(refBinding.hasRestrictedAccess()) {
        AccessRestriction accessRestriction = this.lookupEnvironment.getAccessRestriction(refBinding);
        if(accessRestriction != null) {
          switch (accessRestriction.getProblemId()) {
            case IProblem.ForbiddenReference:
              if (this.options.checkForbiddenReference) {
                return;
              }
              accessibility = IAccessRule.K_NON_ACCESSIBLE;
              break;
            case IProblem.DiscouragedReference:
              if (this.options.checkDiscouragedReference) {
                return;
              }
              accessibility = IAccessRule.K_DISCOURAGED;
              break;
          }
        }
      }

      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForCaseMatching(refBinding.sourceName, refBinding.sourceName);
      relevance += computeRelevanceForExpectingType(refBinding);
      relevance += computeRelevanceForQualification(false);
      relevance += computeRelevanceForRestrictions(accessibility); // no access restriction for type in the current unit

      if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
        createTypeProposal(
            refBinding,
            refBinding.qualifiedSourceName(),
            IAccessRule.K_ACCESSIBLE,
            CharOperation.NO_CHAR,
            relevance,
            null,
            null,
            null,
            false);
      }
    }
  }

  private void findSubMemberTypes(
    char[] typeName,
    ReferenceBinding receiverType,
    Scope scope,
    SourceTypeBinding typeInvocation,
    boolean staticOnly,
    boolean staticFieldsAndMethodOnly,
    boolean fromStaticImport,
    ObjectVector typesFound) {

    ReferenceBinding currentType = receiverType;
    if (typeName == null)
      return;

    if (this.assistNodeIsSuperType && !this.insideQualifiedReference && isForbidden(currentType)) return; // we're trying to find a supertype

    findMemberTypes(
        typeName,
        currentType.memberTypes(),
        typesFound,
        receiverType,
        typeInvocation,
        staticOnly,
        staticFieldsAndMethodOnly,
        fromStaticImport,
        true,
        scope,
        null,
        null,
        null,
        false);

    ReferenceBinding[] memberTypes = receiverType.memberTypes();
    next : for (int i = 0; i < memberTypes.length; i++) {
      if (this.options.checkVisibility) {
        if (typeInvocation != null && !memberTypes[i].canBeSeenBy(receiverType, typeInvocation)) {
          continue next;
        } else if(typeInvocation == null && !memberTypes[i].canBeSeenBy(this.unitScope.fPackage)) {
          continue next;
        }
      }
      findSubMemberTypes(
        typeName,
        memberTypes[i],
        scope,
        typeInvocation,
        staticOnly,
        staticFieldsAndMethodOnly,
        fromStaticImport,
        typesFound);
    }
  }

  private void findTrueOrFalseKeywords(char[][] choices) {
    if(choices == null || choices.length == 0) return;

    if(this.expectedTypesPtr != 0 || this.expectedTypes[0] != TypeBinding.BOOLEAN) return;

    for (int i = 0; i < choices.length; i++) {
      if (CharOperation.equals(choices[i], Keywords.TRUE) ||
          CharOperation.equals(choices[i], Keywords.FALSE)
      ){
        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal();
        relevance += computeRelevanceForCaseMatching(CharOperation.NO_CHAR, choices[i]);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywors
        relevance += computeRelevanceForExpectingType(TypeBinding.BOOLEAN);
        relevance += computeRelevanceForQualification(false);
        relevance += R_TRUE_OR_FALSE;

        this.noProposal = false;
        if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
          InternalCompletionProposal proposal =  createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition);
          proposal.setName(choices[i]);
          proposal.setCompletion(choices[i]);
          proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
          proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
          proposal.setRelevance(relevance);
          this.requestor.accept(proposal);
          if(DEBUG) {
            this.printDebug(proposal);
          }
        }
      }
    }
  }

  private void findTypeParameters(char[] token, Scope scope) {
    if (this.compilerOptions.sourceLevel < ClassFileConstants.JDK1_5) return;

    TypeParameter[] typeParameters = null;
    while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found
      typeParameters = null;
      switch (scope.kind) {
        case Scope.METHOD_SCOPE :
          MethodScope methodScope = (MethodScope) scope;
          if(methodScope.referenceContext instanceof MethodDeclaration) {
            MethodDeclaration methodDeclaration = (MethodDeclaration) methodScope.referenceContext;
            typeParameters = methodDeclaration.typeParameters;
          } else if(methodScope.referenceContext instanceof ConstructorDeclaration) {
            ConstructorDeclaration methodDeclaration = (ConstructorDeclaration) methodScope.referenceContext;
            typeParameters = methodDeclaration.typeParameters;
          }
          break;
        case Scope.CLASS_SCOPE :
          ClassScope classScope = (ClassScope) scope;
          typeParameters = classScope.referenceContext.typeParameters;
          break;
        case Scope.COMPILATION_UNIT_SCOPE :
          return;
      }
      if(typeParameters != null) {
        for (int i = 0; i < typeParameters.length; i++) {
          int typeLength = token.length;
          TypeParameter typeParameter = typeParameters[i];

          if(typeParameter.binding == null) continue;

          if (typeLength > typeParameter.name.length) continue;

          if (!CharOperation.prefixEquals(token, typeParameter.name, false)
              && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeParameter.name))) continue;

          int relevance = computeBaseRelevance();
          relevance += computeRelevanceForResolution();
          relevance += computeRelevanceForInterestingProposal();
          relevance += computeRelevanceForCaseMatching(token, typeParameter.name);
          relevance += computeRelevanceForExpectingType(typeParameter.type == null ? null :typeParameter.type.resolvedType);
          relevance += computeRelevanceForQualification(false);
          relevance += computeRelevanceForException(typeParameter.name);
          relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction fot type parameter

          this.noProposal = false;
          if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
            createTypeParameterProposal(typeParameter, relevance);
          }
        }
      }
      scope = scope.parent;
    }
  }

  private void findTypesAndPackages(char[] token, Scope scope, boolean proposeBaseTypes, boolean proposeVoidType, ObjectVector typesFound) {

    if (token == null)
      return;
   
    boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
   
    boolean proposeType =
      !this.requestor.isIgnored(CompletionProposal.TYPE_REF) ||
      ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF));

    boolean proposeAllMemberTypes = !this.assistNodeIsConstructor;
   
    boolean proposeConstructor =
      allowingLongComputationProposals &&
      this.assistNodeIsConstructor &&
      (!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF) ||
          !isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF));
   

    if ((proposeType || proposeConstructor) && scope.enclosingSourceType() != null) {
     
      checkCancel();
     
      findNestedTypes(token, scope.enclosingSourceType(), scope, proposeAllMemberTypes, typesFound);
      if(!this.assistNodeIsInterface &&
          !this.assistNodeIsConstructor &&
          !this.assistNodeIsAnnotation &&
          this.assistNodeInJavadoc == 0) {
       
        checkCancel();
       
        // don't propose type parameters if the completion is a constructor ('new |')
        findTypeParameters(token, scope);
      }
    }

    boolean isEmptyPrefix = token.length == 0;

    if ((proposeType || proposeConstructor) && this.unitScope != null) {
     
      ReferenceBinding outerInvocationType = scope.enclosingSourceType();
      if(outerInvocationType != null) {
        ReferenceBinding temp = outerInvocationType.enclosingType();
        while(temp != null) {
          outerInvocationType = temp;
          temp = temp.enclosingType();
        }
      }

      int typeLength = token.length;
      SourceTypeBinding[] types = this.unitScope.topLevelTypes;

      next : for (int i = 0, length = types.length; i < length; i++) {
       
        checkCancel();
       
        SourceTypeBinding sourceType = types[i];

        if(isForbidden(sourceType)) continue next;

        if(proposeAllMemberTypes &&
          sourceType != outerInvocationType) {
          findSubMemberTypes(
              token,
              sourceType,
              scope,
              scope.enclosingSourceType(),
              false,
              false,
              false,
              typesFound);
        }

        if (sourceType.sourceName == CompletionParser.FAKE_TYPE_NAME) continue next;
        if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME) continue next;

        if (typeLength > sourceType.sourceName.length) continue next;

        if (!CharOperation.prefixEquals(token, sourceType.sourceName, false)
            && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, sourceType.sourceName))) continue next;

        if (this.assistNodeIsAnnotation && !hasPossibleAnnotationTarget(sourceType, scope)) {
          continue next;
        }

        for (int j = typesFound.size; --j >= 0;) {
          ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j);

          if (sourceType == otherType) continue next;
        }
       
        typesFound.add(sourceType);

        if (this.assistNodeIsExtendedType && sourceType.isFinal()) continue next;
        if (this.assistNodeIsInterfaceExcludingAnnotation && sourceType.isAnnotationType()) continue next;
        if(this.assistNodeIsClass) {
          if(!sourceType.isClass()) continue next;
        } else if(this.assistNodeIsInterface) {
          if(!sourceType.isInterface() && !sourceType.isAnnotationType()) continue next;
        } else if (this.assistNodeIsAnnotation) {
          if(!sourceType.isAnnotationType()) continue next;
        } else if (this.assistNodeIsException) {
           if (!sourceType.isClass()) continue next;
           if (isEmptyPrefix) {
             if (sourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null) {
               continue next;
               }
            }
        }

        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal(sourceType);
        relevance += computeRelevanceForCaseMatching(token, sourceType.sourceName);
        relevance += computeRelevanceForExpectingType(sourceType);
        relevance += computeRelevanceForQualification(false);
        relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for type in the current unit

        if (sourceType.isAnnotationType()) {
          relevance += computeRelevanceForAnnotation();
          relevance += computeRelevanceForAnnotationTarget(sourceType);
        } else if (sourceType.isInterface()) {
          relevance += computeRelevanceForInterface();
        } else if(sourceType.isClass()){
          relevance += computeRelevanceForClass();
          relevance += computeRelevanceForException(sourceType.sourceName);
        }
       
       
        this.noProposal = false;
        if(proposeType &&
            (!this.assistNodeIsConstructor ||
                !allowingLongComputationProposals ||
                hasStaticMemberTypes(sourceType, null, this.unitScope) ||
                hasMemberTypesInEnclosingScope(sourceType, scope)) ||
                hasArrayTypeAsExpectedSuperTypes()) {
          char[] typeName = sourceType.sourceName();
          createTypeProposal(
              sourceType,
              typeName,
              IAccessRule.K_ACCESSIBLE,
              typeName,
              relevance,
              null,
              null,
              null,
              false);
        }
       
        if (proposeConstructor) {
          findConstructorsOrAnonymousTypes(
              sourceType,
              scope,
              FakeInvocationSite,
              false,
              relevance);
        }
      }
    }

    if (proposeConstructor && !isEmptyPrefix) {
     
      checkCancel();
     
      findTypesFromImports(token, scope, proposeType, typesFound);
    } else if(proposeType) {
     
      checkCancel();
     
      findTypesFromStaticImports(token, scope, proposeAllMemberTypes, typesFound);
    }
   
    if (proposeConstructor) {
     
      checkCancel();
     
      findTypesFromExpectedTypes(token, scope, typesFound, proposeType, proposeConstructor);
    }

    if (isEmptyPrefix && !this.assistNodeIsAnnotation) {
      if (!proposeConstructor) {
        findTypesFromExpectedTypes(token, scope, typesFound, proposeType, proposeConstructor);
      }
    } else {
      if(!isEmptyPrefix && !this.requestor.isIgnored(CompletionProposal.KEYWORD)) {
        if (this.assistNodeInJavadoc == 0 || (this.assistNodeInJavadoc & CompletionOnJavadoc.BASE_TYPES) != 0) {
          if (proposeBaseTypes) {
            if (proposeVoidType) {
              findKeywords(token, BASE_TYPE_NAMES, false, false);
            } else {
              findKeywords(token, BASE_TYPE_NAMES_WITHOUT_VOID, false, false);
            }
          }
        }
      }
     
      if (proposeConstructor) {
        int l = typesFound.size();
        for (int i = 0; i < l; i++) {
          ReferenceBinding typeFound = (ReferenceBinding) typesFound.elementAt(i);
          char[] fullyQualifiedTypeName =
            CharOperation.concat(
                typeFound.qualifiedPackageName(),
                typeFound.qualifiedSourceName(),
                '.');
          this.knownTypes.put(fullyQualifiedTypeName, KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS);
        }
       
        checkCancel();
       
        this.foundConstructorsCount = 0;
        this.nameEnvironment.findConstructorDeclarations(
            token,
            this.options.camelCaseMatch,
            this,
            this.monitor);
        acceptConstructors(scope);
      } else if (proposeType) {
        int l = typesFound.size();
        for (int i = 0; i < l; i++) {
          ReferenceBinding typeFound = (ReferenceBinding) typesFound.elementAt(i);
          char[] fullyQualifiedTypeName =
            CharOperation.concat(
                typeFound.qualifiedPackageName(),
                typeFound.qualifiedSourceName(),
                '.');
          this.knownTypes.put(fullyQualifiedTypeName, KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS);
        }
        int searchFor = IJavaSearchConstants.TYPE;
        if(this.assistNodeIsClass || this.assistNodeIsException) {
          searchFor = IJavaSearchConstants.CLASS;
        } else if (this.assistNodeIsInterfaceExcludingAnnotation) {
          searchFor = IJavaSearchConstants.INTERFACE;
        } else if(this.assistNodeIsInterface) {
          searchFor = IJavaSearchConstants.INTERFACE_AND_ANNOTATION;
        } else if(this.assistNodeIsEnum) {
          searchFor = IJavaSearchConstants.ENUM;
        } else if(this.assistNodeIsAnnotation) {
          searchFor = IJavaSearchConstants.ANNOTATION_TYPE;
        }
       
        checkCancel();
       
        this.foundTypesCount = 0;
        this.nameEnvironment.findTypes(
            token,
            proposeAllMemberTypes,
            this.options.camelCaseMatch,
            searchFor,
            this,
            this.monitor);
        acceptTypes(scope);
      }
      if(!isEmptyPrefix && !this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
       
        checkCancel();
       
        this.nameEnvironment.findPackages(token, this);
      }
    }
  }

  private void findTypesAndSubpackages(
    char[] token,
    PackageBinding packageBinding,
    Scope scope) {
   
    boolean allowingLongComputationProposals = isAllowingLongComputationProposals();

    boolean proposeType =
      !this.requestor.isIgnored(CompletionProposal.TYPE_REF) ||
      ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF));
   
    boolean proposeConstructor =
      allowingLongComputationProposals &&
      this.assistNodeIsConstructor &&
      (!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF) ||
          !isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF));

    char[] qualifiedName =
      CharOperation.concatWith(packageBinding.compoundName, token, '.');

    if (token == null || token.length == 0) {
      int length = qualifiedName.length;
      System.arraycopy(
        qualifiedName,
        0,
        qualifiedName = new char[length + 1],
        0,
        length);
      qualifiedName[length] = '.';
    }

    this.qualifiedCompletionToken = qualifiedName;

    if ((proposeType || proposeConstructor) && this.unitScope != null) {
      int typeLength = qualifiedName.length;
      SourceTypeBinding[] types = this.unitScope.topLevelTypes;

      for (int i = 0, length = types.length; i < length; i++) {
       
        checkCancel();
       
        SourceTypeBinding sourceType = types[i];
       
        if (isForbidden(sourceType)) continue;
        if (this.assistNodeIsClass && sourceType.isInterface()) continue;
        if (this.assistNodeIsInterface && sourceType.isClass()) continue;

        char[] qualifiedSourceTypeName = CharOperation.concatWith(sourceType.compoundName, '.');

        if (sourceType.sourceName == CompletionParser.FAKE_TYPE_NAME) continue;
        if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME) continue;
        if (typeLength > qualifiedSourceTypeName.length) continue;
        if (!(packageBinding == sourceType.getPackage())) continue;

        if (!CharOperation.prefixEquals(qualifiedName, qualifiedSourceTypeName, false)
            && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, sourceType.sourceName)))  continue;

        if (this.options.checkDeprecation &&
            sourceType.isViewedAsDeprecated() &&
            !scope.isDefinedInSameUnit(sourceType))
          continue;

          if (this.assistNodeIsExtendedType && sourceType.isFinal()) continue;
          if (this.assistNodeIsInterfaceExcludingAnnotation && sourceType.isAnnotationType()) continue;
        int accessibility = IAccessRule.K_ACCESSIBLE;
        if(sourceType.hasRestrictedAccess()) {
          AccessRestriction accessRestriction = this.lookupEnvironment.getAccessRestriction(sourceType);
          if(accessRestriction != null) {
            switch (accessRestriction.getProblemId()) {
              case IProblem.ForbiddenReference:
                if (this.options.checkForbiddenReference) {
                  continue;
                }
                accessibility = IAccessRule.K_NON_ACCESSIBLE;
                break;
              case IProblem.DiscouragedReference:
                if (this.options.checkDiscouragedReference) {
                  continue;
                }
                accessibility = IAccessRule.K_DISCOURAGED;
                break;
            }
          }
        }

        this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), KNOWN_TYPE_WITH_KNOWN_CONSTRUCTORS);

        int relevance = computeBaseRelevance();
        relevance += computeRelevanceForResolution();
        relevance += computeRelevanceForInterestingProposal(sourceType);
        relevance += computeRelevanceForCaseMatching(qualifiedName, qualifiedSourceTypeName);
        relevance += computeRelevanceForExpectingType(sourceType);
        relevance += computeRelevanceForQualification(false);
        relevance += computeRelevanceForRestrictions(accessibility);

        if (sourceType.isAnnotationType()) {
          relevance += computeRelevanceForAnnotation();
        } else if (sourceType.isInterface()) {
          relevance += computeRelevanceForInterface();
        } else if (sourceType.isClass()) {
          relevance += computeRelevanceForClass();
          relevance += computeRelevanceForException(sourceType.sourceName);
        }
       
        this.noProposal = false;
        if(proposeType &&
            (!this.assistNodeIsConstructor ||
                !allowingLongComputationProposals ||
                hasStaticMemberTypes(sourceType, null, this.unitScope) ||
                hasMemberTypesInEnclosingScope(sourceType, scope)) ||
                hasArrayTypeAsExpectedSuperTypes()) {
          char[] typeName = sourceType.sourceName();
          createTypeProposal(
              sourceType,
              typeName,
              IAccessRule.K_ACCESSIBLE,
              typeName,
              relevance,
              null,
              null,
              null,
              false);
        }
       
        if (proposeConstructor) {
          findConstructorsOrAnonymousTypes(
              sourceType,
              scope,
              FakeInvocationSite,
              false,
              relevance);
        }
      }
    }

    if (proposeConstructor) {

     
      checkCancel();
     
      this.foundConstructorsCount = 0;
      this.nameEnvironment.findConstructorDeclarations(
          qualifiedName,
          this.options.camelCaseMatch,
          this,
          this.monitor);
      acceptConstructors(scope);
    } if(proposeType) {
      int searchFor = IJavaSearchConstants.TYPE;
      if(this.assistNodeIsClass) {
        searchFor = IJavaSearchConstants.CLASS;
      } else if (this.assistNodeIsInterfaceExcludingAnnotation) {
        searchFor = IJavaSearchConstants.INTERFACE;
      } else if(this.assistNodeIsInterface) {
        searchFor = IJavaSearchConstants.INTERFACE_AND_ANNOTATION;
      } else if(this.assistNodeIsEnum) {
        searchFor = IJavaSearchConstants.ENUM;
      } else if(this.assistNodeIsAnnotation) {
        searchFor = IJavaSearchConstants.ANNOTATION_TYPE;
      }
     
      checkCancel();
     
      this.foundTypesCount = 0;
      this.nameEnvironment.findTypes(
          qualifiedName,
          false,
          this.options.camelCaseMatch,
          searchFor,
          this,
          this.monitor);
      acceptTypes(scope);
    }
   
    if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) {
      this.nameEnvironment.findPackages(qualifiedName, this);
    }
  }
 
  private void findTypesFromExpectedTypes(char[] token, Scope scope, ObjectVector typesFound, boolean proposeType, boolean proposeConstructor) {
    if(this.expectedTypesPtr > -1) {
      boolean allowingLongComputationProposals = isAllowingLongComputationProposals();
     
      int typeLength = token == null ? 0 : token.length;
     
      next : for (int i = 0; i <= this.expectedTypesPtr; i++) {
       
        checkCancel();
       
        if(this.expectedTypes[i] instanceof ReferenceBinding) {
          ReferenceBinding refBinding = (ReferenceBinding)this.expectedTypes[i];
         
          if (typeLength > 0) {
            if (typeLength > refBinding.sourceName.length) continue next;
 
            if (!CharOperation.prefixEquals(token, refBinding.sourceName, false)
                && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, refBinding.sourceName))) continue next;
          }


          if(refBinding.isTypeVariable() && this.assistNodeIsConstructor) {
            // don't propose type variable if the completion is a constructor ('new |')
            continue next;
          }
          if (this.options.checkDeprecation &&
              refBinding.isViewedAsDeprecated() &&
              !scope.isDefinedInSameUnit(refBinding))
            continue next;

          int accessibility = IAccessRule.K_ACCESSIBLE;
          if(refBinding.hasRestrictedAccess()) {
            AccessRestriction accessRestriction = this.lookupEnvironment.getAccessRestriction(refBinding);
            if(accessRestriction != null) {
              switch (accessRestriction.getProblemId()) {
                case IProblem.ForbiddenReference:
                  if (this.options.checkForbiddenReference) {
                    continue next;
                  }
                  accessibility = IAccessRule.K_NON_ACCESSIBLE;
                  break;
                case IProblem.DiscouragedReference:
                  if (this.options.checkDiscouragedReference) {
                    continue next;
                  }
                  accessibility = IAccessRule.K_DISCOURAGED;
                  break;
              }
            }
          }
          if(isForbidden(refBinding)) continue next;

          for (int j = 0; j < typesFound.size(); j++) {
            ReferenceBinding typeFound = (ReferenceBinding)typesFound.elementAt(j);
            if (typeFound == refBinding.erasure()) {
              continue next;
            }
          }
         
          typesFound.add(refBinding);

          boolean inSameUnit = this.unitScope.isDefinedInSameUnit(refBinding);

          // top level types of the current unit are already proposed.
          if(!inSameUnit || (inSameUnit && refBinding.isMemberType())) {
            char[] packageName = refBinding.qualifiedPackageName();
            char[] typeName = refBinding.sourceName();
            char[] completionName = typeName;

            boolean isQualified = false;
            if (!this.insideQualifiedReference && !refBinding.isMemberType()) {
              if (mustQualifyType(packageName, typeName, null, refBinding.modifiers)) {
                if (packageName == null || packageName.length == 0)
                  if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
                    continue next; // ignore types from the default package from outside it
                completionName = CharOperation.concat(packageName, typeName, '.');
                isQualified = true;
              }
            }

            if (this.assistNodeIsExtendedType && refBinding.isFinal()) continue next;
            if (this.assistNodeIsInterfaceExcludingAnnotation && refBinding.isAnnotationType()) continue next;
            if(this.assistNodeIsClass) {
              if(!refBinding.isClass()) continue next;
            } else if(this.assistNodeIsInterface) {
              if(!refBinding.isInterface() && !refBinding.isAnnotationType()) continue next;
            } else if (this.assistNodeIsAnnotation) {
              if(!refBinding.isAnnotationType()) continue next;
            }

            int relevance = computeBaseRelevance();
            relevance += computeRelevanceForResolution();
            relevance += computeRelevanceForInterestingProposal(refBinding);
            relevance += computeRelevanceForCaseMatching(token, typeName);
            relevance += computeRelevanceForExpectingType(refBinding);
            relevance += computeRelevanceForQualification(isQualified);
            relevance += computeRelevanceForRestrictions(accessibility);

            if(refBinding.isClass()) {
              relevance += computeRelevanceForClass();
              relevance += computeRelevanceForException(typeName);
            } else if(refBinding.isEnum()) {
              relevance += computeRelevanceForEnum();
            } else if(refBinding.isInterface()) {
              relevance += computeRelevanceForInterface();
            }
           
            if (proposeType &&
                (!this.assistNodeIsConstructor ||
                    !allowingLongComputationProposals ||
                    hasStaticMemberTypes(refBinding, scope.enclosingSourceType() ,this.unitScope)) ||
                    hasArrayTypeAsExpectedSuperTypes()) {
              this.noProposal = false;
              if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
                InternalCompletionProposal proposal =  createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
                proposal.setDeclarationSignature(packageName);
                proposal.setSignature(getSignature(refBinding));
                proposal.setPackageName(packageName);
                proposal.setTypeName(typeName);
                proposal.setCompletion(completionName);
                proposal.setFlags(refBinding.modifiers);
                proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                proposal.setAccessibility(accessibility);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            }
           
            if (proposeConstructor) {
              findConstructorsOrAnonymousTypes(
                  refBinding,
                  scope,
                  FakeInvocationSite,
                  isQualified,
                  relevance);
            }
          }
        }
      }
    }
  }

  private void findTypesFromImports(char[] token, Scope scope, boolean proposeType, ObjectVector typesFound) {
    ImportBinding[] importBindings = scope.compilationUnitScope().imports;
    next : for (int i = 0; i < importBindings.length; i++) {
      ImportBinding importBinding = importBindings[i];
      if(importBinding.isValidBinding()) {
        Binding binding = importBinding.resolvedImport;
        if(binding != null && binding.isValidBinding()) {
          if(importBinding.onDemand) {
            if (importBinding.isStatic()) {
              if((binding.kind() & Binding.TYPE) != 0) {
                this.findMemberTypes(
                    token,
                    (ReferenceBinding) binding,
                    scope,
                    scope.enclosingSourceType(),
                    true,
                    false,
                    true,
                    true,
                    false,
                    null,
                    typesFound,
                    null,
                    null,
                    null,
                    false);
              }
            }
          } else {
            if ((binding.kind() & Binding.TYPE) != 0) {
              ReferenceBinding typeBinding = (ReferenceBinding) binding;
              int typeLength = token.length;

              if (!typeBinding.isStatic()) continue next;

              if (typeLength > typeBinding.sourceName.lengthcontinue next;

              if (!CharOperation.prefixEquals(token, typeBinding.sourceName, false)
                  && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeBinding.sourceName))) continue next;
             
              int accessibility = IAccessRule.K_ACCESSIBLE;
              if(typeBinding.hasRestrictedAccess()) {
                AccessRestriction accessRestriction = this.lookupEnvironment.getAccessRestriction(typeBinding);
                if(accessRestriction != null) {
                  switch (accessRestriction.getProblemId()) {
                    case IProblem.ForbiddenReference:
                      if (this.options.checkForbiddenReference) {
                        continue next;
                      }
                      accessibility = IAccessRule.K_NON_ACCESSIBLE;
                      break;
                    case IProblem.DiscouragedReference:
                      if (this.options.checkDiscouragedReference) {
                        continue next;
                      }
                      accessibility = IAccessRule.K_DISCOURAGED;
                      break;
                  }
                }
              }
             
              if (typesFound.contains(typeBinding)) continue next;
             
              typesFound.add(typeBinding);
             
              if (this.assistNodeIsExtendedType && typeBinding.isFinal()) continue;
              if (this.assistNodeIsInterfaceExcludingAnnotation && typeBinding.isAnnotationType()) continue;
              if(this.assistNodeIsClass) {
                if(!typeBinding.isClass()) continue;
              } else if(this.assistNodeIsInterface) {
                if(!typeBinding.isInterface() && !typeBinding.isAnnotationType()) continue;
              } else if (this.assistNodeIsAnnotation) {
                if(!typeBinding.isAnnotationType()) continue;
              }
             
              int relevance = computeBaseRelevance();
              relevance += computeRelevanceForResolution();
              relevance += computeRelevanceForInterestingProposal(typeBinding);
              relevance += computeRelevanceForCaseMatching(token, typeBinding.sourceName);
              relevance += computeRelevanceForExpectingType(typeBinding);
              relevance += computeRelevanceForQualification(false);
              relevance += computeRelevanceForRestrictions(accessibility);
     
              if (typeBinding.isAnnotationType()) {
                relevance += computeRelevanceForAnnotation();
                relevance += computeRelevanceForAnnotationTarget(typeBinding);
              } else if (typeBinding.isInterface()) {
                relevance += computeRelevanceForInterface();
              } else if(typeBinding.isClass()){
                relevance += computeRelevanceForClass();
                relevance += computeRelevanceForException(typeBinding.sourceName);
              }
             
              if (proposeType &&
                  (hasStaticMemberTypes(typeBinding, scope.enclosingSourceType(), this.unitScope) || hasArrayTypeAsExpectedSuperTypes())) {
                this.noProposal = false;
                if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
                  InternalCompletionProposal proposal =  createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
                  proposal.setDeclarationSignature(typeBinding.qualifiedPackageName());
                  proposal.setSignature(getSignature(typeBinding));
                  proposal.setPackageName(typeBinding.qualifiedPackageName());
                  proposal.setTypeName(typeBinding.qualifiedSourceName());
                  proposal.setCompletion(typeBinding.sourceName());
                  proposal.setFlags(typeBinding.modifiers);
                  proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
                  proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                  proposal.setRelevance(relevance);
                  this.requestor.accept(proposal);
                  if(DEBUG) {
                    this.printDebug(proposal);
                  }
                }
              }
             
              findConstructorsOrAnonymousTypes(
                  typeBinding,
                  scope,
                  FakeInvocationSite,
                  false,
                  relevance);
            }
          }
        }
      }
    }
  }
 
  private void findTypesFromStaticImports(char[] token, Scope scope, boolean proposeAllMemberTypes, ObjectVector typesFound) {
    ImportBinding[] importBindings = scope.compilationUnitScope().imports;
    for (int i = 0; i < importBindings.length; i++) {
      ImportBinding importBinding = importBindings[i];
      if(importBinding.isValidBinding() && importBinding.isStatic()) {
        Binding binding = importBinding.resolvedImport;
        if(binding != null && binding.isValidBinding()) {
          if(importBinding.onDemand) {
            if((binding.kind() & Binding.TYPE) != 0) {
              this.findMemberTypes(
                  token,
                  (ReferenceBinding) binding,
                  scope,
                  scope.enclosingSourceType(),
                  true,
                  false,
                  true,
                  true,
                  proposeAllMemberTypes,
                  null,
                  typesFound,
                  null,
                  null,
                  null,
                  false);
            }
          } else {
            if ((binding.kind() & Binding.TYPE) != 0) {
              ReferenceBinding typeBinding = (ReferenceBinding) binding;
              int typeLength = token.length;

              if (!typeBinding.isStatic()) continue;

              if (typeLength > typeBinding.sourceName.lengthcontinue;

              if (!CharOperation.prefixEquals(token, typeBinding.sourceName, false)
                  && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeBinding.sourceName)))  continue;

              if (typesFound.contains(typeBinding))  continue;

              typesFound.add(typeBinding);

              if (this.assistNodeIsExtendedType && typeBinding.isFinal()) continue;
              if (this.assistNodeIsInterfaceExcludingAnnotation && typeBinding.isAnnotationType()) continue;
              if(this.assistNodeIsClass || this.assistNodeIsException) {
                if(!typeBinding.isClass()) continue;
              } else if(this.assistNodeIsInterface) {
                if(!typeBinding.isInterface() && !typeBinding.isAnnotationType()) continue;
              } else if (this.assistNodeIsAnnotation) {
                if(!typeBinding.isAnnotationType()) continue;
              }

              int relevance = computeBaseRelevance();
              relevance += computeRelevanceForResolution();
              relevance += computeRelevanceForInterestingProposal(typeBinding);
              relevance += computeRelevanceForCaseMatching(token, typeBinding.sourceName);
              relevance += computeRelevanceForExpectingType(typeBinding);
              relevance += computeRelevanceForQualification(false);
              relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE);

              if (typeBinding.isClass()) {
                relevance += computeRelevanceForClass();
                relevance += computeRelevanceForException(typeBinding.sourceName);
              } else if(typeBinding.isEnum()) {
                relevance += computeRelevanceForEnum();
              } else if(typeBinding.isInterface()) {
                relevance += computeRelevanceForInterface();
              }

              this.noProposal = false;
              if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
                InternalCompletionProposal proposal =  createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
                proposal.setDeclarationSignature(typeBinding.qualifiedPackageName());
                proposal.setSignature(getSignature(typeBinding));
                proposal.setPackageName(typeBinding.qualifiedPackageName());
                proposal.setTypeName(typeBinding.qualifiedSourceName());
                proposal.setCompletion(typeBinding.sourceName());
                proposal.setFlags(typeBinding.modifiers);
                proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            }
          }
        }
      }
    }
  }

  private void findUnresolvedReference(int completedNameStart, int completedNameEnd, BlockScope scope, char[][] discouragedNames) {
    char[][] foundNames = findUnresolvedReferenceBefore(completedNameStart - 1, completedNameEnd, scope, discouragedNames);
    if (foundNames != null && foundNames.length > 1) {
      int discouragedNamesLength = discouragedNames.length;
      int foundNamesLength = foundNames.length;
      int newLength = discouragedNamesLength + foundNamesLength;
      System.arraycopy(discouragedNames, 0, discouragedNames = new char[newLength][], 0, discouragedNamesLength);
      System.arraycopy(foundNames, 0, discouragedNames, discouragedNamesLength, foundNamesLength);
    }
    findUnresolvedReferenceAfter(completedNameEnd + 1, scope, discouragedNames);
  }

  private char[][] findUnresolvedReferenceAfter(int from, BlockScope scope, final char[][] discouragedNames) {
    final ArrayList proposedNames = new ArrayList();

    UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor nameRequestor =
      new UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor() {
        public void acceptName(char[] name) {
          CompletionEngine.this.acceptUnresolvedName(name);
          proposedNames.add(name);
        }
      };

    ReferenceContext referenceContext = scope.referenceContext();
    if (referenceContext instanceof AbstractMethodDeclaration) {
      AbstractMethodDeclaration md = (AbstractMethodDeclaration)referenceContext;

      UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this);
      nameFinder.findAfter(
          this.completionToken,
          md.scope,
          md.scope.classScope(),
          from,
          md.bodyEnd,
          discouragedNames,
          nameRequestor);
    } else if (referenceContext instanceof TypeDeclaration) {
      TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext;
      FieldDeclaration[] fields = typeDeclaration.fields;
      if (fields != null) {
        done : for (int i = 0; i < fields.length; i++) {
          if (fields[i] instanceof Initializer) {
            Initializer initializer = (Initializer) fields[i];
            if (initializer.block.sourceStart <= from &&
                from < initializer.bodyEnd) {
              UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this);
              nameFinder.findAfter(
                    this.completionToken,
                    typeDeclaration.scope,
                    typeDeclaration.scope,
                    from,
                    initializer.bodyEnd,
                    discouragedNames,
                    nameRequestor);
              break done;
            }
          }
        }
      }
    }

    int proposedNamesCount = proposedNames.size();
    if (proposedNamesCount > 0) {
      return (char[][])proposedNames.toArray(new char[proposedNamesCount][]);
    }

    return null;
  }

  private char[][] findUnresolvedReferenceBefore(int recordTo, int parseTo, BlockScope scope, final char[][] discouragedNames) {
    final ArrayList proposedNames = new ArrayList();

    UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor nameRequestor =
      new UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor() {
        public void acceptName(char[] name) {
          CompletionEngine.this.acceptUnresolvedName(name);
          proposedNames.add(name);
        }
      };

    BlockScope upperScope = scope;
    while (upperScope.enclosingMethodScope() != null) {
      upperScope = upperScope.enclosingMethodScope();
    }

    ReferenceContext referenceContext = upperScope.referenceContext();
    if (referenceContext instanceof AbstractMethodDeclaration) {
      AbstractMethodDeclaration md = (AbstractMethodDeclaration)referenceContext;

      UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this);
      nameFinder.findBefore(
          this.completionToken,
          md.scope,
          md.scope.classScope(),
          md.bodyStart,
          recordTo,
          parseTo,
          discouragedNames,
          nameRequestor);
    } else if (referenceContext instanceof TypeDeclaration) {
      TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext;


      done : {
        FieldDeclaration[] fields = typeDeclaration.fields;
        if (fields != null) {
          for (int i = 0; i < fields.length; i++) {
            if (fields[i] instanceof Initializer) {
              Initializer initializer = (Initializer) fields[i];
              if (initializer.block.sourceStart <= recordTo &&
                  recordTo < initializer.bodyEnd) {

                UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this);
                nameFinder.findBefore(
                    this.completionToken,
                    typeDeclaration.scope,
                    typeDeclaration.scope,
                    initializer.block.sourceStart,
                    recordTo,
                    parseTo,
                    discouragedNames,
                    nameRequestor);
                break done;
              }
            }
          }
        }
      }
    }

    int proposedNamesCount = proposedNames.size();
    if (proposedNamesCount > 0) {
      return (char[][])proposedNames.toArray(new char[proposedNamesCount][]);
    }

    return null;
  }

  private char[][] findVariableFromUnresolvedReference(LocalDeclaration variable, BlockScope scope, final char[][] discouragedNames) {
    final TypeReference type = variable.type;
    if(type != null &&
        type.resolvedType != null &&
        type.resolvedType.problemId() == ProblemReasons.NoError){

      final ArrayList proposedNames = new ArrayList();

      UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor nameRequestor =
        new UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor() {
          public void acceptName(char[] name) {
            int relevance = computeBaseRelevance();
            relevance += computeRelevanceForInterestingProposal();
            relevance += computeRelevanceForCaseMatching(CompletionEngine.this.completionToken, name);
            relevance += R_NAME_FIRST_PREFIX;
            relevance += R_NAME_FIRST_SUFFIX;
            relevance += R_NAME_LESS_NEW_CHARACTERS;
            relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for variable name

            // accept result
            CompletionEngine.this.noProposal = false;
            if(!CompletionEngine.this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
              InternalCompletionProposal proposal =  CompletionEngine.this.createProposal(CompletionProposal.VARIABLE_DECLARATION, CompletionEngine.this.actualCompletionPosition);
              proposal.setSignature(getSignature(type.resolvedType));
              proposal.setPackageName(type.resolvedType.qualifiedPackageName());
              proposal.setTypeName(type.resolvedType.qualifiedSourceName());
              proposal.setName(name);
              proposal.setCompletion(name);
              //proposal.setFlags(Flags.AccDefault);
              proposal.setReplaceRange(CompletionEngine.this.startPosition - CompletionEngine.this.offset, CompletionEngine.this.endPosition - CompletionEngine.this.offset);
              proposal.setTokenRange(CompletionEngine.this.tokenStart - CompletionEngine.this.offset, CompletionEngine.this.tokenEnd - CompletionEngine.this.offset);
              proposal.setRelevance(relevance);
              CompletionEngine.this.requestor.accept(proposal);
              if(DEBUG) {
                CompletionEngine.this.printDebug(proposal);
              }
            }
            proposedNames.add(name);
          }
        };

      ReferenceContext referenceContext = scope.referenceContext();
      if (referenceContext instanceof AbstractMethodDeclaration) {
        AbstractMethodDeclaration md = (AbstractMethodDeclaration)referenceContext;

        UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this);
        nameFinder.find(
            this.completionToken,
            md,
            variable.declarationSourceEnd + 1,
            discouragedNames,
            nameRequestor);
      } else if (referenceContext instanceof TypeDeclaration) {
        TypeDeclaration typeDeclaration = (TypeDeclaration) referenceContext;
        FieldDeclaration[] fields = typeDeclaration.fields;
        if (fields != null) {
          done : for (int i = 0; i < fields.length; i++) {
            if (fields[i] instanceof Initializer) {
              Initializer initializer = (Initializer) fields[i];
              if (initializer.bodyStart <= variable.sourceStart &&
                  variable.sourceStart < initializer.bodyEnd) {
                UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this);
                nameFinder.find(
                    this.completionToken,
                    initializer,
                    typeDeclaration.scope,
                    variable.declarationSourceEnd + 1,
                    discouragedNames,
                    nameRequestor);
                break done;
              }
            }
          }
        }
      }

      int proposedNamesCount = proposedNames.size();
      if (proposedNamesCount > 0) {
        return (char[][])proposedNames.toArray(new char[proposedNamesCount][]);
      }
    }

    return null;
  }

  private void findVariableName(
      char[] token,
      char[] qualifiedPackageName,
      char[] qualifiedSourceName,
      char[] sourceName,
      final TypeBinding typeBinding,
      char[][] discouragedNames,
      final char[][] forbiddenNames,
      boolean forCollection,
      int dim,
      int kind){

    if(sourceName == null || sourceName.length == 0)
      return;

    // compute variable name for non base type
    final char[] displayName;
    if (!forCollection) {
      if (dim > 0){
        int l = qualifiedSourceName.length;
        displayName = new char[l+(2*dim)];
        System.arraycopy(qualifiedSourceName, 0, displayName, 0, l);
        for(int i = 0; i < dim; i++){
          displayName[l+(i*2)] = '[';
          displayName[l+(i*2)+1] = ']';
        }
      } else {
        displayName = qualifiedSourceName;
      }
    } else {
      displayName = typeBinding.qualifiedSourceName();
    }

    final char[] t = token;
    final char[] q = qualifiedPackageName;
    INamingRequestor namingRequestor = new INamingRequestor() {
      void accept(char[] name, int prefixAndSuffixRelevance, int reusedCharacters){
        int l = forbiddenNames == null ? 0 : forbiddenNames.length;
        for (int i = 0; i < l; i++) {
          if (CharOperation.equals(forbiddenNames[i], name, false)) return;
        }

        if (CharOperation.prefixEquals(t, name, false)) {
          int relevance = computeBaseRelevance();
          relevance += computeRelevanceForInterestingProposal();
          relevance += computeRelevanceForCaseMatching(t, name);
          relevance += prefixAndSuffixRelevance;
          if(reusedCharacters > 0) relevance += R_NAME_LESS_NEW_CHARACTERS;
          relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for variable name

          // accept result
          CompletionEngine.this.noProposal = false;
          if(!CompletionEngine.this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) {
            InternalCompletionProposal proposal =  CompletionEngine.this.createProposal(CompletionProposal.VARIABLE_DECLARATION, CompletionEngine.this.actualCompletionPosition);
            proposal.setSignature(getSignature(typeBinding));
            proposal.setPackageName(q);
            proposal.setTypeName(displayName);
            proposal.setName(name);
            proposal.setCompletion(name);
            //proposal.setFlags(Flags.AccDefault);
            proposal.setReplaceRange(CompletionEngine.this.startPosition - CompletionEngine.this.offset, CompletionEngine.this.endPosition - CompletionEngine.this.offset);
            proposal.setTokenRange(CompletionEngine.this.tokenStart - CompletionEngine.this.offset, CompletionEngine.this.tokenEnd - CompletionEngine.this.offset);
            proposal.setRelevance(relevance);
            CompletionEngine.this.requestor.accept(proposal);
            if(DEBUG) {
              CompletionEngine.this.printDebug(proposal);
            }
          }
        }
      }

      public void acceptNameWithoutPrefixAndSuffix(char[] name,int reusedCharacters) {
        accept(name, 0, reusedCharacters);
      }

      public void acceptNameWithPrefix(char[] name, boolean isFirstPrefix, int reusedCharacters) {
        accept(name, isFirstPrefix ? R_NAME_FIRST_PREFIX :  R_NAME_PREFIX, reusedCharacters);
      }

      public void acceptNameWithPrefixAndSuffix(char[] name, boolean isFirstPrefix, boolean isFirstSuffix, int reusedCharacters) {
        accept(
            name,
            (isFirstPrefix ? R_NAME_FIRST_PREFIX : R_NAME_PREFIX) + (isFirstSuffix ? R_NAME_FIRST_SUFFIX : R_NAME_SUFFIX),
            reusedCharacters);
      }
      public void acceptNameWithSuffix(char[] name, boolean isFirstSuffix, int reusedCharacters) {
        accept(name, isFirstSuffix ? R_NAME_FIRST_SUFFIX : R_NAME_SUFFIX, reusedCharacters);
      }
    };

    InternalNamingConventions.suggestVariableNames(
        kind,
        InternalNamingConventions.BK_SIMPLE_TYPE_NAME,
        qualifiedSourceName,
        this.javaProject,
        dim,
        token,
        discouragedNames,
        true,
        namingRequestor);
  }

  // Helper method for private void findVariableNames(char[] name, TypeReference type )
  private void findVariableName(
      char[] token,
      char[] qualifiedPackageName,
      char[] qualifiedSourceName,
      char[] sourceName,
      final TypeBinding typeBinding,
      char[][] discouragedNames,
      final char[][] forbiddenNames,
      int dim,
      int kind){
    findVariableName(
        token,
        qualifiedPackageName,
        qualifiedSourceName,
        sourceName,
        typeBinding,
        discouragedNames,
        forbiddenNames,
        false,
        dim,
        kind);
  }
  private void findVariableNameForCollection(
      char[] token,
      char[] qualifiedPackageName,
      char[] qualifiedSourceName,
      char[] sourceName,
      final TypeBinding typeBinding,
      char[][] discouragedNames,
      final char[][] forbiddenNames,
      int kind){

    findVariableName(
        token,
        qualifiedPackageName,
        qualifiedSourceName,
        sourceName,
        typeBinding,
        discouragedNames,
        forbiddenNames,
        false,
        1,
        kind);
  }
  private void findVariableNames(char[] name, TypeReference type , char[][] discouragedNames, char[][] forbiddenNames, int kind){
    if(type != null &&
      type.resolvedType != null) {
      TypeBinding tb = type.resolvedType;

      if (tb.problemId() == ProblemReasons.NoError &&
          tb != Scope.getBaseType(VOID)) {
        findVariableName(
          name,
          tb.leafComponentType().qualifiedPackageName(),
          tb.leafComponentType().qualifiedSourceName(),
          tb.leafComponentType().sourceName(),
          tb,
          discouragedNames,
          forbiddenNames,
          type.dimensions(),
          kind);
       
        if (tb.isParameterizedType() &&
            tb.findSuperTypeOriginatingFrom(TypeIds.T_JavaUtilCollection, false) != null) {
          ParameterizedTypeBinding ptb = ((ParameterizedTypeBinding) tb);
          TypeBinding[] arguments = ptb.arguments;
          if (arguments != null && arguments.length == 1) {
            TypeBinding argument = arguments[0];
            findVariableNameForCollection(
              name,
              argument.leafComponentType().qualifiedPackageName(),
              argument.leafComponentType().qualifiedSourceName(),
              argument.leafComponentType().sourceName(),
              tb,
              discouragedNames,
              forbiddenNames,
              kind);
          }
        }
      }
    }

  }
  private void findVariablesAndMethods(
    char[] token,
    Scope scope,
    InvocationSite invocationSite,
    Scope invocationScope,
    boolean insideTypeAnnotation,
    boolean insideAnnotationAttribute) {

    if (token == null)
      return;

    // Should local variables hide fields from the receiver type or any of its enclosing types?
    // we know its an implicit field/method access... see BlockScope getBinding/getImplicitMethod

    boolean staticsOnly = false;
    // need to know if we're in a static context (or inside a constructor)
    int tokenLength = token.length;

    ObjectVector localsFound = new ObjectVector();
    ObjectVector fieldsFound = new ObjectVector();
    ObjectVector methodsFound = new ObjectVector();

    Scope currentScope = scope;

    if (!this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) {
      done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found

        switch (currentScope.kind) {

          case Scope.METHOD_SCOPE :
            // handle the error case inside an explicit constructor call (see MethodScope>>findField)
            MethodScope methodScope = (MethodScope) currentScope;
            staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;

          //$FALL-THROUGH$
          case Scope.BLOCK_SCOPE :
            BlockScope blockScope = (BlockScope) currentScope;

            next : for (int i = 0, length = blockScope.locals.length; i < length; i++) {
              LocalVariableBinding local = blockScope.locals[i];

              if (local == null)
                break next;

              if (tokenLength > local.name.length)
                continue next;

              if (!CharOperation.prefixEquals(token, local.name, false /* ignore case */)
                  && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, local.name)))
                continue next;

              if (local.isSecret())
                continue next;
             
              // https://bugs.eclipse.org/bugs/show_bug.cgi?id=328674
              if (local.declaration.initialization != null) {
                // proposal being asked inside field's initialization. Don't propose this field.
                continue next;
              }
                       
              // don't propose non constant variables or strings (1.6 or below) in case expression
              // https://bugs.eclipse.org/bugs/show_bug.cgi?id=195346
              // https://bugs.eclipse.org/bugs/show_bug.cgi?id=343342
              if (this.assistNodeIsInsideCase) {
                if (local.isFinal()) {
                  if (this.assistNodeIsString){
                    if (local.type == null || local.type.id != TypeIds.T_JavaLangString)
                      continue next;
                  } else if (!(local.type instanceof BaseTypeBinding))
                    continue next;
                } else {
                  continue next; // non-constants not allowed in case. 
                }
              }
             
              int ptr = this.uninterestingBindingsPtr;
              // Cases where the binding is uninteresting eg. for completion occurring inside a local var
              // declaration, the local var binding is uninteresting and shouldn't be proposed.
              while (ptr >= 0) {
                if (this.uninterestingBindings[ptr] == local) {
                  continue next;
                }
                ptr--;
              }

              for (int f = 0; f < localsFound.size; f++) {
                LocalVariableBinding otherLocal =
                  (LocalVariableBinding) localsFound.elementAt(f);
                if (CharOperation.equals(otherLocal.name, local.name, true))
                  continue next;
              }
              localsFound.add(local);

              int relevance = computeBaseRelevance();
              relevance += computeRelevanceForResolution();
              relevance += computeRelevanceForInterestingProposal(local);
              relevance += computeRelevanceForCaseMatching(token, local.name);
              relevance += computeRelevanceForExpectingType(local.type);
              relevance += computeRelevanceForEnumConstant(local.type);
              relevance += computeRelevanceForQualification(false);
              relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for local variable
              relevance += computeRelevanceForFinal(this.assistNodeIsInsideCase, local.isFinal());
              this.noProposal = false;
              if(!this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) {
                InternalCompletionProposal proposal =  createProposal(CompletionProposal.LOCAL_VARIABLE_REF, this.actualCompletionPosition);
                proposal.setSignature(
                  local.type == null
                  ? createTypeSignature(
                      CharOperation.NO_CHAR,
                      local.declaration.type.toString().toCharArray())
                  : getSignature(local.type));
                if(local.type == null) {
                  //proposal.setPackageName(null);
                  proposal.setTypeName(local.declaration.type.toString().toCharArray());
                } else {
                  proposal.setPackageName(local.type.qualifiedPackageName());
                  proposal.setTypeName(local.type.qualifiedSourceName());
                }
                proposal.setName(local.name);
                proposal.setCompletion(local.name);
                proposal.setFlags(local.modifiers);
                proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
                proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
                proposal.setRelevance(relevance);
                this.requestor.accept(proposal);
                if(DEBUG) {
                  this.printDebug(proposal);
                }
              }
            }
            break;

          case Scope.COMPILATION_UNIT_SCOPE :
            break done1;
        }
        currentScope = currentScope.parent;
      }
    }
   
    checkCancel();

    boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF);
    boolean proposeMethod = !this.requestor.isIgnored(CompletionProposal.METHOD_REF);

    staticsOnly = false;
    currentScope = scope;

    if(proposeField || proposeMethod) {
      done2 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found

        switch (currentScope.kind) {
          case Scope.METHOD_SCOPE :
            // handle the error case inside an explicit constructor call (see MethodScope>>findField)
            MethodScope methodScope = (MethodScope) currentScope;
            staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;
            break;
          case Scope.CLASS_SCOPE :
            ClassScope classScope = (ClassScope) currentScope;
            SourceTypeBinding enclosingType = classScope.referenceContext.binding;
            /*        if (tokenLength == 0) { // only search inside the type itself if no prefix was provided
                      findFields(token, enclosingType.fields(), classScope, fieldsFound, staticsOnly);
                      findMethods(token, enclosingType.methods(), classScope, methodsFound, staticsOnly, false);
                      break done;
                    } else { */
            if(!insideTypeAnnotation) {
              if(proposeField) {
                findFields(
                  token,
                  enclosingType,
                  classScope,
                  fieldsFound,
                  localsFound,
                  staticsOnly,
                  invocationSite,
                  invocationScope,
                  true,
                  true,
                  null,
                  null,
                  null,
                  false,
                  null,
                  -1,
                  -1);
              }
              if(proposeMethod && !insideAnnotationAttribute) {
                findMethods(
                  token,
                  null,
                  null,
                  enclosingType,
                  classScope,
                  methodsFound,
                  staticsOnly,
                  false,
                  invocationSite,
                  invocationScope,
                  true,
                  false,
                  true,
                  null,
                  null,
                  null,
                  false,
                  null,
                  -1,
                  -1);
              }
            }
            staticsOnly |= enclosingType.isStatic();
            insideTypeAnnotation = false;
            //        }
            break;

          case Scope.COMPILATION_UNIT_SCOPE :
            break done2;
        }
        currentScope = currentScope.parent;
      }
     
      checkCancel();
     
      findFieldsAndMethodsFromStaticImports(
          token,
          scope,
          invocationSite,
          invocationScope,
          false,
          insideAnnotationAttribute,
          localsFound,
          fieldsFound,
          methodsFound,
          proposeField,
          proposeMethod);

      if (this.assistNodeInJavadoc == 0) {
       
        checkCancel();
       
        // search in favorites import
        findFieldsAndMethodsFromFavorites(
            token,
            scope,
            invocationSite,
            invocationScope,
            localsFound,
            fieldsFound,
            methodsFound);
      }
     
      checkCancel();
     
      findEnumConstantsFromExpectedTypes(
          token,
          invocationScope,
          fieldsFound);
    }
  }

  private char[] getCompletedTypeSignature(ReferenceBinding referenceBinding) {
    char[] result = null;
    StringBuffer sig = new StringBuffer(10);
    if (!referenceBinding.isMemberType()) {
      char[] typeSig = referenceBinding.genericTypeSignature();
      sig.append(typeSig, 0, typeSig.length);
    } else if (!this.insideQualifiedReference) {
      if (referenceBinding.isStatic()) {
        char[] typeSig = referenceBinding.signature();
        sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon

        TypeVariableBinding[] typeVariables = referenceBinding.typeVariables();
        if (typeVariables != Binding.NO_TYPE_VARIABLES) {
            sig.append(Signature.C_GENERIC_START);
            for (int i = 0, length = typeVariables.length; i < length; i++) {
                sig.append(typeVariables[i].genericTypeSignature());
            }
            sig.append(Signature.C_GENERIC_END);
        }
        sig.append(Signature.C_SEMICOLON);
      } else {
        char[] typeSig = referenceBinding.genericTypeSignature();
        sig.append(typeSig, 0, typeSig.length);
      }
    } else {
      ReferenceBinding enclosingType = referenceBinding.enclosingType();
      if (enclosingType.isParameterizedType()) {
        char[] typeSig = referenceBinding.genericTypeSignature();
        sig.append(typeSig, 0, typeSig.length-1);

        TypeVariableBinding[] typeVariables = referenceBinding.typeVariables();
        if (typeVariables != Binding.NO_TYPE_VARIABLES) {
            sig.append(Signature.C_GENERIC_START);
            for (int i = 0, length = typeVariables.length; i < length; i++) {
                sig.append(typeVariables[i].genericTypeSignature());
            }
            sig.append(Signature.C_GENERIC_END);
        }
      } else {
        char[] typeSig = referenceBinding.signature();
        sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon

        if (referenceBinding.isStatic()) {
          TypeVariableBinding[] typeVariables = referenceBinding.typeVariables();
          if (typeVariables != Binding.NO_TYPE_VARIABLES) {
              sig.append(Signature.C_GENERIC_START);
              for (int i = 0, length = typeVariables.length; i < length; i++) {
                  sig.append(typeVariables[i].genericTypeSignature());
              }
              sig.append(Signature.C_GENERIC_END);
          }
        }
      }
      sig.append(Signature.C_SEMICOLON);
    }
    int sigLength = sig.length();
    result = new char[sigLength];
    sig.getChars(0, sigLength, result, 0);
    result = CharOperation.replaceOnCopy(result, '/', Signature.C_DOT);
    return result;
  }

  private ImportBinding[] getFavoriteReferenceBindings(Scope scope) {
    if (this.favoriteReferenceBindings != null) return this.favoriteReferenceBindings;

    String[] favoriteReferences = this.requestor.getFavoriteReferences();

    if (favoriteReferences == null || favoriteReferences.length == 0) return null;

    ImportBinding[] resolvedImports = new ImportBinding[favoriteReferences.length];

    int count = 0;
    next : for (int i = 0; i < favoriteReferences.length; i++) {
      String favoriteReference = favoriteReferences[i];

      int length;
      if (favoriteReference == null || (length = favoriteReference.length()) == 0) continue next;

      boolean onDemand = favoriteReference.charAt(length - 1) == '*';

      char[][] compoundName = CharOperation.splitOn('.', favoriteReference.toCharArray());
      if (onDemand) {
        compoundName = CharOperation.subarray(compoundName, 0, compoundName.length - 1);
      }

      // remove duplicate and conflicting
      for (int j = 0; j < count; j++) {
        ImportReference f = resolvedImports[j].reference;

        if (CharOperation.equals(f.tokens, compoundName)) continue next;

        if (!onDemand && ((f.bits & ASTNode.OnDemand) == 0)) {
          if (CharOperation.equals(f.tokens[f.tokens.length - 1], compoundName[compoundName.length - 1]))
            continue next;
        }
      }

      boolean isStatic = true;

      ImportReference importReference =
        new ImportReference(
            compoundName,
            new long[compoundName.length],
            onDemand,
            isStatic ? ClassFileConstants.AccStatic : ClassFileConstants.AccDefault);

      Binding importBinding = this.unitScope.findImport(compoundName, isStatic, onDemand);

      if (!importBinding.isValidBinding()) {
        continue next;
      }

      if (importBinding instanceof PackageBinding) {
        continue next;
      }

      resolvedImports[count++] =
        new ImportBinding(compoundName, onDemand, importBinding, importReference);
    }

    if (resolvedImports.length > count)
      System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[count], 0, count);

    return this.favoriteReferenceBindings = resolvedImports;
  }
 
  private INameEnvironment getNoCacheNameEnvironment() {
    if (this.noCacheNameEnvironment == null) {
      JavaModelManager.getJavaModelManager().cacheZipFiles(this);
      this.noCacheNameEnvironment = new JavaSearchNameEnvironment(this.javaProject, this.owner == null ? null : JavaModelManager.getJavaModelManager().getWorkingCopies(this.owner, true/*add primary WCs*/));
    }
    return this.noCacheNameEnvironment;
  }

  public AssistParser getParser() {

    return this.parser;
  }
  protected boolean hasArrayTypeAsExpectedSuperTypes() {
    if ((this.expectedTypesFilter & ~SUBTYPE) != 0) return false;
   
    if (!this.hasComputedExpectedArrayTypes) {
      if(this.expectedTypes != null) {
        done : for (int i = 0; i <= this.expectedTypesPtr; i++) {
          if(this.expectedTypes[i].isArrayType()) {
            this.hasExpectedArrayTypes = true;
            break done;
          }
        }
      }
     
      this.hasComputedExpectedArrayTypes = true;
    }
   
    return this.hasExpectedArrayTypes;
  }
  protected boolean hasPossibleAnnotationTarget(TypeBinding typeBinding, Scope scope) {
    if (this.targetedElement == TagBits.AnnotationForPackage) {
      long target = typeBinding.getAnnotationTagBits() & TagBits.AnnotationTargetMASK;
      if(target != 0 && (target & TagBits.AnnotationForPackage) == 0) {
        return false;
      }
    } else if ((this.targetedElement & TagBits.AnnotationForType) != 0) {
      if (scope.parent != null &&
          scope.parent.parent != null &&
          scope.parent.referenceContext() instanceof CompletionOnAnnotationOfType &&
          scope.parent.parent instanceof CompilationUnitScope) {
        long target = typeBinding.getAnnotationTagBits() & TagBits.AnnotationTargetMASK;
        if ((this.targetedElement & TagBits.AnnotationForAnnotationType) != 0) {
          if(target != 0 && (target &(TagBits.AnnotationForType | TagBits.AnnotationForAnnotationType)) == 0) {
            return false;
          }
        } else {
          if(target != 0 && (target &(TagBits.AnnotationForType)) == 0) {
            return false;
          }
        }
      }
    }
    return true;
  }
  /**
   * Returns completion string inserted inside a specified inline tag.
   * @param completionName
   * @return char[] Completion text inclunding specified inline tag
   */
  private char[] inlineTagCompletion(char[] completionName, char[] inlineTag) {
    int tagLength= inlineTag.length;
    int completionLength = completionName.length;
    int inlineLength = 2+tagLength+1+completionLength+1;
    char[] inlineCompletion = new char[inlineLength];
    inlineCompletion[0] = '{';
    inlineCompletion[1] = '@';
    System.arraycopy(inlineTag, 0, inlineCompletion, 2, tagLength);
    inlineCompletion[tagLength+2] = ' ';
    System.arraycopy(completionName, 0, inlineCompletion, tagLength+3, completionLength);
    // do not add space at end of inline tag (see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=121026)
    //inlineCompletion[inlineLength-2] = ' ';
    inlineCompletion[inlineLength-1] = '}';
    return inlineCompletion;
  }
  private boolean isAllowingLongComputationProposals() {
    return this.monitor != null;
  }
  private boolean isForbidden(Binding binding) {
    for (int i = 0; i <= this.forbbidenBindingsPtr; i++) {
      if(this.forbbidenBindings[i] == binding) {
        return true;
      }
    }
    return false;
  }

  private boolean isForbiddenType(char[] givenPkgName, char[] givenTypeName, char[][] enclosingTypeNames) {
    // CharOperation.concatWith() handles the cases where input args are null/empty
    char[] fullTypeName = CharOperation.concatWith(enclosingTypeNames, givenTypeName, '.');
    for (int i = 0; i <= this.forbbidenBindingsPtr; i++) {
      if (this.forbbidenBindings[i] instanceof TypeBinding) {
        TypeBinding typeBinding = (TypeBinding) this.forbbidenBindings[i];
        char[] currPkgName = typeBinding.qualifiedPackageName();
        if (CharOperation.equals(givenPkgName, currPkgName))  {
          char[] currTypeName = typeBinding.qualifiedSourceName();
          if (CharOperation.equals(fullTypeName, currTypeName)) {
            return true;
          }
        }
      }
    }
   
    // filter packages ending with enum for projects above 1.5
    // see https://bugs.eclipse.org/bugs/show_bug.cgi?id=317264
    if (this.compilerOptions.sourceLevel >= ClassFileConstants.JDK1_5 &&
        CharOperation.endsWith(givenPkgName, DOT_ENUM)) { //note: it should be .enum and not just enum
        return true;
    }
   
    return false;
  }

  private boolean isIgnored(int kind) {
    return this.requestor.isIgnored(kind);
  }
  boolean isIgnored(int kind, boolean missingTypes) {
    return this.requestor.isIgnored(kind) ||
      (missingTypes && !this.requestor.isAllowingRequiredProposals(kind, CompletionProposal.TYPE_REF));
  }

  private boolean isIgnored(int kind, int requiredProposalKind) {
    return this.requestor.isIgnored(kind) ||
      !this.requestor.isAllowingRequiredProposals(kind, requiredProposalKind);
  }
  private boolean isValidParent(ASTNode parent, ASTNode node, Scope scope){

    if(parent instanceof ParameterizedSingleTypeReference) {
      ParameterizedSingleTypeReference ref = (ParameterizedSingleTypeReference) parent;
      TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables();
      int length = ref.typeArguments == null ? 0 : ref.typeArguments.length;
      int nodeIndex = -1;
      for(int i = length - 1 ; i > -1 ; i--) {
        if(node == ref.typeArguments[i]) {
          nodeIndex = i;
          break;
        }
      }
      if(nodeIndex > -1 && (typeVariables == null || typeVariables.length < nodeIndex + 1)) {
        TypeBinding[] typeBindings = new TypeBinding[nodeIndex + 1];
        for(int i = 0; i < nodeIndex; i++) {
          typeBindings[i] = ref.typeArguments[i].resolvedType;
        }
        typeBindings[nodeIndex] = scope.getJavaLangObject();
        if(typeVariables == null || typeVariables.length == 0) {
          scope.problemReporter().nonGenericTypeCannotBeParameterized(0, ref, ref.resolvedType, typeBindings);
        } else {
          scope.problemReporter().incorrectArityForParameterizedType(ref, ref.resolvedType, typeBindings);
        }
        return false;
      }
    } else if(parent instanceof ParameterizedQualifiedTypeReference) {
      ParameterizedQualifiedTypeReference ref = (ParameterizedQualifiedTypeReference) parent;
      TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables();
      TypeReference[][] arguments = ref.typeArguments;
      int iLength = arguments == null ? 0 : arguments.length;
      for (int i = 0; i < iLength; i++) {
        int jLength = arguments[i] == null ? 0 : arguments[i].length;
        for (int j = 0; j < jLength; j++) {
          if(arguments[i][j] == node && (typeVariables == null || typeVariables.length <= j)) {
            TypeBinding[] typeBindings = new TypeBinding[j + 1];
            for(int k = 0; k < j; k++) {
              typeBindings[k] = ref.typeArguments[i][k].resolvedType;
            }
            typeBindings[j] = scope.getJavaLangObject();
            if(typeVariables == null || typeVariables.length == 0) {
              scope.problemReporter().nonGenericTypeCannotBeParameterized(0, ref, ref.resolvedType, typeBindings);
            } else {
              scope.problemReporter().incorrectArityForParameterizedType(ref, ref.resolvedType, typeBindings);
            }
            return false;
          }
        }
      }
    }
    return true;
  }
  private boolean mustQualifyType(ReferenceBinding type, char[] packageName, Scope scope) {
    if(!mustQualifyType(
        packageName,
        type.sourceName(),
        type.isMemberType() ? type.enclosingType().qualifiedSourceName() : null,
        type.modifiers)) {
      return false;
    }
    ReferenceBinding enclosingType = scope.enclosingSourceType();
    while (enclosingType != null) {
      ReferenceBinding currentType = enclosingType;
      while (currentType != null) {
        ReferenceBinding[] memberTypes = currentType.memberTypes();
        if(memberTypes != null) {
          for (int i = 0; i < memberTypes.length; i++) {
            if (CharOperation.equals(memberTypes[i].sourceName, type.sourceName()) &&
                memberTypes[i].canBeSeenBy(scope)) {
              return memberTypes[i] != type;
            }
          }
        }
        currentType = currentType.superclass();
      }
      enclosingType = enclosingType.enclosingType();
    }
    return true;
  }
  private Initializer parseSnippeInitializer(char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){
    StringBuffer prefix = new StringBuffer();
    prefix.append("public class FakeType {\n "); //$NON-NLS-1$
    if(isStatic) {
      prefix.append("static "); //$NON-NLS-1$
    }
    prefix.append("{\n"); //$NON-NLS-1$
    for (int i = 0; i < localVariableTypeNames.length; i++) {
      ASTNode.printModifiers(localVariableModifiers[i], prefix);
      prefix.append(' ');
      prefix.append(localVariableTypeNames[i]);
      prefix.append(' ');
      prefix.append(localVariableNames[i]);
      prefix.append(';');
    }

    char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$
    this.offset = prefix.length();

    String encoding = this.compilerOptions.defaultEncoding;
    BasicCompilationUnit fakeUnit = new BasicCompilationUnit(
      fakeSource,
      null,
      "FakeType.java", //$NON-NLS-1$
      encoding);

    this.actualCompletionPosition = prefix.length() + position - 1;

    CompilationResult fakeResult = new CompilationResult(fakeUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
    CompilationUnitDeclaration fakeAST = this.parser.dietParse(fakeUnit, fakeResult, this.actualCompletionPosition);

    parseBlockStatements(fakeAST, this.actualCompletionPosition);

    return (Initializer)fakeAST.types[0].fields[0];
  }
  protected void printDebug(CategorizedProblem error) {
    if(CompletionEngine.DEBUG) {
      System.out.print("COMPLETION - completionFailure("); //$NON-NLS-1$
      System.out.print(error);
      System.out.println(")"); //$NON-NLS-1$
    }
  }
  protected void printDebug(CompletionProposal proposal){
    StringBuffer buffer = new StringBuffer();
    printDebug(proposal, 0, buffer);
    System.out.println(buffer.toString());
  }

  private void printDebug(CompletionProposal proposal, int tab, StringBuffer buffer){
    printDebugTab(tab, buffer);
    buffer.append("COMPLETION - "); //$NON-NLS-1$
    switch(proposal.getKind()) {
      case CompletionProposal.ANONYMOUS_CLASS_DECLARATION :
        buffer.append("ANONYMOUS_CLASS_DECLARATION"); //$NON-NLS-1$
        break;
      case CompletionProposal.FIELD_REF :
        buffer.append("FIELD_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.FIELD_REF_WITH_CASTED_RECEIVER :
        buffer.append("FIELD_REF_WITH_CASTED_RECEIVER"); //$NON-NLS-1$
        break;
      case CompletionProposal.KEYWORD :
        buffer.append("KEYWORD"); //$NON-NLS-1$
        break;
      case CompletionProposal.LABEL_REF :
        buffer.append("LABEL_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.LOCAL_VARIABLE_REF :
        buffer.append("LOCAL_VARIABLE_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.METHOD_DECLARATION :
        buffer.append("METHOD_DECLARATION"); //$NON-NLS-1$
        break;
      case CompletionProposal.METHOD_REF :
        buffer.append("METHOD_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.METHOD_REF_WITH_CASTED_RECEIVER :
        buffer.append("METHOD_REF_WITH_CASTED_RECEIVER"); //$NON-NLS-1$
        break;
      case CompletionProposal.PACKAGE_REF :
        buffer.append("PACKAGE_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.TYPE_REF :
        buffer.append("TYPE_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.VARIABLE_DECLARATION :
        buffer.append("VARIABLE_DECLARATION"); //$NON-NLS-1$
        break;
      case CompletionProposal.POTENTIAL_METHOD_DECLARATION :
        buffer.append("POTENTIAL_METHOD_DECLARATION"); //$NON-NLS-1$
        break;
      case CompletionProposal.METHOD_NAME_REFERENCE :
        buffer.append("METHOD_NAME_REFERENCE"); //$NON-NLS-1$
        break;
      case CompletionProposal.ANNOTATION_ATTRIBUTE_REF :
        buffer.append("ANNOTATION_ATTRIBUT_REF"); //$NON-NLS-1$
        break;
      case CompletionProposal.FIELD_IMPORT :
        buffer.append("FIELD_IMPORT"); //$NON-NLS-1$
        break;
      case CompletionProposal.METHOD_IMPORT :
        buffer.append("METHOD_IMPORT"); //$NON-NLS-1$
        break;
      case CompletionProposal.TYPE_IMPORT :
        buffer.append("TYPE_IMPORT"); //$NON-NLS-1$
        break;
      case CompletionProposal.CONSTRUCTOR_INVOCATION :
        buffer.append("CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
        break;
      case CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION :
        buffer.append("ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION"); //$NON-NLS-1$
        break;
      default :
        buffer.append("PROPOSAL"); //$NON-NLS-1$
        break;

    }

    buffer.append("{\n");//$NON-NLS-1$
    printDebugTab(tab, buffer);
    buffer.append("\tCompletion[").append(proposal.getCompletion() == null ? "null".toCharArray() : proposal.getCompletion()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    printDebugTab(tab, buffer);
    buffer.append("\tDeclarationSignature[").append(proposal.getDeclarationSignature() == null ? "null".toCharArray() : proposal.getDeclarationSignature()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    printDebugTab(tab, buffer);
    buffer.append("\tDeclarationKey[").append(proposal.getDeclarationKey() == null ? "null".toCharArray() : proposal.getDeclarationKey()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    printDebugTab(tab, buffer);
    buffer.append("\tSignature[").append(proposal.getSignature() == null ? "null".toCharArray() : proposal.getSignature()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    printDebugTab(tab, buffer);
    buffer.append("\tKey[").append(proposal.getKey() == null ? "null".toCharArray() : proposal.getKey()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    printDebugTab(tab, buffer);
    buffer.append("\tName[").append(proposal.getName() == null ? "null".toCharArray() : proposal.getName()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$

    printDebugTab(tab, buffer);
    buffer.append("\tFlags[");//$NON-NLS-1$
    int flags = proposal.getFlags();
    buffer.append(Flags.toString(flags));
    if((flags & Flags.AccInterface) != 0) buffer.append("interface ");//$NON-NLS-1$
    if((flags & Flags.AccEnum) != 0) buffer.append("enum ");//$NON-NLS-1$
    buffer.append("]\n"); //$NON-NLS-1$

    CompletionProposal[] proposals = proposal.getRequiredProposals();
    if(proposals != null) {
      printDebugTab(tab, buffer);
      buffer.append("\tRequiredProposals[");//$NON-NLS-1$
      for (int i = 0; i < proposals.length; i++) {
        buffer.append("\n"); //$NON-NLS-1$
        printDebug(proposals[i], tab + 2, buffer);
      }
      printDebugTab(tab, buffer);
      buffer.append("\n\t]\n"); //$NON-NLS-1$
    }

    printDebugTab(tab, buffer);
    buffer.append("\tCompletionLocation[").append(proposal.getCompletionLocation()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$
    int start = proposal.getReplaceStart();
    int end = proposal.getReplaceEnd();
    printDebugTab(tab, buffer);
    buffer.append("\tReplaceStart[").append(start).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
    buffer.append("-ReplaceEnd[").append(end).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$
    start = proposal.getTokenStart();
    end = proposal.getTokenEnd();
    printDebugTab(tab, buffer);
    buffer.append("\tTokenStart[").append(start).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
    buffer.append("-TokenEnd[").append(end).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$
    if (this.source != null) {
      printDebugTab(tab, buffer);
      buffer.append("\tReplacedText[").append(this.source, start, end-start).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$
    }
    printDebugTab(tab, buffer);
    buffer.append("\tTokenStart[").append(proposal.getTokenStart()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$
    buffer.append("-TokenEnd[").append(proposal.getTokenEnd()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$
    printDebugTab(tab, buffer);
    buffer.append("\tRelevance[").append(proposal.getRelevance()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$

    printDebugTab(tab, buffer);
    buffer.append("}\n");//$NON-NLS-1$
  }

  private void printDebugTab(int tab, StringBuffer buffer) {
    for (int i = 0; i < tab; i++) {
      buffer.append('\t');
    }
  }
 
  private void proposeConstructor(AcceptedConstructor deferredProposal, Scope scope) {
    if (deferredProposal.proposeConstructor) {
      proposeConstructor(
          deferredProposal.simpleTypeName,
          deferredProposal.parameterCount,
          deferredProposal.signature,
          deferredProposal.parameterTypes,
          deferredProposal.parameterNames,
          deferredProposal.modifiers,
          deferredProposal.packageName,
          deferredProposal.typeModifiers,
          deferredProposal.accessibility,
          deferredProposal.simpleTypeName,
          deferredProposal.fullyQualifiedName,
          deferredProposal.mustBeQualified,
          scope,
          deferredProposal.extraFlags);
    }
  }
 
  private void proposeConstructor(
      char[] simpleTypeName,
      int parameterCount,
      char[] signature,
      char[][] parameterTypes,
      char[][] parameterNames,
      int modifiers,
      char[] packageName,
      int typeModifiers,
      int accessibility,
      char[] typeName,
      char[] fullyQualifiedName,
      boolean isQualified,
      Scope scope,
      int extraFlags) {
    char[] typeCompletion = fullyQualifiedName;
    if(isQualified) {
      if (packageName == null || packageName.length == 0)
        if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
          return; // ignore types from the default package from outside it
    } else {
      typeCompletion = simpleTypeName;
    }

    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution();
    relevance += computeRelevanceForInterestingProposal();
    relevance += computeRelevanceForRestrictions(accessibility);
    relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
    relevance += computeRelevanceForExpectingType(packageName, simpleTypeName);
    relevance += computeRelevanceForQualification(isQualified);

    boolean isInterface = false;
    int kind = typeModifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation);
    switch (kind) {
      case ClassFileConstants.AccAnnotation:
      case ClassFileConstants.AccAnnotation | ClassFileConstants.AccInterface:
        relevance += computeRelevanceForAnnotation();
        relevance += computeRelevanceForInterface();
        isInterface = true;
        break;
      case ClassFileConstants.AccEnum:
        relevance += computeRelevanceForEnum();
        break;
      case ClassFileConstants.AccInterface:
        relevance += computeRelevanceForInterface();
        isInterface = true;
        break;
      default:
        relevance += computeRelevanceForClass();
        relevance += computeRelevanceForException(simpleTypeName);
        break;
    }
   
    char[] completion;
    if (this.source != null
          && this.source.length > this.endPosition
          && this.source[this.endPosition] == '(') {
      completion = CharOperation.NO_CHAR;
    } else {
      completion = new char[] { '(', ')' };
    }
   
    InternalCompletionProposal typeProposal = createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition);
    typeProposal.nameLookup = this.nameEnvironment.nameLookup;
    typeProposal.completionEngine = this;
    typeProposal.setDeclarationSignature(packageName);
    typeProposal.setSignature(createNonGenericTypeSignature(packageName, typeName));
    typeProposal.setPackageName(packageName);
    typeProposal.setTypeName(typeName);
    typeProposal.setCompletion(typeCompletion);
    typeProposal.setFlags(typeModifiers);
    typeProposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
    typeProposal.setTokenRange(this.startPosition - this.offset, this.endPosition - this.offset);
    typeProposal.setRelevance(relevance);
   
    switch (parameterCount) {
      case -1: // default constructor
        int flags = Flags.AccPublic;
        if (Flags.isDeprecated(typeModifiers)) {
          flags |= Flags.AccDeprecated;
        }
       
        if (isInterface || (typeModifiers & ClassFileConstants.AccAbstract) != 0) {
          this.noProposal = false;
          if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
            InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
            proposal.setDeclarationSignature(createNonGenericTypeSignature(packageName, typeName));
            proposal.setDeclarationKey(createBindingKey(packageName, typeName));
            proposal.setSignature(DEFAULT_CONSTRUCTOR_SIGNATURE);
            proposal.setDeclarationPackageName(packageName);
            proposal.setDeclarationTypeName(typeName);
            proposal.setParameterPackageNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterTypeNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterNames(CharOperation.NO_CHAR_CHAR);
            proposal.setName(simpleTypeName);
            proposal.setRequiredProposals(new CompletionProposal[]{typeProposal});
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(flags);
            proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        } else {
          this.noProposal = false;
          if(!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
            proposal.setDeclarationSignature(createNonGenericTypeSignature(packageName, typeName));
            proposal.setSignature(DEFAULT_CONSTRUCTOR_SIGNATURE);
            proposal.setDeclarationPackageName(packageName);
            proposal.setDeclarationTypeName(typeName);
            proposal.setParameterPackageNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterTypeNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterNames(CharOperation.NO_CHAR_CHAR);
            proposal.setName(simpleTypeName);
            proposal.setRequiredProposals(new CompletionProposal[]{typeProposal});
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(flags);
            proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
        break;
      case 0: // constructor with no parameter
       
        if ((typeModifiers & ClassFileConstants.AccAbstract) != 0) {
          this.noProposal = false;
          if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
            InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
            proposal.setDeclarationSignature(createNonGenericTypeSignature(packageName, typeName));
            proposal.setDeclarationKey(createBindingKey(packageName, typeName));
            proposal.setSignature(DEFAULT_CONSTRUCTOR_SIGNATURE);
            proposal.setDeclarationPackageName(packageName);
            proposal.setDeclarationTypeName(typeName);
            proposal.setParameterPackageNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterTypeNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterNames(CharOperation.NO_CHAR_CHAR);
            proposal.setName(simpleTypeName);
            proposal.setRequiredProposals(new CompletionProposal[]{typeProposal});
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(modifiers);
            proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        } else {
          this.noProposal = false;
          if(!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
            proposal.setDeclarationSignature(createNonGenericTypeSignature(packageName, typeName));
            proposal.setSignature(DEFAULT_CONSTRUCTOR_SIGNATURE);
            proposal.setDeclarationPackageName(packageName);
            proposal.setDeclarationTypeName(typeName);
            proposal.setParameterPackageNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterTypeNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterNames(CharOperation.NO_CHAR_CHAR);
            proposal.setName(simpleTypeName);
            proposal.setRequiredProposals(new CompletionProposal[]{typeProposal});
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(modifiers);
            proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
        break;
      default: // constructor with parameter
        if (signature == null) {
          // resolve type to found parameter types
          signature = getResolvedSignature(parameterTypes, fullyQualifiedName, parameterCount, scope);
          if (signature == null) return;
        } else {
          signature = CharOperation.replaceOnCopy(signature, '/', '.');
        }
       
        int parameterNamesLength = parameterNames == null ? 0 : parameterNames.length;
        if (parameterCount != parameterNamesLength) {
          parameterNames = null;
        }
       
        if ((typeModifiers & ClassFileConstants.AccAbstract) != 0) {
          this.noProposal = false;
          if(!isIgnored(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
            InternalCompletionProposal proposal = createProposal(CompletionProposal.ANONYMOUS_CLASS_CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
            proposal.setDeclarationSignature(createNonGenericTypeSignature(packageName, typeName));
            proposal.setDeclarationKey(createBindingKey(packageName, typeName));
            proposal.setSignature(signature);
            proposal.setDeclarationPackageName(packageName);
            proposal.setDeclarationTypeName(typeName);
            proposal.setParameterPackageNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterTypeNames(CharOperation.NO_CHAR_CHAR);
            if (parameterNames != null) {
              proposal.setParameterNames(parameterNames);
            } else {
              proposal.setHasNoParameterNamesFromIndex(true);
            }
            proposal.setName(simpleTypeName);
            proposal.setRequiredProposals(new CompletionProposal[]{typeProposal});
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(modifiers);
            proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        } else {
          this.noProposal = false;
          if(!isIgnored(CompletionProposal.CONSTRUCTOR_INVOCATION, CompletionProposal.TYPE_REF)) {
            InternalCompletionProposal proposal =  createProposal(CompletionProposal.CONSTRUCTOR_INVOCATION, this.actualCompletionPosition);
            proposal.setDeclarationSignature(createNonGenericTypeSignature(packageName, typeName));
            proposal.setSignature(signature);
            proposal.setDeclarationPackageName(packageName);
            proposal.setDeclarationTypeName(typeName);
            proposal.setParameterPackageNames(CharOperation.NO_CHAR_CHAR);
            proposal.setParameterTypeNames(CharOperation.NO_CHAR_CHAR);
            if (parameterNames != null) {
              proposal.setParameterNames(parameterNames);
            } else {
              proposal.setHasNoParameterNamesFromIndex(true);
            }
            proposal.setName(simpleTypeName);
            proposal.setRequiredProposals(new CompletionProposal[]{typeProposal});
            proposal.setIsContructor(true);
            proposal.setCompletion(completion);
            proposal.setFlags(modifiers);
            proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - this.offset);
            proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
            proposal.setRelevance(relevance);
           
            this.requestor.accept(proposal);
            if(DEBUG) {
              this.printDebug(proposal);
            }
          }
        }
        break;
    }
  }

  private void proposeNewMethod(char[] token, ReferenceBinding reference) {
    if(!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) {
      int relevance = computeBaseRelevance();
      relevance += computeRelevanceForResolution();
      relevance += computeRelevanceForInterestingProposal();
      relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for new method

      InternalCompletionProposal proposal =  createProposal(CompletionProposal.POTENTIAL_METHOD_DECLARATION, this.actualCompletionPosition);
      proposal.setDeclarationSignature(getSignature(reference));
      proposal.setSignature(
          createMethodSignature(
              CharOperation.NO_CHAR_CHAR,
              CharOperation.NO_CHAR_CHAR,
              CharOperation.NO_CHAR,
              VOID));
      proposal.setDeclarationPackageName(reference.qualifiedPackageName());
      proposal.setDeclarationTypeName(reference.qualifiedSourceName());

      //proposal.setPackageName(null);
      proposal.setTypeName(VOID);
      proposal.setName(token);
      //proposal.setParameterPackageNames(null);
      //proposal.setParameterTypeNames(null);
      //proposal.setPackageName(null);
      proposal.setCompletion(token);
      proposal.setFlags(Flags.AccPublic);
      proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset);
      proposal.setTokenRange(this.tokenStart - this.offset, this.tokenEnd - this.offset);
      proposal.setRelevance(relevance);
      this.requestor.accept(proposal);
      if(DEBUG) {
        this.printDebug(proposal);
      }
    }
  }

  private void proposeType(
      char[] packageName,
      char[] simpleTypeName,
      int modifiers,
      int accessibility,
      char[] typeName,
      char[] fullyQualifiedName,
      boolean isQualified,
      Scope scope) {
    char[] completionName = fullyQualifiedName;
    if(isQualified) {
      if (packageName == null || packageName.length == 0)
        if (this.unitScope != null && this.unitScope.fPackage.compoundName != CharOperation.NO_CHAR_CHAR)
          return; // ignore types from the default package from outside it
    } else {
      completionName = simpleTypeName;
    }

    TypeBinding guessedType = null;
    if ((modifiers & ClassFileConstants.AccAnnotation) != 0 &&
        this.assistNodeIsAnnotation &&
        (this.targetedElement & TagBits.AnnotationTargetMASK) != 0) {
      char[][] cn = CharOperation.splitOn('.', fullyQualifiedName);

      TypeReference ref;
      if (cn.length == 1) {
        ref = new SingleTypeReference(simpleTypeName, 0);
      } else {
        ref = new QualifiedTypeReference(cn,new long[cn.length]);
      }

      switch (scope.kind) {
        case Scope.METHOD_SCOPE :
        case Scope.BLOCK_SCOPE :
          guessedType = ref.resolveType((BlockScope)scope);
          break;
        case Scope.CLASS_SCOPE :
          guessedType = ref.resolveType((ClassScope)scope);
          break;
      }

      if (guessedType == null || !guessedType.isValidBinding()) return;

      if (!hasPossibleAnnotationTarget(guessedType, scope)) return;
    }

    int relevance = computeBaseRelevance();
    relevance += computeRelevanceForResolution();
    relevance += computeRelevanceForInterestingProposal(packageName, fullyQualifiedName);
    relevance += computeRelevanceForRestrictions(accessibility);
    relevance += computeRelevanceForCaseMatching(this.completionToken, simpleTypeName);
    relevance += computeRelevanceForExpectingType(packageName, simpleTypeName);
    relevance += computeRelevanceForQualification(isQualified);

    int kind = modifiers & (ClassFileConstants.AccInterface | ClassFileConstants.AccEnum | ClassFileConstants.AccAnnotation);
    switch (kind) {
      case ClassFileConstants.AccAnnotation:
      case ClassFileConstants.AccAnnotation | ClassFileConstants.AccInterface:
        relevance += computeRelevanceForAnnotation();
        if (guessedType != null) relevance += computeRelevanceForAnnotationTarget(guessedType);
        relevance += computeRelevanceForInterface();
        break;
      case ClassFileConstants.AccEnum:
        relevance += computeRelevanceForEnum();
        break;
      case ClassFileConstants.AccInterface:
        relevance += computeRelevanceForInterface();
        break;
      default:
        relevance += computeRelevanceForClass();
        relevance += computeRelevanceForException(simpleTypeName);
        break;
    }

    this.noProposal = false;
    if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) {
      createTypeProposal(packageName, typeName, modifiers, accessibility, completionName, relevance);
    }
  }

  protected void reset() {

    super.reset(false);
    this.knownPkgs = new HashtableOfObject(10);
    this.knownTypes = new HashtableOfObject(10);
    if (this.noCacheNameEnvironment != null) {
      this.noCacheNameEnvironment.cleanup();
      this.noCacheNameEnvironment = null;
      JavaModelManager.getJavaModelManager().flushZipFiles(this);
    }
  }

  private void setSourceAndTokenRange(int start, int end) {
    this.setSourceAndTokenRange(start, end, true);
  }

  private void setSourceAndTokenRange(int start, int end, boolean emptyTokenAdjstment) {
    this.setSourceRange(start, end, emptyTokenAdjstment);
    this.setTokenRange(start, end, emptyTokenAdjstment);
  }

  private void setSourceRange(int start, int end) {
    this.setSourceRange(start, end, true);
  }

  private void setSourceRange(int start, int end, boolean emptyTokenAdjstment) {
    this.startPosition = start;
    if(emptyTokenAdjstment) {
      int endOfEmptyToken = ((CompletionScanner)this.parser.scanner).endOfEmptyToken;
      this.endPosition = endOfEmptyToken > end ? endOfEmptyToken + 1 : end + 1;
    } else {
      this.endPosition = end + 1;
    }
  }

  private void setTokenRange(int start, int end) {
    this.setTokenRange(start, end, true);
  }
  private void setTokenRange(int start, int end, boolean emptyTokenAdjstment) {
    this.tokenStart = start;
    if(emptyTokenAdjstment) {
      int endOfEmptyToken = ((CompletionScanner)this.parser.scanner).endOfEmptyToken;
      this.tokenEnd = endOfEmptyToken > end ? endOfEmptyToken + 1 : end + 1;
    } else {
      this.tokenEnd = end + 1;
    }
  }

  private char[] substituteMethodTypeParameterName(char firstName, char startChar, char endChar, char[][] excludedNames, char[][] otherParameterNames) {
    char name = firstName;
    next : while (true) {
      for (int i = 0 ; i < excludedNames.length ; i++){
        if(excludedNames[i].length == 1 && ScannerHelper.toLowerCase(excludedNames[i][0]) == ScannerHelper.toLowerCase(name)) {
          name++;
          if(name > endChar)
            name = startChar;
          if(name == firstName)
            return substituteMethodTypeParameterName(new char[]{firstName}, excludedNames, otherParameterNames);
          continue next;
        }
      }

      for (int i = 0; i < otherParameterNames.length; i++) {
        if(otherParameterNames[i].length == 1 && ScannerHelper.toLowerCase(otherParameterNames[i][0]) == ScannerHelper.toLowerCase(name)) {
          name++;
          if(name > endChar)
            name = startChar;
          if(name == firstName)
            return substituteMethodTypeParameterName(new char[]{firstName}, excludedNames, otherParameterNames);
          continue next;
        }
      }
      break next;
    }
    return new char[]{name};
  }

  private char[] substituteMethodTypeParameterName(char[] firstName, char[][] excludedNames, char[][] otherParameterNames) {
    char[] name = firstName;
    int count = 2;
    next : while(true) {
      for(int k = 0 ; k < excludedNames.length ; k++){
        if(CharOperation.equals(name, excludedNames[k], false)) {
          name = CharOperation.concat(firstName, String.valueOf(count++).toCharArray());
          continue next;
        }
      }
      for (int i = 0; i < otherParameterNames.length; i++) {
        if(CharOperation.equals(name, otherParameterNames[i], false)) {
          name = CharOperation.concat(firstName, String.valueOf(count++).toCharArray());
          continue next;
        }
      }
      break next;
    }
    return name;
  }

  private char[][] substituteMethodTypeParameterNames(TypeVariableBinding[] typeVariables, char[][] excludedNames) {
    char[][] substituedParameterNames = new char[typeVariables.length][];

    for (int i = 0; i < substituedParameterNames.length; i++) {
      substituedParameterNames[i] = typeVariables[i].sourceName;
    }

    boolean foundConflicts = false;

    nextTypeParameter : for (int i = 0; i < typeVariables.length; i++) {
      TypeVariableBinding typeVariableBinding = typeVariables[i];
      char[] methodParameterName = typeVariableBinding.sourceName;

      for (int j = 0; j < excludedNames.length; j++) {
        char[] typeParameterName = excludedNames[j];
        if(CharOperation.equals(typeParameterName, methodParameterName, false)) {
          char[] substitution;
          if(methodParameterName.length == 1) {
            if(ScannerHelper.isUpperCase(methodParameterName[0])) {
              substitution = substituteMethodTypeParameterName(methodParameterName[0], 'A', 'Z', excludedNames, substituedParameterNames);
            } else {
              substitution = substituteMethodTypeParameterName(methodParameterName[0], 'a', 'z', excludedNames, substituedParameterNames);
            }
          } else {
            substitution = substituteMethodTypeParameterName(methodParameterName, excludedNames, substituedParameterNames);
          }
          substituedParameterNames[i] = substitution;

          foundConflicts = true;
          continue nextTypeParameter;
        }
      }
    }

    if(foundConflicts) return substituedParameterNames;
    return null;
  }
}
TOP

Related Classes of org.eclipse.jdt.internal.codeassist.CompletionEngine$CompletionProblemFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.