### Eclipse Workspace Patch 1.0 #P org.eclipse.jdt.core Index: codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java,v retrieving revision 1.198 diff -u -r1.198 CompletionParser.java --- codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java 23 Jul 2008 09:48:45 -0000 1.198 +++ codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionParser.java 9 Oct 2008 11:46:21 -0000 @@ -1554,9 +1554,9 @@ System.arraycopy(labels, 0, labels = new char[labelCount][], 0, labelCount); long position = this.identifierPositionStack[this.identifierPtr]; - CompletionOnBrankStatementLabel statementLabel = - new CompletionOnBrankStatementLabel( - kind == K_INSIDE_BREAK_STATEMENT ? CompletionOnBrankStatementLabel.BREAK : CompletionOnBrankStatementLabel.CONTINUE, + CompletionOnBranchStatementLabel statementLabel = + new CompletionOnBranchStatementLabel( + kind == K_INSIDE_BREAK_STATEMENT ? CompletionOnBranchStatementLabel.BREAK : CompletionOnBranchStatementLabel.CONTINUE, this.identifierStack[this.identifierPtr--], (int) (position >>> 32), (int)position, Index: codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBrankStatementLabel.java =================================================================== RCS file: codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBrankStatementLabel.java diff -N codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBrankStatementLabel.java --- codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBrankStatementLabel.java 27 Jun 2008 16:03:59 -0000 1.4 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2005, 2006 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.complete; - -import org.eclipse.jdt.internal.compiler.ast.BranchStatement; -import org.eclipse.jdt.internal.compiler.flow.FlowContext; -import org.eclipse.jdt.internal.compiler.flow.FlowInfo; -import org.eclipse.jdt.internal.compiler.lookup.BlockScope; - -public class CompletionOnBrankStatementLabel extends BranchStatement { - public static final int BREAK = 1; - public static final int CONTINUE = 2; - - private int kind; - public char[][] possibleLabels; - - public CompletionOnBrankStatementLabel(int kind, char[] l, int s, int e, char[][] possibleLabels) { - super(l, s, e); - this.kind = kind; - this.possibleLabels = possibleLabels; - } - - public FlowInfo analyseCode(BlockScope currentScope, - FlowContext flowContext, FlowInfo flowInfo) { - // Is never called - return null; - } - - public void resolve(BlockScope scope) { - throw new CompletionNodeFound(this, scope); - } - public StringBuffer printStatement(int indent, StringBuffer output) { - printIndent(indent, output); - if(this.kind == CONTINUE) { - output.append("continue "); //$NON-NLS-1$ - } else { - output.append("break "); //$NON-NLS-1$ - } - output.append(";"); //$NON-NLS-1$ - } - -} Index: model/org/eclipse/jdt/internal/core/SourceType.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/SourceType.java,v retrieving revision 1.145 diff -u -r1.145 SourceType.java --- model/org/eclipse/jdt/internal/core/SourceType.java 27 Jun 2008 16:03:51 -0000 1.145 +++ model/org/eclipse/jdt/internal/core/SourceType.java 9 Oct 2008 11:46:22 -0000 @@ -74,14 +74,36 @@ /** * @see IType */ +public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException { + codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor); +} +/** + * @see IType + */ public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException { + codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, owner, null); +} +/** + * @see IType + */ +public void codeComplete( + char[] snippet, + int insertion, + int position, + char[][] localVariableTypeNames, + char[][] localVariableNames, + int[] localVariableModifiers, + boolean isStatic, + CompletionRequestor requestor, + WorkingCopyOwner owner, + IProgressMonitor monitor) throws JavaModelException { if (requestor == null) { throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$ } JavaProject project = (JavaProject) getJavaProject(); SearchableEnvironment environment = project.newSearchableNameEnvironment(owner); - CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner); + CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner, monitor); String source = getCompilationUnit().getSource(); if (source != null && insertion > -1 && insertion < source.length()) { Index: model/org/eclipse/jdt/internal/core/ClassFile.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/ClassFile.java,v retrieving revision 1.143 diff -u -r1.143 ClassFile.java --- model/org/eclipse/jdt/internal/core/ClassFile.java 27 Jun 2008 16:03:50 -0000 1.143 +++ model/org/eclipse/jdt/internal/core/ClassFile.java 9 Oct 2008 11:46:22 -0000 @@ -122,11 +122,22 @@ public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException { codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY); } - +/* (non-Javadoc) + * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.core.runtime.IProgressMonitor) + */ +public void codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException { + codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor); +} /* (non-Javadoc) * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner) */ public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException { + codeComplete(offset, requestor, owner, null); +} +/* (non-Javadoc) + * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner, org.eclipse.core.runtime.IProgressMonitor) + */ +public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException { String source = getSource(); if (source != null) { BinaryType type = (BinaryType) getType(); @@ -136,7 +147,7 @@ null, type.sourceFileName((IBinaryType) type.getElementInfo()), getJavaProject()); // use project to retrieve corresponding .java IFile - codeComplete(cu, cu, offset, requestor, owner, null/*extended context isn't computed*/); + codeComplete(cu, cu, offset, requestor, owner, null/*extended context isn't computed*/, monitor); } } Index: model/org/eclipse/jdt/internal/core/Openable.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/Openable.java,v retrieving revision 1.119 diff -u -r1.119 Openable.java --- model/org/eclipse/jdt/internal/core/Openable.java 9 Oct 2008 08:45:46 -0000 1.119 +++ model/org/eclipse/jdt/internal/core/Openable.java 9 Oct 2008 11:46:22 -0000 @@ -101,7 +101,8 @@ org.eclipse.jdt.internal.compiler.env.ICompilationUnit unitToSkip, int position, CompletionRequestor requestor, WorkingCopyOwner owner, - ITypeRoot typeRoot) throws JavaModelException { + ITypeRoot typeRoot, + IProgressMonitor monitor) throws JavaModelException { if (requestor == null) { throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$ } @@ -125,7 +126,7 @@ environment.unitToSkip = unitToSkip; // code complete - CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner); + CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner, monitor); engine.complete(cu, position, 0, typeRoot); if(performanceStats != null) { performanceStats.endRun(); Index: model/org/eclipse/jdt/internal/core/BinaryType.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/BinaryType.java,v retrieving revision 1.159 diff -u -r1.159 BinaryType.java --- model/org/eclipse/jdt/internal/core/BinaryType.java 27 Jun 2008 16:03:50 -0000 1.159 +++ model/org/eclipse/jdt/internal/core/BinaryType.java 9 Oct 2008 11:46:22 -0000 @@ -82,17 +82,38 @@ public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor) throws JavaModelException { codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY); } - +/* + * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor, IProgressMonitor) + */ +public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException { + codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor); +} /* * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor, WorkingCopyOwner) */ public void codeComplete(char[] snippet,int insertion,int position,char[][] localVariableTypeNames,char[][] localVariableNames,int[] localVariableModifiers,boolean isStatic,CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException { + codeComplete(snippet, insertion, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic, requestor, owner, null); +} +/* + * @see IType#codeComplete(char[], int, int, char[][], char[][], int[], boolean, ICompletionRequestor, WorkingCopyOwner, IProgressMonitor) + */ +public void codeComplete( + char[] snippet, + int insertion, + int position, + char[][] localVariableTypeNames, + char[][] localVariableNames, + int[] localVariableModifiers, + boolean isStatic, + CompletionRequestor requestor, + WorkingCopyOwner owner, + IProgressMonitor monitor) throws JavaModelException { if (requestor == null) { throw new IllegalArgumentException("Completion requestor cannot be null"); //$NON-NLS-1$ } JavaProject project = (JavaProject) getJavaProject(); SearchableEnvironment environment = project.newSearchableNameEnvironment(owner); - CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner); + CompletionEngine engine = new CompletionEngine(environment, requestor, project.getOptions(true), project, owner, monitor); String source = getClassFile().getSource(); if (source != null && insertion > -1 && insertion < source.length()) { Index: model/org/eclipse/jdt/internal/core/CompilationUnit.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/CompilationUnit.java,v retrieving revision 1.252 diff -u -r1.252 CompilationUnit.java --- model/org/eclipse/jdt/internal/core/CompilationUnit.java 5 Sep 2008 13:30:43 -0000 1.252 +++ model/org/eclipse/jdt/internal/core/CompilationUnit.java 9 Oct 2008 11:46:22 -0000 @@ -336,18 +336,30 @@ public void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException { codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY); } - +/* (non-Javadoc) + * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.core.runtime.IProgressMonitor) + */ +public void codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException { + codeComplete(offset, requestor, DefaultWorkingCopyOwner.PRIMARY, monitor); +} /* (non-Javadoc) * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner) */ public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner workingCopyOwner) throws JavaModelException { + codeComplete(offset, requestor, workingCopyOwner, null); +} +/* (non-Javadoc) + * @see org.eclipse.jdt.core.ICodeAssist#codeComplete(int, org.eclipse.jdt.core.CompletionRequestor, org.eclipse.jdt.core.WorkingCopyOwner, org.eclipse.core.runtime.IProgressMonitor) + */ +public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner workingCopyOwner, IProgressMonitor monitor) throws JavaModelException { codeComplete( this, isWorkingCopy() ? (org.eclipse.jdt.internal.compiler.env.ICompilationUnit) getOriginalElement() : this, offset, requestor, workingCopyOwner, - this); + this, + monitor); } /** Index: model/org/eclipse/jdt/core/eval/IEvaluationContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/eval/IEvaluationContext.java,v retrieving revision 1.25 diff -u -r1.25 IEvaluationContext.java --- model/org/eclipse/jdt/core/eval/IEvaluationContext.java 27 Jun 2008 16:04:08 -0000 1.25 +++ model/org/eclipse/jdt/core/eval/IEvaluationContext.java 9 Oct 2008 11:46:22 -0000 @@ -177,6 +177,34 @@ int position, CompletionRequestor requestor) throws JavaModelException; + + /** + * Performs a code completion at the given position in the given code snippet, + * reporting results to the given completion requestor. + *

+ * Note that code completion does not involve evaluation. + *

+ * + * @param codeSnippet the code snippet to complete in + * @param position the character position in the code snippet to complete at, + * or -1 indicating the beginning of the snippet + * @param requestor the code completion requestor capable of accepting all + * possible types of completions + * @param monitor the progress monitor used to report progress + * @exception JavaModelException if code completion could not be performed. Reasons include: + *

+ * @since 3.5 + */ + public void codeComplete( + String codeSnippet, + int position, + CompletionRequestor requestor, + IProgressMonitor monitor) + throws JavaModelException; + /** * Performs a code completion at the given position in the given code snippet, * reporting results to the given completion requestor. @@ -210,6 +238,43 @@ CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException; + + /** + * Performs a code completion at the given position in the given code snippet, + * reporting results to the given completion requestor. + * It considers types in the working copies with the given owner first. In other words, + * the owner's working copies will take precedence over their original compilation units + * in the workspace. + *

+ * Note that if a working copy is empty, it will be as if the original compilation + * unit had been deleted. + *

+ *

+ * Note that code completion does not involve evaluation. + *

+ * + * @param codeSnippet the code snippet to complete in + * @param position the character position in the code snippet to complete at, + * or -1 indicating the beginning of the snippet + * @param requestor the code completion requestor capable of accepting all + * possible types of completions + * @param owner the owner of working copies that take precedence over their original compilation units + * @param monitor the progress monitor used to report progress + * @exception JavaModelException if code completion could not be performed. Reasons include: + *

+ * @since 3.5 + */ + public void codeComplete( + String codeSnippet, + int position, + CompletionRequestor requestor, + WorkingCopyOwner owner, + IProgressMonitor monitor) + throws JavaModelException; + /** * Resolves and returns a collection of Java elements corresponding to the source * code at the given positions in the given code snippet. Index: codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java,v retrieving revision 1.377 diff -u -r1.377 CompletionEngine.java --- codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java 25 Sep 2008 23:10:30 -0000 1.377 +++ codeassist/org/eclipse/jdt/internal/codeassist/CompletionEngine.java 9 Oct 2008 11:46:21 -0000 @@ -14,6 +14,8 @@ 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; @@ -64,6 +66,7 @@ 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.util.Messages; /** * This class is the entry point for source completions. @@ -73,7 +76,43 @@ public final class CompletionEngine extends Engine implements ISearchRequestor, TypeConstants , TerminalTokens , RelevanceConstants, SuffixConstants { + + 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; @@ -133,6 +172,7 @@ char[] originatingFileName, int problemId, String[] problemArguments, + int elaborationId, String[] messageArguments, int severity, int start, @@ -144,6 +184,7 @@ originatingFileName, problemId, problemArguments, + elaborationId, messageArguments, severity, start, @@ -156,7 +197,6 @@ char[] originatingFileName, int problemId, String[] problemArguments, - int elaborationId, String[] messageArguments, int severity, int start, @@ -168,7 +208,6 @@ originatingFileName, problemId, problemArguments, - elaborationId, messageArguments, severity, start, @@ -188,67 +227,109 @@ } } - private static class AcceptedType { - 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 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); } - 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; + return Signature.createMethodSignature( + parameterTypeSignature, + returnTypeSignature); + } - 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 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); } - public HashtableOfObject typeCache; + 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; + } + public HashtableOfObject typeCache; + public static boolean DEBUG = false; public static boolean PERF = false; - + + private final static int CHECK_CANCEL_FREQUENCY_IN_FIND_TYPES = 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[] 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$ @@ -257,40 +338,39 @@ 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 int FIELD = 0; private final static int LOCAL = 1; private final static int ARGUMENT = 2; - int expectedTypesPtr = -1; TypeBinding[] expectedTypes = new TypeBinding[1]; int expectedTypesFilter; boolean hasJavaLangObjectAsExpectedType = false; + int uninterestingBindingsPtr = -1; + Binding[] uninterestingBindings = new Binding[1]; int forbbidenBindingsPtr = -1; Binding[] forbbidenBindings = new Binding[1]; int forbbidenBindingsFilter; - ImportBinding[] favoriteReferenceBindings; - boolean assistNodeIsClass; boolean assistNodeIsEnum; boolean assistNodeIsException; boolean assistNodeIsInterface; + boolean assistNodeIsAnnotation; + boolean assistNodeIsConstructor; boolean assistNodeIsSuperType; int assistNodeInJavadoc = 0; boolean assistNodeCanBeSingleMemberAnnotation = false; - long targetedElement; - WorkingCopyOwner owner; + IProgressMonitor monitor; IJavaProject javaProject; ITypeRoot typeRoot; CompletionParser parser; @@ -307,13 +387,15 @@ 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); Scanner nameScanner; - - /* + + /* static final char[][] mainDeclarations = new char[][] { "package".toCharArray(), @@ -349,23 +431,19 @@ 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= ClassFileConstants.JDK1_4 && packageName.length == 0) { - continue next; // import of default package is forbidden when compliance is 1.4 or higher + + 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_IN_FIND_TYPES) == 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[] 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; + char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.'); + + if (this.knownTypes.containsKey(fullyQualifiedName)) continue next; + + this.knownTypes.put(fullyQualifiedName, this); + + 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(); + 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 { - completionName = CharOperation.concat(completionName, new char[] { ';' }); - } - - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - 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])) { + 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, @@ -557,50 +720,43 @@ accessibility, typeName, fullyQualifiedName, - !CharOperation.equals(fullyQualifiedName, importName[1]), + false, 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; + } 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) { + 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( @@ -608,82 +764,79 @@ 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; + } 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) { + if(CharOperation.equals(fullyQualifiedEnclosingTypeOrPackageName, importFlatName)) { + if(importBinding.isStatic()) { + if((modifiers & ClassFileConstants.AccStatic) != 0) { + foundType.mustBeQualified = true; + break done; + } + } else { foundType.mustBeQualified = true; break done; } - } else { - foundType.mustBeQualified = true; - break done; } } } + proposeType( + packageName, + simpleTypeName, + modifiers, + accessibility, + typeName, + fullyQualifiedName, + true, + scope); } - 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(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); + + char[][] keys = onDemandFound.keyTable; + Object[] values = onDemandFound.valueTable; + int max = keys.length; + for (int i = 0; i < max; i++) { + 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 } - this.acceptedTypes = null; // reset + + } - + public void acceptUnresolvedName(char[] name) { int relevance = computeBaseRelevance(); relevance += computeRelevanceForResolution(false); @@ -709,6 +862,41 @@ } } } + 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) { @@ -741,127 +929,6 @@ return true; } - 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(); - 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); - } - } - - /** - * 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); - } - } - } - private void buildContext( ASTNode astNode, ASTNode astNodeParent, @@ -991,6 +1058,12 @@ } } + private void checkCancel() { + if (this.monitor != null && this.monitor.isCanceled()) { + throw new OperationCanceledException(); + } + } + private boolean complete( ASTNode astNode, ASTNode astNodeParent, @@ -1012,501 +1085,600 @@ buildContext(astNode, astNodeParent, compilationUnitDeclaration, qualifiedBinding, scope); if (astNode instanceof CompletionOnFieldType) { - - 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)) { - findMethods( - this.completionToken, - null, - null, - enclosingType, - scope, - new ObjectVector(), - false, - false, - true, - null, - null, - false, - false, - true, - null, - null, - null, - false, - null, - -1, - -1); - } - if (!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) { - proposeNewMethod(this.completionToken, enclosingType); - } - } - } + completionOnFieldType(astNode, scope); } else if (astNode instanceof CompletionOnMethodReturnType) { - - 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); + 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; + } - if (method.modifiers == ClassFileConstants.AccDefault) { - SourceTypeBinding enclosingType = scope.enclosingSourceType(); - if (!enclosingType.isAnnotationType()) { - if (!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) { - findMethods( - this.completionToken, - null,null, - scope.enclosingSourceType(), - scope, - new ObjectVector(), - false, - false, - true, - null, - null, - false, - false, - true, - null, - null, - null, - false, - null, - -1, - -1); - } - if (!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) { - proposeNewMethod(this.completionToken, scope.enclosingSourceType()); - } - } - } - } else if (astNode instanceof CompletionOnSingleNameReference) { + /** + * 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) { - 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(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()); } - 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); - } - findVariablesAndMethods( - this.completionToken, - scope, - singleNameReference, - scope, - insideTypeAnnotation, - singleNameReference.isInsideAnnotationAttribute); - // 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); + // 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 (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); + if(this.noProposal && this.problem != null) { + this.requestor.completionFailure(this.problem); + if(DEBUG) { + this.printDebug(this.problem); + } } + return; } - } - } else if (astNode instanceof CompletionOnSingleTypeReference) { - - CompletionOnSingleTypeReference singleRef = (CompletionOnSingleTypeReference) astNode; + 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); - this.completionToken = singleRef.token; + long positions = importReference.sourcePositions[importReference.sourcePositions.length - 1]; + setSourceAndTokenRange((int) (positions >>> 32), (int) positions); - this.assistNodeIsClass = singleRef.isClass(); - this.assistNodeIsException = singleRef.isException(); - this.assistNodeIsInterface = singleRef.isInterface(); - this.assistNodeIsConstructor = singleRef.isConstructorType; - this.assistNodeIsSuperType = singleRef.isSuperType(); + char[][] oldTokens = importReference.tokens; + int tokenCount = oldTokens.length; + if (tokenCount == 1) { + findImports((CompletionOnImportReference)importReference, true); + } else if(tokenCount > 1){ + this.insideQualifiedReference = true; - // 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); + char[] lastToken = oldTokens[tokenCount - 1]; + char[][] qualifierTokens = CharOperation.subarray(oldTokens, 0, tokenCount - 1); - findParameterizedType((TypeReference)astNodeParent, scope); - } else { - ObjectVector typesFound = new ObjectVector(); - if (this.assistNodeIsException && astNodeParent instanceof TryStatement) { - findExceptionFromTryStatement( - this.completionToken, - null, - scope.enclosingSourceType(), - (BlockScope)scope, - typesFound); - } - 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); - } - } else if (astNode instanceof CompletionOnQualifiedNameReference) { + Binding binding = this.unitScope.getTypeOrPackage(qualifierTokens); + if(binding != null) { + if(binding instanceof PackageBinding) { + findImports((CompletionOnImportReference)importReference, false); + } else { + ReferenceBinding ref = (ReferenceBinding) binding; - this.insideQualifiedReference = true; - CompletionOnQualifiedNameReference ref = - (CompletionOnQualifiedNameReference) astNode; - this.completionToken = ref.completionIdentifier; - long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1]; + if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { + findImportsOfMemberTypes(lastToken, ref, importReference.isStatic()); + } + if(importReference.isStatic()) { - 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(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { + findImportsOfStaticFields(lastToken, ref); + } + if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) { + findImportsOfStaticMethods(lastToken, ref); + } + } + } + } + } - if (!foundSomeFields) { - findMembersFromMissingType( - ref.tokens[0], - ref.sourcePositions[0], - null, - scope, - ref, - ref.isInsideAnnotationAttribute); + 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; } } } - } 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); - - findFieldsAndMethodsFromCastedReceiver( - enclosingNode, - qualifiedBinding, - scope, - fieldsFound, - methodsFound, - ref, - scope, - ref); + if (parsedUnit.types != null) { + try { + this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); - } 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); + 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); } } } + } - } else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) { - boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute; - ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding; - setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition); + 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(); + } + } - findMembers( - this.completionToken, - receiverType, - scope, - ref, - isInsideAnnotationAttribute, - null, - null, - null, - false); + 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(); + } - } else if (qualifiedBinding instanceof PackageBinding) { + this.fileName = topLevelType.getParent().getElementName().toCharArray(); + CompilationResult compilationResult = new CompilationResult(this.fileName, 1, 1, this.compilerOptions.maxProblemsPerUnit); - setSourceRange(astNode.sourceStart, (int) completionPosition); - setTokenRange((int) (completionPosition >>> 32), (int) completionPosition); + CompilationUnitDeclaration compilationUnit = null; - // replace to the end of the completion identifier - findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding, scope); + 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); } - } else if (astNode instanceof CompletionOnQualifiedTypeReference) { - this.insideQualifiedReference = true; + if(typeDeclaration != null) { + // build AST from snippet + Initializer fakeInitializer = parseSnippeInitializer(snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic); - CompletionOnQualifiedTypeReference ref = - (CompletionOnQualifiedTypeReference) astNode; + // 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; - this.assistNodeIsClass = ref.isClass(); - this.assistNodeIsException = ref.isException(); - this.assistNodeIsInterface = ref.isInterface(); - this.assistNodeIsSuperType = ref.isSuperType(); + if(DEBUG) { + System.out.println("SNIPPET COMPLETION AST :"); //$NON-NLS-1$ + System.out.println(compilationUnit.toString()); + } - this.completionToken = ref.completionIdentifier; - long completionPosition = ref.sourcePositions[ref.tokens.length]; + if (compilationUnit.types != null) { + try { + this.lookupEnvironment.buildTypeBindings(compilationUnit, null /*no access restriction*/); - // 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); + 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); + } } } - } 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); + 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); } - - 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); } - } else if (astNode instanceof CompletionOnMemberAccess) { - 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) { - findFieldsAndMethodsFromCastedReceiver( - enclosingNode, - qualifiedBinding, - scope, - fieldsFound, - methodsFound, - access, - scope, - access.receiver); - } - } + } 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); } - - } else if (astNode instanceof CompletionOnMessageSend) { + } 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); + } + } + + private void completionOnFieldName(ASTNode astNode, Scope scope) { + if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { + CompletionOnFieldName field = (CompletionOnFieldName) astNode; - 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(); + FieldBinding[] fields = scope.enclosingSourceType().fields(); + char[][] excludeNames = new char[fields.length][]; + for(int i = 0 ; i < fields.length ; i++){ + excludeNames[i] = fields[i].name; + } - findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope, methodsFound); + this.completionToken = field.realName; - findLocalMethodsFromStaticImports( + findVariableNames(field.realName, field.type, excludeNames, null, FIELD, field.modifiers); + } + } + + 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, - messageSend, - scope, - true, - methodsFound, - true); + 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); + } + } + //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 (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { + } 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, - argTypes, - (ReferenceBinding)((ReferenceBinding) qualifiedBinding).capture(scope, messageSend.receiver.sourceEnd), + null, + receiverType, scope, new ObjectVector(), + false, /*not only static */ false, - true, - false, - messageSend, + fieldRef, scope, false, - messageSend.receiver instanceof SuperReference, false, + true, null, null, null, @@ -1514,443 +1686,466 @@ 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); + } + } } - } else if (astNode instanceof CompletionOnExplicitConstructorCall) { - 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); - } - } else if (astNode instanceof CompletionOnQualifiedAllocationExpression) { - setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, 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; - CompletionOnQualifiedAllocationExpression allocExpression = - (CompletionOnQualifiedAllocationExpression) astNode; - TypeBinding[] argTypes = computeTypes(allocExpression.arguments); + // 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); - ReferenceBinding ref = (ReferenceBinding) qualifiedBinding; - if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF) - && ref.isClass() - && !ref.isAbstract()) { - findConstructors( - ref, - argTypes, - scope, - allocExpression, - false); + if (qualifiedBinding == null) { + if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { + findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope, new ObjectVector()); } - if (!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION) - && !ref.isFinal() - && !ref.isEnum()){ - findAnonymousType( - ref, - argTypes, + } 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, - allocExpression); + scope.enclosingSourceType(), + false, + false, + new ObjectVector(), + null, + null, + null, + false); } - } else if (astNode instanceof CompletionOnClassLiteralAccess) { - if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { - CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode; - setSourceAndTokenRange(access.classStart, access.sourceEnd); + } else if (qualifiedBinding instanceof PackageBinding) { - this.completionToken = access.completionIdentifier; - - findClassField( - this.completionToken, - (TypeBinding) qualifiedBinding, - scope, - null, - null, - null, - false); + 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 = LOCAL; + } else { + CompletionOnArgumentName arg = (CompletionOnArgumentName) variable; + this.completionToken = arg.realName; + kind = arg.isCatchArgument ? LOCAL : ARGUMENT; } - } else if (astNode instanceof CompletionOnMethodName) { - if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { - CompletionOnMethodName method = (CompletionOnMethodName) astNode; - setSourceAndTokenRange(method.sourceStart, method.selectorEnd); + char[][] alreadyDefinedName = computeAlreadyDefinedName((BlockScope)scope, variable); - 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; - - findVariableNames(this.completionToken, method.returnType, excludeNames, null, FIELD, method.modifiers); - } - } else if (astNode instanceof CompletionOnFieldName) { - if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { - CompletionOnFieldName field = (CompletionOnFieldName) astNode; + char[][] forbiddenNames = findVariableFromUnresolvedReference(variable, (BlockScope)scope, alreadyDefinedName); - FieldBinding[] fields = scope.enclosingSourceType().fields(); - char[][] excludeNames = new char[fields.length][]; - for(int i = 0 ; i < fields.length ; i++){ - excludeNames[i] = fields[i].name; + 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; } - - this.completionToken = field.realName; - - findVariableNames(field.realName, field.type, excludeNames, null, FIELD, field.modifiers); } - } else if (astNode instanceof CompletionOnLocalName || astNode instanceof CompletionOnArgumentName) { - if (!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { - LocalDeclaration variable = (LocalDeclaration) astNode; - - int kind; - if (variable instanceof CompletionOnLocalName){ - this.completionToken = ((CompletionOnLocalName) variable).realName; - kind = LOCAL; - } else { - CompletionOnArgumentName arg = (CompletionOnArgumentName) variable; - this.completionToken = arg.realName; - kind = arg.isCatchArgument ? LOCAL : ARGUMENT; - } - - 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); - System.arraycopy(discouragedNames, 0, discouragedNames = new char[localCount][], 0, localCount); + findVariableNames(this.completionToken, variable.type, discouragedNames, forbiddenNames, kind, variable.modifiers); + } + } + + private void completionOnMarkerAnnotationName(ASTNode astNode, Binding qualifiedBinding, Scope scope) { + CompletionOnMarkerAnnotationName annot = (CompletionOnMarkerAnnotationName) astNode; - findVariableNames(this.completionToken, variable.type, discouragedNames, forbiddenNames, kind, variable.modifiers); - } - } else if (astNode instanceof CompletionOnKeyword) { - if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { - CompletionOnKeyword keyword = (CompletionOnKeyword)astNode; - findKeywords(keyword.getToken(), keyword.getPossibleKeywords(), keyword.canCompleteEmptyToken(), false); + 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); } - } else if (astNode instanceof CompletionOnParameterizedQualifiedTypeReference) { - 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.assistNodeIsAnnotation = true; + if (annot.type instanceof CompletionOnSingleTypeReference) { + CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) annot.type; + this.completionToken = type.token; + setSourceAndTokenRange(type.sourceStart, type.sourceEnd); - this.completionToken = ref.completionIdentifier; - long completionPosition = ref.sourcePositions[ref.tokens.length]; - setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition); + if (scope.parent.parent != null && + !(scope.parent.parent instanceof MethodScope) && + !fakeType.isParameter) { - 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); + 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); } } - } else { - ObjectVector typesFound = new ObjectVector(); - if (this.assistNodeIsException && astNodeParent instanceof TryStatement) { - findExceptionFromTryStatement( - this.completionToken, - (ReferenceBinding)qualifiedBinding, - scope.enclosingSourceType(), - (BlockScope)scope, - typesFound); - } - - findMemberTypes( - this.completionToken, - (ReferenceBinding) qualifiedBinding, - scope, - scope.enclosingSourceType(), - false, - false, - typesFound, - null, - null, - null, - false); } } - } else if (astNode instanceof CompletionOnMarkerAnnotationName) { - 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); - } + 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) { - 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); + 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, + 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, - scope.enclosingSourceType(), - false, - false, - new ObjectVector(), - null, - null, - null, - false); - } + access, + insideTypeAnnotation); } - } else if (astNode instanceof CompletionOnMemberValueName) { - CompletionOnMemberValueName memberValuePair = (CompletionOnMemberValueName) astNode; - Annotation annotation = (Annotation) astNodeParent; - - this.completionToken = memberValuePair.name; + } else { + if (!access.isInsideAnnotation) { + if (!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { + findKeywords(this.completionToken, new char[][]{Keywords.NEW}, false, false); + } - ReferenceBinding annotationType = (ReferenceBinding)annotation.resolvedType; + ObjectVector fieldsFound = new ObjectVector(); + ObjectVector methodsFound = new ObjectVector(); - 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; - } - } + boolean superCall = access.receiver instanceof SuperReference; - } - if (scope instanceof BlockScope && !this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) { - char[][] alreadyDefinedName = computeAlreadyDefinedName((BlockScope)scope, FakeInvocationSite); + findFieldsAndMethods( + this.completionToken, + ((TypeBinding) qualifiedBinding).capture(scope, access.receiver.sourceEnd), + scope, + fieldsFound, + methodsFound, + access, + scope, + false, + superCall, + null, + null, + null, + false, + null, + -1, + -1); - findUnresolvedReference( - memberValuePair.sourceStart, - memberValuePair.sourceEnd, - (BlockScope)scope, - alreadyDefinedName); - } - findVariablesAndMethods( - this.completionToken, + if (!superCall) { + + checkCancel(); + + findFieldsAndMethodsFromCastedReceiver( + enclosingNode, + qualifiedBinding, scope, - FakeInvocationSite, + fieldsFound, + methodsFound, + access, scope, - insideTypeAnnotation, - true); - // can be the start of a qualified type name - findTypesAndPackages(this.completionToken, scope, false, false, new ObjectVector()); - } + access.receiver); } } - } else if(astNode instanceof CompletionOnBrankStatementLabel) { - if (!this.requestor.isIgnored(CompletionProposal.LABEL_REF)) { - CompletionOnBrankStatementLabel label = (CompletionOnBrankStatementLabel) astNode; + } + } + + private void completionOnMemberValueName(ASTNode astNode, ASTNode astNodeParent, Scope scope, + boolean insideTypeAnnotation) { + CompletionOnMemberValueName memberValuePair = (CompletionOnMemberValueName) astNode; + Annotation annotation = (Annotation) astNodeParent; - this.completionToken = label.label; + this.completionToken = memberValuePair.name; - findLabels(this.completionToken, label.possibleLabels); + ReferenceBinding annotationType = (ReferenceBinding)annotation.resolvedType; + + if (annotationType != null && annotationType.isAnnotationType()) { + if (!this.requestor.isIgnored(CompletionProposal.ANNOTATION_ATTRIBUTE_REF)) { + findAnnotationAttributes(this.completionToken, annotation.memberValuePairs(), annotationType); } - } else if(astNode instanceof CompletionOnMessageSendName) { - if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { - CompletionOnMessageSendName messageSend = (CompletionOnMessageSendName) astNode; + 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; + } + } - 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, - false, - messageSend, - scope, - false, - false, - false, - null, - null, - null, - false, - null, - -1, - -1); } + 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()); } } - // Completion on Javadoc nodes - } else if ((astNode.bits & ASTNode.InsideJavadoc) != 0) { - if (astNode instanceof CompletionOnJavadocSingleTypeReference) { + } + } + + private void completionOnMessageSend(ASTNode astNode, Binding qualifiedBinding, Scope scope) { + setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false); - CompletionOnJavadocSingleTypeReference typeRef = (CompletionOnJavadocSingleTypeReference) astNode; - this.completionToken = typeRef.token; - this.javadocTagPosition = typeRef.tagSourceStart; - setSourceAndTokenRange(typeRef.sourceStart, typeRef.sourceEnd); - findTypesAndPackages( + 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, - (this.assistNodeInJavadoc & CompletionOnJavadoc.BASE_TYPES) != 0, - false, - new ObjectVector()); - - } else if (astNode instanceof CompletionOnJavadocQualifiedTypeReference) { + 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.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; + } - 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( + TypeBinding receiverType = (TypeBinding)qualifiedBinding; + + if(receiverType != null && receiverType instanceof ReferenceBinding) { + TypeBinding[] typeArgTypes = computeTypesIfCorrect(messageSend.typeArguments); + if(typeArgTypes != null) { + findMethods( this.completionToken, - (ReferenceBinding) qualifiedBinding, - scope, - scope.enclosingSourceType(), - false, - false, - new ObjectVector(), - null, - null, + typeArgTypes, 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); - } - } else if (astNode instanceof CompletionOnJavadocFieldReference) { - - 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, + (ReferenceBinding)receiverType.capture(scope, messageSend.receiver.sourceEnd), scope, new ObjectVector(), - new ObjectVector(), - false, /*not only static */ - fieldRef, + onlyStatic, + false, + messageSend, scope, false, - true, + false, + false, null, null, null, @@ -1958,3115 +2153,2886 @@ 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; + + findVariableNames(this.completionToken, method.returnType, excludeNames, null, FIELD, method.modifiers); + } + } + + 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 (!this.requestor.isIgnored(CompletionProposal.METHOD_REF) - || !this.requestor.isIgnored(CompletionProposal.JAVADOC_METHOD_REF)) { - findMethods( + if (method.modifiers == ClassFileConstants.AccDefault) { + SourceTypeBinding enclosingType = scope.enclosingSourceType(); + if (!enclosingType.isAnnotationType()) { + if (!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) { + findMethodDeclarations( this.completionToken, - null, - null, - receiverType, + scope.enclosingSourceType(), scope, new ObjectVector(), - false, /*not only static */ - false, - 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); - } - } - } - } - } else if (astNode instanceof CompletionOnJavadocMessageSend) { - - 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 */, - false, - messageSend, - scope, - false, - messageSend.receiver instanceof SuperReference, - true, - null, - null, - null, - false, - null, - -1, - -1); - } - } else if (astNode instanceof CompletionOnJavadocAllocationExpression) { -// 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); - } - } else if (astNode instanceof CompletionOnJavadocParamNameReference) { - 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); + false); } - } else if (astNode instanceof CompletionOnJavadocTypeParamReference) { - if (!this.requestor.isIgnored(CompletionProposal.JAVADOC_PARAM_REF)) { - CompletionOnJavadocTypeParamReference paramRef = (CompletionOnJavadocTypeParamReference) astNode; - setSourceAndTokenRange(paramRef.tagSourceStart, paramRef.tagSourceEnd); - findJavadocParamNames(paramRef.token, paramRef.missingParams, true); + if (!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) { + proposeNewMethod(this.completionToken, scope.enclosingSourceType()); } - } else if (astNode instanceof CompletionOnJavadocTag) { - CompletionOnJavadocTag javadocTag = (CompletionOnJavadocTag) astNode; - setSourceAndTokenRange(javadocTag.tagSourceStart, javadocTag.sourceEnd); - findJavadocBlockTags(javadocTag); - findJavadocInlineTags(javadocTag); } } - return true; } + + private void completionOnParameterizedQualifiedTypeReference(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope) { + if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { + CompletionOnParameterizedQualifiedTypeReference ref = (CompletionOnParameterizedQualifiedTypeReference) astNode; - 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; - - if (!(ifStatement.condition instanceof InstanceOfExpression)) return; - - InstanceOfExpression instanceOfExpression = (InstanceOfExpression) ifStatement.condition; - - TypeReference instanceOfType = instanceOfExpression.type; - - if (instanceOfType.resolvedType == null) return; + this.insideQualifiedReference = true; - boolean findFromAnotherReceiver = false; + this.assistNodeIsClass = ref.isClass(); + this.assistNodeIsException = ref.isException(); + this.assistNodeIsInterface = ref.isInterface(); + this.assistNodeIsSuperType = ref.isSuperType(); - char[][] receiverName = null; - int receiverStart = -1; - int receiverEnd = -1; + this.completionToken = ref.completionIdentifier; + long completionPosition = ref.sourcePositions[ref.tokens.length]; + setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition); - if (receiver instanceof QualifiedNameReference) { - QualifiedNameReference qualifiedNameReference = (QualifiedNameReference) receiver; + 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 void completionOnQualifiedAllocationExpression(ASTNode astNode, Binding qualifiedBinding, Scope scope) { + setSourceAndTokenRange(astNode.sourceStart, astNode.sourceEnd, false); - receiverName = qualifiedNameReference.tokens; + CompletionOnQualifiedAllocationExpression allocExpression = + (CompletionOnQualifiedAllocationExpression) astNode; + TypeBinding[] argTypes = computeTypes(allocExpression.arguments); + + ReferenceBinding ref = (ReferenceBinding) qualifiedBinding; + if (!this.requestor.isIgnored(CompletionProposal.METHOD_REF) + && ref.isClass() + && !ref.isAbstract()) { + findConstructors( + ref, + argTypes, + scope, + allocExpression, + false); + } + + checkCancel(); + + if (!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION) + && !ref.isFinal() + && !ref.isEnum()){ + findAnonymousType( + ref, + argTypes, + scope, + allocExpression); + } + } + + 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 (receiverName.length != 1) return; + 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(); - receiverStart = (int) (qualifiedNameReference.sourcePositions[0] >>> 32); - receiverEnd = (int) qualifiedNameReference.sourcePositions[qualifiedNameReference.tokens.length - 1] + 1; + findFieldsAndMethods( + this.completionToken, + receiverType.capture(scope, ref.sourceEnd), + scope, + fieldsFound, + methodsFound, + ref, + scope, + false, + false, + null, + null, + null, + false, + null, + -1, + -1); + + checkCancel(); - // 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; - } + findFieldsAndMethodsFromCastedReceiver( + enclosingNode, + qualifiedBinding, + scope, + fieldsFound, + methodsFound, + ref, + scope, + ref); - // if (this.field instanceof X) field.| - if (instanceOfExpression.expression instanceof FieldReference) { - FieldReference fieldReference = (FieldReference)instanceOfExpression.expression; + } 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); + } - 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) { + } else if (qualifiedBinding instanceof ReferenceBinding && !(qualifiedBinding instanceof TypeVariableBinding)) { + boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute; + ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding; + setSourceAndTokenRange((int) (completionPosition >>> 32), (int) completionPosition); - receiverName = new char[][] {THIS, fieldReference1.token}; + findMembers( + this.completionToken, + receiverType, + scope, + ref, + isInsideAnnotationAttribute, + null, + null, + null, + false); - // if (field instanceof X) this.field.| - if (instanceOfExpression.expression instanceof SingleNameReference && - ((SingleNameReference)instanceOfExpression.expression).binding == fieldReference1.binding) { - findFromAnotherReceiver = true; - } + } else if (qualifiedBinding instanceof PackageBinding) { - // if (this.field instanceof X) this.field.| - if (instanceOfExpression.expression instanceof FieldReference) { - FieldReference fieldReference2 = (FieldReference)instanceOfExpression.expression; + setSourceRange(astNode.sourceStart, (int) completionPosition); + setTokenRange((int) (completionPosition >>> 32), (int) completionPosition); - if (fieldReference2.receiver instanceof ThisReference && - fieldReference2.binding == fieldReference1.binding) { - findFromAnotherReceiver = true; - } - } - } + // 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; - if (findFromAnotherReceiver) { - TypeBinding receiverTypeBinding = instanceOfType.resolvedType; - char[] castedReceiver = null; + CompletionOnQualifiedTypeReference ref = + (CompletionOnQualifiedTypeReference) astNode; - char[] castedTypeChars = CharOperation.concatWith(instanceOfType.getTypeName(), '.'); - if(this.source != null) { - int memberRefStart = this.startPosition; + this.assistNodeIsClass = ref.isClass(); + this.assistNodeIsException = ref.isException(); + this.assistNodeIsInterface = ref.isInterface(); + this.assistNodeIsSuperType = ref.isSuperType(); - char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd); - char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart); + this.completionToken = ref.completionIdentifier; + long completionPosition = ref.sourcePositions[ref.tokens.length]; - 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); + // 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); - if (castedReceiver == null) return; + ObjectVector typesFound = new ObjectVector(); - int oldStartPosition = this.startPosition; - this.startPosition = receiverStart; + if (this.assistNodeIsException && astNodeParent instanceof TryStatement) { + findExceptionFromTryStatement( + this.completionToken, + (ReferenceBinding)qualifiedBinding, + scope.enclosingSourceType(), + (BlockScope)scope, + typesFound); + } + + checkCancel(); - findFieldsAndMethods( + findMemberTypes( this.completionToken, - receiverTypeBinding, + (ReferenceBinding) qualifiedBinding, scope, - fieldsFound, - methodsFound, - invocationSite, - invocationScope, + scope.enclosingSourceType(), false, false, + typesFound, null, null, null, - false, - castedReceiver, - receiverStart, - receiverEnd); + false); + } + } else if (qualifiedBinding instanceof PackageBinding) { - this.startPosition = oldStartPosition; + 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; + } + } - 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(); + } + 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.fileName = topLevelType.getParent().getElementName().toCharArray(); - CompilationResult compilationResult = new CompilationResult(this.fileName, 1, 1, this.compilerOptions.maxProblemsPerUnit); + this.completionToken = singleRef.token; - CompilationUnitDeclaration compilationUnit = null; + this.assistNodeIsClass = singleRef.isClass(); + this.assistNodeIsException = singleRef.isException(); + this.assistNodeIsInterface = singleRef.isInterface(); + this.assistNodeIsConstructor = singleRef.isConstructorType; + this.assistNodeIsSuperType = singleRef.isSuperType(); + + // 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); - 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]; + findParameterizedType((TypeReference)astNodeParent, scope); } 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); - } + 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); } - } 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(); + } 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 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(';'); - } + private char[][] computeAlreadyDefinedName( + BlockScope scope, + InvocationSite invocationSite) { + ArrayList result = new ArrayList(); - char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$ - this.offset = prefix.length(); + boolean staticsOnly = false; - String encoding = this.compilerOptions.defaultEncoding; - BasicCompilationUnit fakeUnit = new BasicCompilationUnit( - fakeSource, - null, - "FakeType.java", //$NON-NLS-1$ - encoding); + Scope currentScope = scope; - this.actualCompletionPosition = prefix.length() + position - 1; + done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found - CompilationResult fakeResult = new CompilationResult(fakeUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); - CompilationUnitDeclaration fakeAST = this.parser.dietParse(fakeUnit, fakeResult, this.actualCompletionPosition); + switch (currentScope.kind) { - parseBlockStatements(fakeAST, this.actualCompletionPosition); + 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; - return (Initializer)fakeAST.types[0].fields[0]; - } + //$FALL-THROUGH$ + case Scope.BLOCK_SCOPE : + BlockScope blockScope = (BlockScope) currentScope; - /** - * 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) { + next : for (int i = 0, length = blockScope.locals.length; i < length; i++) { + LocalVariableBinding local = blockScope.locals[i]; - 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()); - } - this.requestor.beginReporting(); - boolean contextAccepted = false; - try { - this.fileName = sourceUnit.getFileName(); - this.actualCompletionPosition = completionPosition - 1; - this.offset = pos; - this.typeRoot = root; - // 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); + if (local == null) + break next; - // boolean completionNodeFound = false; - if (parsedUnit != null) { - if(DEBUG) { - System.out.println("COMPLETION - Diet AST :"); //$NON-NLS-1$ - System.out.println(parsedUnit.toString()); - } + if (local.isSecret()) + continue next; - // 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); - } + result.add(local.name); } - return; - } + break; - 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); + case Scope.CLASS_SCOPE : + ClassScope classScope = (ClassScope) currentScope; + SourceTypeBinding enclosingType = classScope.referenceContext.binding; + computeAlreadyDefinedName( + enclosingType, + classScope, + staticsOnly, + invocationSite, + result); + staticsOnly |= enclosingType.isStatic(); + break; - long positions = importReference.sourcePositions[importReference.sourcePositions.length - 1]; - setSourceAndTokenRange((int) (positions >>> 32), (int) positions); + case Scope.COMPILATION_UNIT_SCOPE : + break done1; + } + currentScope = currentScope.parent; + } - char[][] oldTokens = importReference.tokens; - int tokenCount = oldTokens.length; - if (tokenCount == 1) { - findImports((CompletionOnImportReference)importReference, true); - } else if(tokenCount > 1){ - this.insideQualifiedReference = true; + if (result.size() == 0) return CharOperation.NO_CHAR_CHAR; - char[] lastToken = oldTokens[tokenCount - 1]; - char[][] qualifierTokens = CharOperation.subarray(oldTokens, 0, tokenCount - 1); + return (char[][])result.toArray(new char[result.size()][]); + } - Binding binding = this.unitScope.getTypeOrPackage(qualifierTokens); - if(binding != null) { - if(binding instanceof PackageBinding) { - findImports((CompletionOnImportReference)importReference, false); - } else { - ReferenceBinding ref = (ReferenceBinding) binding; + private void computeAlreadyDefinedName( + FieldBinding[] fields, + Scope scope, + boolean onlyStaticFields, + ReferenceBinding receiverType, + InvocationSite invocationSite, + ArrayList result) { - if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { - findImportsOfMemberTypes(lastToken, ref, importReference.isStatic()); - } - if(importReference.isStatic()) { + next : for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; - if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { - findImportsOfStaticFields(lastToken, ref); - } - if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) { - findImportsOfStaticMethods(lastToken, ref); - } - } - } - } - } + if (field.isSynthetic()) continue next; - 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 (onlyStaticFields && !field.isStatic()) continue next; - if (parsedUnit.types != null) { - try { - this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); + if (!field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; - 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); - } + 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; } } } - 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); - } + FieldBinding[] fields = currentType.availableFields(); + if(fields != null && fields.length > 0) { + computeAlreadyDefinedName( + fields, + scope, + onlyStaticFields, + receiverType, + invocationSite, + result); } - /* 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 + 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; } - */ - } 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 { - reset(); - 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(); } } - private long computeTargetedElement(CompletionOnAnnotationOfType fakeNode) { - ASTNode annotatedElement = fakeNode.potentialAnnotatedNode; + int computeBaseRelevance(){ + return R_DEFAULT; + } - if (annotatedElement instanceof TypeDeclaration) { - TypeDeclaration annotatedTypeDeclaration = (TypeDeclaration) annotatedElement; - if (TypeDeclaration.kind(annotatedTypeDeclaration.modifiers) == TypeDeclaration.ANNOTATION_TYPE_DECL) { - return TagBits.AnnotationForAnnotationType | TagBits.AnnotationForType; + 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) { + AbstractVariableDeclaration variable = (AbstractVariableDeclaration)parent; + TypeBinding binding = variable.type.resolvedType; + if(binding != null) { + if(!(variable.initialization instanceof ArrayInitializer)) { + addExpectedType(binding, scope); + } } - return TagBits.AnnotationForType; - } else if (annotatedElement instanceof FieldDeclaration) { - if (fakeNode.isParameter) { - return TagBits.AnnotationForParameter; + } else if(parent instanceof Assignment) { + TypeBinding binding = ((Assignment)parent).lhs.resolvedType; + if(binding != null) { + addExpectedType(binding, scope); } - 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 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); + } 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); } } - } - } - private void findAnonymousType( - ReferenceBinding currentType, - TypeBinding[] argTypes, - Scope scope, - InvocationSite invocationSite) { + } else if(parent instanceof CastExpression) { + Expression 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 (currentType.isInterface()) { - char[] completion = CharOperation.NO_CHAR; - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + if(messageSend.actualReceiverType instanceof ReferenceBinding) { + ReferenceBinding binding = (ReferenceBinding)messageSend.actualReceiverType; + boolean isStatic = messageSend.receiver.isTypeReference(); - this.noProposal = false; - if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)) { - 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); - 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); + 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 { - findConstructors( - currentType, - argTypes, - scope, - invocationSite, - true); - } - } - - private void findClassField( - char[] token, - TypeBinding receiverType, - Scope scope, - Binding[] missingElements, - int[] missingElementsStarts, - int[] missingElementsEnds, - boolean missingElementsHaveProblems) { - - if (token == null) return; + } else if(parent instanceof AllocationExpression) { + AllocationExpression allocationExpression = (AllocationExpression) parent; - 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; + ReferenceBinding binding = (ReferenceBinding)allocationExpression.type.resolvedType; - if (missingElements != null) { - relevance += computeRelevanceForMissingElements(missingElementsHaveProblems); + if(binding != null) { + computeExpectedTypesForAllocationExpression( + binding, + allocationExpression.arguments, + scope, + allocationExpression); } - - 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); + } 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; } - } - } - } - - private void findEnumConstants( - char[] enumConstantName, - ReferenceBinding enumType, - Scope invocationScope, - ObjectVector fieldsFound, - char[][] alreadyUsedConstants, - int alreadyUsedConstantCount, - boolean needQualification) { - - FieldBinding[] fields = enumType.fields(); + } 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); + } - int enumConstantLength = enumConstantName.length; - next : for (int f = fields.length; --f >= 0;) { - FieldBinding field = fields[f]; + } + } + } + } 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; + 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--; - if (field.isSynthetic()) continue next; + TypeBinding bound = typeVariables[index].firstBound; + addExpectedType(bound == null ? scope.getJavaLangObject() : bound, scope); + } + } else if(parent instanceof ParameterizedQualifiedTypeReference) { + ParameterizedQualifiedTypeReference ref = (ParameterizedQualifiedTypeReference) parent; + TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables(); + TypeReference[][] arguments = ref.typeArguments; + 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(); + ReferenceBinding[] bindings = thrownExceptionFinder.find((TryStatement) parent, (BlockScope)scope); + if (bindings != null && bindings.length > 0) { + for (int i = 0; i < bindings.length; i++) { + addExpectedType(bindings[i], scope); + } + this.expectedTypesFilter = SUPERTYPE; + } + } + } else if (parent instanceof SwitchStatement) { + SwitchStatement switchStatement = (SwitchStatement) parent; + if (switchStatement.expression != null && + switchStatement.expression.resolvedType != null) { + addExpectedType(switchStatement.expression.resolvedType, scope); + } - if ((field.modifiers & Flags.AccEnum) == 0) continue next; + // 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 (enumConstantLength > field.name.length) continue next; + if(this.expectedTypesPtr + 1 != this.expectedTypes.length) { + System.arraycopy(this.expectedTypes, 0, this.expectedTypes = new TypeBinding[this.expectedTypesPtr + 1], 0, this.expectedTypesPtr + 1); + } + } - if (!CharOperation.prefixEquals(enumConstantName, field.name, false /* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(enumConstantName, field.name))) continue next; + private void computeExpectedTypesForAllocationExpression( + ReferenceBinding binding, + Expression[] arguments, + Scope scope, + InvocationSite invocationSite) { - char[] fieldName = field.name; + MethodBinding[] methods = binding.availableMethods(); + nextMethod : for (int i = 0; i < methods.length; i++) { + MethodBinding method = methods[i]; - for (int i = 0; i < alreadyUsedConstantCount; i++) { - if(CharOperation.equals(alreadyUsedConstants[i], fieldName)) continue next; - } + if (!method.isConstructor()) continue nextMethod; - 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); + if (method.isSynthetic()) continue nextMethod; - this.noProposal = false; - if (!needQualification) { - char[] completion = fieldName; + if (this.options.checkVisibility && !method.canBeSeenBy(invocationSite, scope)) continue nextMethod; - 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); - } - } + TypeBinding[] parameters = method.parameters; + if(parameters.length < arguments.length) + continue nextMethod; - } else { - TypeBinding visibleType = invocationScope.getType(field.type.sourceName()); - boolean needImport = visibleType == null || !visibleType.isValidBinding(); + int length = arguments.length - 1; - char[] completion = CharOperation.concat(field.type.sourceName(), field.name, '.'); + for (int j = 0; j < length; j++) { + Expression argument = arguments[j]; + TypeBinding argType = argument.resolvedType; + if(argType != null && !argType.isCompatibleWith(parameters[j])) + continue nextMethod; + } - 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; + 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) { - ReferenceBinding fieldType = (ReferenceBinding)field.type; + MethodBinding[] methods = binding.availableMethods(); + nextMethod : for (int i = 0; i < methods.length; i++) { + MethodBinding method = methods[i]; - 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); + if (method.isSynthetic()) continue nextMethod; - char[] typeImportCompletion = createImportCharArray(CharOperation.concatWith(fieldType.compoundName, '.'), false, false); + if (method.isDefaultAbstract()) continue nextMethod; - 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); + if (method.isConstructor()) continue nextMethod; - proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal}); + if (isStatic && !method.isStatic()) continue nextMethod; - this.requestor.accept(proposal); - if(DEBUG) { - this.printDebug(proposal); - } - } - } + 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; } - } - } - 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); + 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) { - private void findEnumConstantsFromSwithStatement(char[] enumConstantName, SwitchStatement switchStatement) { - TypeBinding expressionType = switchStatement.expression.resolvedType; - if(expressionType != null && expressionType.isEnum()) { - ReferenceBinding enumType = (ReferenceBinding) expressionType; + ReferenceBinding[] itsInterfaces = binding.superInterfaces(); + if (itsInterfaces != Binding.NO_SUPERINTERFACES) { + ReferenceBinding[] interfacesToVisit = itsInterfaces; + int nextPosition = interfacesToVisit.length; - CaseStatement[] cases = switchStatement.cases; + for (int i = 0; i < nextPosition; i++) { + ReferenceBinding currentType = interfacesToVisit[i]; + computeExpectedTypesForMessageSend( + currentType, + selector, + arguments, + receiverType, + scope, + invocationSite, + isStatic); - 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; + 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; + } } } - - 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(); + private Scope computeForbiddenBindings(ASTNode astNode, ASTNode astNodeParent, Scope scope) { + this.forbbidenBindingsFilter = NONE; + if(scope instanceof ClassScope) { + TypeDeclaration typeDeclaration = ((ClassScope)scope).referenceContext; + if(typeDeclaration.superclass == astNode) { + addForbiddenBindings(typeDeclaration.binding); + return scope.parent; + } + TypeReference[] superInterfaces = typeDeclaration.superInterfaces; + int length = superInterfaces == null ? 0 : superInterfaces.length; + for (int i = 0; i < length; i++) { + if(superInterfaces[i] == astNode) { + addForbiddenBindings(typeDeclaration.binding); + return scope.parent; } } - } - - 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 (astNodeParent != null && astNodeParent 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) { + Argument[] catchArguments = ((TryStatement) astNodeParent).catchArguments; + int length = catchArguments == null ? 0 : catchArguments.length; + for (int i = 0; i < length; i++) { + TypeBinding caughtException = catchArguments[i].type.resolvedType; + if (caughtException != null) { + addForbiddenBindings(caughtException); + this.knownTypes.put(CharOperation.concat(caughtException.qualifiedPackageName(), caughtException.qualifiedSourceName(), '.'), this); + } + } + this.forbbidenBindingsFilter = SUBTYPE; } - } else if(!exceptionType.canBeSeenBy(this.unitScope.fPackage)) { - return; } } +// else if(scope instanceof MethodScope) { +// MethodScope methodScope = (MethodScope) scope; +// if(methodScope.insideTypeAnnotation) { +// return methodScope.parent.parent; +// } +// } + return scope; + } - for (int j = typesFound.size; --j >= 0;) { - ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j); + private char[] computePrefix(SourceTypeBinding declarationType, SourceTypeBinding invocationType, boolean isStatic){ - if (exceptionType == otherType) - return; + StringBuffer completion = new StringBuffer(10); - if (CharOperation.equals(exceptionType.sourceName, otherType.sourceName, true)) { + if (isStatic) { + completion.append(declarationType.sourceName()); - if (exceptionType.enclosingType().isSuperclassOf(otherType.enclosingType())) - return; + } else if (declarationType == invocationType) { + completion.append(THIS); - 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); + } else { - char[] completionName = exceptionType.sourceName(); + if (!declarationType.isNestedType()) { - boolean isQualified = false; + completion.append(declarationType.sourceName()); + completion.append('.'); + completion.append(THIS); - if(!this.insideQualifiedReference) { - isQualified = true; + } else if (!declarationType.isAnonymousType()) { - char[] memberPackageName = exceptionType.qualifiedPackageName(); - char[] memberTypeName = exceptionType.sourceName(); - char[] memberEnclosingTypeNames = null; + completion.append(declarationType.sourceName()); + completion.append('.'); + completion.append(THIS); - 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; - } - } - } - + return completion.toString().toCharArray(); + } - break; + private int computeRelevanceForAnnotation(){ + if(this.assistNodeIsAnnotation) { + return R_ANNOTATION; + } + return 0; + } - 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; + 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; } - - 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; + } + 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; } - - if (isQualified) { - completionName = - CharOperation.concat( - memberPackageName, - CharOperation.concat( - memberEnclosingTypeNames, - memberTypeName, - '.'), - '.'); + } 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; + } - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForCaseMatching(typeName, exceptionType.sourceName); - relevance += computeRelevanceForExpectingType(exceptionType); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - if(!this.insideQualifiedReference) { - relevance += computeRelevanceForQualification(isQualified); + private int computeRelevanceForClass(){ + if(this.assistNodeIsClass) { + return R_CLASS; } - relevance += computeRelevanceForClass(); - relevance += computeRelevanceForException(); + return 0; + } - this.noProposal = false; - if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { - createTypeProposal( - exceptionType, - exceptionType.qualifiedSourceName(), - IAccessRule.K_ACCESSIBLE, - completionName, - relevance, - null, - null, - null, - false); + private int computeRelevanceForEnum(){ + if(this.assistNodeIsEnum) { + return R_ENUM; } + return 0; } - 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]; + 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; + } - findExceptionFromTryStatement(typeName, exceptionType, receiverType, invocationType, scope, typesFound, true); + } } + return 0; } - 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()) { + private int computeRelevanceForException(){ + if (this.assistNodeIsException) { + return R_EXCEPTION; + } + return 0; + } - if (constructor.isSynthetic()) continue next; + private int computeRelevanceForException(char[] proposalName){ - if (this.options.checkDeprecation && - constructor.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(constructor.declaringClass)) - continue next; + 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; + } - if (this.options.checkVisibility - && !constructor.canBeSeenBy(invocationSite, scope)) continue next; + 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; + } - TypeBinding[] parameters = constructor.parameters; - int paramLength = parameters.length; + private int computeRelevanceForExpectingType(TypeBinding proposalType){ + if(this.expectedTypes != null && proposalType != null) { + int relevance = 0; + for (int i = 0; i <= this.expectedTypesPtr; i++) { + if((this.expectedTypesFilter & SUBTYPE) != 0 + && proposalType.isCompatibleWith(this.expectedTypes[i])) { - 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(); + if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) && + CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) { + return R_EXACT_EXPECTED_TYPE; } - 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); + relevance = R_EXPECTED_TYPE; + } + if((this.expectedTypesFilter & SUPERTYPE) != 0 + && this.expectedTypes[i].isCompatibleWith(proposalType)) { - 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); - } + 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; } } + return relevance; } + return 0; } - private void findConstructors( - ReferenceBinding currentType, - TypeBinding[] argTypes, - Scope scope, - InvocationSite invocationSite, - boolean forAnonymousType) { - // No visibility checks can be performed without the scope & invocationSite - MethodBinding[] 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()) { + private int computeRelevanceForInheritance(ReferenceBinding receiverType, ReferenceBinding declaringClass) { + if (receiverType == declaringClass) return R_NON_INHERITED; + return 0; + } - if (constructor.isSynthetic()) continue next; + int computeRelevanceForInterestingProposal(){ + return computeRelevanceForInterestingProposal(null); + } - if (this.options.checkDeprecation && - constructor.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(constructor.declaringClass)) - continue next; + private int computeRelevanceForInterestingProposal(Binding binding){ + if(this.uninterestingBindings != null) { + for (int i = 0; i <= this.uninterestingBindingsPtr; i++) { + if(this.uninterestingBindings[i] == binding) { + return 0; + } + } + } + return R_INTERESTING; + } - if (this.options.checkVisibility - && !constructor.canBeSeenBy(invocationSite, scope)) { - if(!forAnonymousType || !constructor.isProtected()) - continue next; - } + private int computeRelevanceForInterface(){ + if(this.assistNodeIsInterface) { + return R_INTERFACE; + } + return 0; + } - 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; - } + private int computeRelevanceForMissingElements(boolean hasProblems) { + if (!hasProblems) { + return R_NO_PROBLEMS; + } + return 0; + } + int computeRelevanceForQualification(boolean prefixRequired) { + if(!prefixRequired && !this.insideQualifiedReference) { + return R_UNQUALIFIED; + } - 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); + if(prefixRequired && this.insideQualifiedReference) { + return R_QUALIFIED; + } + return 0; + } - char[] completion = CharOperation.NO_CHAR; - if(forAnonymousType){ - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + int computeRelevanceForResolution(){ + return computeRelevanceForResolution(true); + } - this.noProposal = false; - if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)) { - 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); - 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 { - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + int computeRelevanceForResolution(boolean isResolved){ + if (isResolved) { + return R_RESOLVED; + } + return 0; + } - // 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; p0) 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(); - } - } + int computeRelevanceForRestrictions(int accessRuleKind) { + if(accessRuleKind == IAccessRule.K_ACCESSIBLE) { + return R_NON_RESTRICTED; + } + return 0; + } - // Create standard proposal - this.noProposal = false; - if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF) && (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()); - 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 int computeRelevanceForStatic(boolean onlyStatic, boolean isStatic) { + if(this.insideQualifiedReference && !onlyStatic && !isStatic) { + return R_NON_STATIC; } + return 0; } - 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; + private long computeTargetedElement(CompletionOnAnnotationOfType fakeNode) { + ASTNode annotatedElement = fakeNode.potentialAnnotatedNode; - 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; + 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; + } - currentScope = currentScope.parent; + 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; + } - if(excludedNameCount == 0) { - return CharOperation.NO_CHAR_CHAR; + private void computeUninterestingBindings(ASTNode parent, Scope scope){ + if(parent instanceof LocalDeclaration) { + addUninterestingBindings(((LocalDeclaration)parent).binding); + } else if (parent instanceof FieldDeclaration) { + addUninterestingBindings(((FieldDeclaration)parent).binding); } - System.arraycopy(excludedNames, 0, excludedNames = new char[excludedNameCount][], 0, excludedNameCount); - return excludedNames; } - // 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) { + 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); + } - ObjectVector newFieldsFound = new ObjectVector(); - // Inherited fields which are hidden by subclasses are filtered out - // No visibility checks can be performed without the scope & invocationSite + 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); + } - int fieldLength = fieldName.length; - next : for (int f = fields.length; --f >= 0;) { - FieldBinding field = fields[f]; + //// Type parameters - if (field.isSynthetic()) continue next; + 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(' '); + } - if (onlyStaticFields && !field.isStatic()) continue next; + //// Return type + createType(method.returnType, scope, completion); + completion.append(' '); - if (fieldLength > field.name.length) continue next; + //// Selector + completion.append(method.selector); - if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) continue next; + completion.append('('); - if (this.options.checkDeprecation && - field.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(field.declaringClass)) - continue next; + ////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('%'); + } + } - if (this.options.checkVisibility - && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; + completion.append(')'); - boolean prefixRequired = false; + //// Exceptions + ReferenceBinding[] exceptions = method.thrownExceptions; - 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; - } + 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); } + } + } - for (int l = localsFound.size; --l >= 0;) { - LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l); + 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; + } - 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; - } - } + private CompletionProposal createRequiredTypeProposal(Binding binding, int start, int end, int relevance) { + InternalCompletionProposal proposal = null; + if (binding instanceof ReferenceBinding) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; - newFieldsFound.add(new Object[]{field, receiverType}); + char[] packageName = typeBinding.qualifiedPackageName(); + char[] typeName = typeBinding.qualifiedSourceName(); + char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.'); - char[] completion = field.name; + 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; - if(prefixRequired || this.options.forceImplicitQualification){ - char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), field.isStatic()); - completion = CharOperation.concat(prefix,completion,'.'); - } + 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; + } - if (castedReceiver != null) { - completion = CharOperation.concat(castedReceiver, completion); - } + 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) { - // 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 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; + } + } - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(field); - if (fieldName != null) relevance += computeRelevanceForCaseMatching(fieldName, field.name); - relevance += computeRelevanceForExpectingType(field.type); - relevance += computeRelevanceForEnumConstant(field.type); - relevance += computeRelevanceForStatic(onlyStaticFields, field.isStatic()); - relevance += computeRelevanceForQualification(prefixRequired); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - if (onlyStaticFields && this.insideQualifiedReference) { - relevance += computeRelevanceForInheritance(receiverType, field.declaringClass); + /* + * 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); } - if (missingElements != null) { - relevance += computeRelevanceForMissingElements(missingElementsHaveProblems); + } + + // 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); } + } + } - 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); - } - } + /* + * Create a completion proposal for a type. + */ + private void createTypeProposal(char[] packageName, char[] typeName, int modifiers, int accessibility, char[] completionName, int relevance) { - // 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); - } - } + // 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); } } - 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; - } - } + // 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); } } } - protected void findFieldsAndMethodsFromAnotherReceiver( - char[] token, - TypeReference receiverType, - Scope scope, - ObjectVector fieldsFound, - ObjectVector methodsFound, - InvocationSite invocationSite, - Scope invocationScope, - boolean implicitCall, - boolean superCall, + /* + * 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, - 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; + boolean missingElementsHaveProblems) { - char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd); - char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart); + // 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); + } + } - castedReceiver = - CharOperation.concat( - CharOperation.concat( - '(', - CharOperation.concat( - CharOperation.concat('(', castedTypeChars, ')'), - receiverChars), - ')'), - dotChars); + // 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 { - castedReceiver = - CharOperation.concat( - CharOperation.concat( - '(', - CharOperation.concat( - CharOperation.concat('(', castedTypeChars, ')'), - CharOperation.concatWith(receiverName, '.')), - ')'), - DOT); + 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 (castedReceiver == null) return; + if(!CharOperation.prefixEquals(token, method.selector, false) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, method.selector))) continue nextAttribute; - int oldStartPosition = this.startPosition; - this.startPosition = receiverStart; + 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; + } - findFieldsAndMethods( - token, - receiverTypeBinding, - scope, - fieldsFound, - methodsFound, - invocationSite, - invocationScope, - implicitCall, - superCall, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(method); + relevance += computeRelevanceForCaseMatching(token, method.selector); + relevance += computeRelevanceForQualification(false); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - this.startPosition = oldStartPosition; + 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); + } + } + } } - protected void findFieldsAndMethods( - char[] token, - TypeBinding receiverType, + private void findAnonymousType( + ReferenceBinding currentType, + TypeBinding[] argTypes, 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; + InvocationSite invocationSite) { - if (receiverType.isBaseType()) - return; // nothing else is possible with base types + if (currentType.isInterface()) { + char[] completion = CharOperation.NO_CHAR; + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - 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); + this.noProposal = false; + if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)) { + 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); + 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); + } + } + private void findClassField( + char[] token, + TypeBinding receiverType, + Scope scope, + Binding[] missingElements, + int[] missingElementsStarts, + int[] missingElementsEnds, + boolean missingElementsHaveProblems) { - if (receiverType.isArrayType()) { - if (proposeField - && token.length <= lengthField.length - && CharOperation.prefixEquals(token, lengthField, false /* ignore case */ - )) { + if (token == null) return; - 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 (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(!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 (missingElements != null) { + relevance += computeRelevanceForMissingElements(missingElementsHaveProblems); } - 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 + 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) { - relevance += computeRelevanceForMissingElements(missingElementsHaveProblems); + 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); } - char[] completion; - if (this.source != null - && this.source.length > this.endPosition - && this.source[this.endPosition] == '(') { - completion = cloneMethod; - } else { - completion = CharOperation.concat(cloneMethod, new char[] { '(', ')' }); + 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); } + } + } + } + private void findConstructors( + ReferenceBinding currentType, + TypeBinding[] argTypes, + Scope scope, + InvocationSite invocationSite, + boolean forAnonymousType) { - if (castedReceiver != null) { - completion = CharOperation.concat(castedReceiver, completion); - } + // No visibility checks can be performed without the scope & invocationSite + MethodBinding[] 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()) { - 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); + 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(); } - 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); + char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames); + + char[] completion = CharOperation.NO_CHAR; + if(forAnonymousType){ + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + + this.noProposal = false; + if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)) { + 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); + 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); } - 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); + } else { + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + + // 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; p0) 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(); + } + } + + // Create standard proposal + this.noProposal = false; + if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF) && (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()); + 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); + } } } } } - - receiverType = scope.getJavaLangObject(); - } - - 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, - false, - invocationSite, - invocationScope, - implicitCall, - superCall, - false, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); } } + private char[][] findEnclosingTypeNames(Scope scope){ + char[][] excludedNames = new char[10][]; + int excludedNameCount = 0; - private void findFieldsAndMethodsFromFavorites( - char[] token, - Scope scope, - InvocationSite invocationSite, - Scope invocationScope, - ObjectVector localsFound, - ObjectVector fieldsFound, - ObjectVector methodsFound) { + Scope currentScope = scope; + while(currentScope != null) { + switch (currentScope.kind) { + case Scope.CLASS_SCOPE : + ClassScope classScope = (ClassScope) currentScope; - ObjectVector methodsFoundFromFavorites = new ObjectVector(); + TypeDeclaration typeDeclaration = classScope.referenceContext; - ImportBinding[] favoriteBindings = getFavoriteReferenceBindings(invocationScope); + if(excludedNameCount == excludedNames.length) { + System.arraycopy(excludedNames, 0, excludedNames = new char[excludedNameCount * 2][], 0, excludedNameCount); + } + excludedNames[excludedNameCount++] = typeDeclaration.name; - 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); + 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; - } - } - } - - methodsFound.addAll(methodsFoundFromFavorites); - } - - private boolean findFieldsAndMethodsFromMissingFieldType( - char[] token, - Scope scope, - InvocationSite invocationSite, - boolean insideTypeAnnotation) { - - boolean foundSomeFields = false; - - boolean staticsOnly = false; - Scope currentScope = scope; - - done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found - - switch (currentScope.kind) { - + } + break; 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(!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); + 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); } - break done; + excludedNames[excludedNameCount++] = typeParameter.name; } } } - staticsOnly |= enclosingType.isStatic(); - insideTypeAnnotation = false; break; - case Scope.COMPILATION_UNIT_SCOPE : - break done; } + currentScope = currentScope.parent; } - return foundSomeFields; + + 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) { - private void findFieldsAndMethodsFromMissingReturnType( - char[] token, - TypeBinding[] arguments, - Scope scope, - InvocationSite invocationSite, - boolean insideTypeAnnotation) { + FieldBinding[] fields = enumType.fields(); - boolean staticsOnly = false; - Scope currentScope = scope; + int enumConstantLength = enumConstantName.length; + next : for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; - done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + if (field.isSynthetic()) continue next; - switch (currentScope.kind) { + if ((field.modifiers & Flags.AccEnum) == 0) continue next; - 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(!insideTypeAnnotation) { + if (enumConstantLength > field.name.length) continue next; - AbstractMethodDeclaration[] methods = classScope.referenceContext.methods; + if (!CharOperation.prefixEquals(enumConstantName, field.name, false /* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(enumConstantName, field.name))) continue next; - 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; + char[] fieldName = field.name; - 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; - } - } - } + 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); } - staticsOnly |= enclosingType.isStatic(); - 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); - } + } else { + TypeBinding visibleType = invocationScope.getType(field.type.sourceName()); + boolean needImport = visibleType == null || !visibleType.isValidBinding(); - private void findFieldsFromFavorites( - char[] fieldName, - FieldBinding[] fields, - Scope scope, - ObjectVector fieldsFound, - ObjectVector localsFound, - ReferenceBinding receiverType, - InvocationSite invocationSite, - Scope invocationScope) { + char[] completion = CharOperation.concat(field.type.sourceName(), field.name, '.'); - char[] typeName = CharOperation.concatWith(receiverType.compoundName, '.'); + 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; - int fieldLength = fieldName.length; - next : for (int f = fields.length; --f >= 0;) { - FieldBinding field = fields[f]; + ReferenceBinding fieldType = (ReferenceBinding)field.type; - if (field.isSynthetic()) continue next; + 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); - // only static fields must be proposed - if (!field.isStatic()) continue next; + char[] typeImportCompletion = createImportCharArray(CharOperation.concatWith(fieldType.compoundName, '.'), false, false); - if (fieldLength > field.name.length) continue next; + 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); - if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) continue next; + proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal}); - if (this.options.checkDeprecation && - field.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(field.declaringClass)) - continue next; + 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); + } + } - if (this.options.checkVisibility - && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; + } + private void findEnumConstantsFromSwithStatement(char[] enumConstantName, SwitchStatement switchStatement) { + TypeBinding expressionType = switchStatement.expression.resolvedType; + if(expressionType != null && expressionType.isEnum()) { + ReferenceBinding enumType = (ReferenceBinding) expressionType; - for (int i = fieldsFound.size; --i >= 0;) { - Object[] other = (Object[])fieldsFound.elementAt(i); - FieldBinding otherField = (FieldBinding) other[0]; + CaseStatement[] cases = switchStatement.cases; - if (field == otherField) continue next; + 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; + } } - fieldsFound.add(new Object[]{field, receiverType}); + 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) { - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(field); - if (fieldName != null) relevance += computeRelevanceForCaseMatching(fieldName, field.name); - relevance += computeRelevanceForExpectingType(field.type); - relevance += computeRelevanceForEnumConstant(field.type); - relevance += computeRelevanceForStatic(true, true); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + 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(); + } + } + } - CompilationUnitDeclaration cu = this.unitScope.referenceContext; - int importStart = cu.types[0].declarationSourceStart; - int importEnd = importStart; + if (typeName.length > exceptionType.sourceName.length) + return; - this.noProposal = false; + if (!CharOperation.prefixEquals(typeName, exceptionType.sourceName, false/* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, exceptionType.sourceName))) + return; - 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, '.'); + if (this.options.checkDeprecation && + exceptionType.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(exceptionType)) + return; - 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); + 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; + } + } - char[] typeImportCompletion = createImportCharArray(typeName, false, false); + for (int j = typesFound.size; --j >= 0;) { + ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j); - 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); + if (exceptionType == otherType) + return; - proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal}); + if (CharOperation.equals(exceptionType.sourceName, otherType.sourceName, true)) { - 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); + if (exceptionType.enclosingType().isSuperclassOf(otherType.enclosingType())) + return; - proposal.setRequiredProposals(new CompletionProposal[]{fieldImportProposal}); + if (otherType.enclosingType().isInterface()) + if (exceptionType.enclosingType() + .implementsInterface(otherType.enclosingType(), true)) + return; - this.requestor.accept(proposal); - if(DEBUG) { - this.printDebug(proposal); - } - } + if (exceptionType.enclosingType().isInterface()) + if (otherType.enclosingType() + .implementsInterface(exceptionType.enclosingType(), true)) + return; } } - } - private void findImports(CompletionOnImportReference importReference, boolean findMembers) { - char[][] tokens = importReference.tokens; + typesFound.add(exceptionType); - char[] importName = CharOperation.concatWith(tokens, '.'); + char[] completionName = exceptionType.sourceName(); - if (importName.length == 0) - return; + boolean isQualified = false; - char[] lastToken = tokens[tokens.length - 1]; - if(lastToken != null && lastToken.length == 0) - importName = CharOperation.concat(importName, new char[]{'.'}); + if(!this.insideQualifiedReference) { + isQualified = true; - this.resolvingImports = true; - this.resolvingStaticImports = importReference.isStatic(); + char[] memberPackageName = exceptionType.qualifiedPackageName(); + char[] memberTypeName = exceptionType.sourceName(); + char[] memberEnclosingTypeNames = null; - this.completionToken = lastToken; - this.qualifiedCompletionToken = importName; + ReferenceBinding enclosingType = exceptionType.enclosingType(); + if (enclosingType != null) { + memberEnclosingTypeNames = exceptionType.enclosingType().qualifiedSourceName(); + } - // 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.nameEnvironment.findTypes( - importName, - findMembers, - this.options.camelCaseMatch, - IJavaSearchConstants.TYPE, - this); - acceptTypes(null); - } - } + Scope currentScope = scope; + done : while (currentScope != null) { // done when a COMPILATION_UNIT_SCOPE is found - private void findImportsOfMemberTypes(char[] typeName, ReferenceBinding ref, boolean onlyStatic) { - ReferenceBinding[] memberTypes = ref.memberTypes(); + switch (currentScope.kind) { - 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; + case Scope.METHOD_SCOPE : + case Scope.BLOCK_SCOPE : + BlockScope blockScope = (BlockScope) currentScope; - if (onlyStatic && !memberType.isStatic()) - continue next; + for (int j = 0, length = blockScope.subscopeCount; j < length; j++) { - if (typeLength > memberType.sourceName.length) - continue next; + if (blockScope.subscopes[j] instanceof ClassScope) { + SourceTypeBinding localType = + ((ClassScope) blockScope.subscopes[j]).referenceContext.binding; - if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName))) - continue next; + if (localType == exceptionType) { + isQualified = false; + break done; + } + } + } + break; - if (this.options.checkDeprecation && memberType.isViewedAsDeprecated()) continue next; + 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; + } + } + } - if (this.options.checkVisibility - && !memberType.canBeSeenBy(this.unitScope.fPackage)) - continue next; - char[] completionName = CharOperation.concat(memberType.sourceName, SEMICOLON); + break; - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + 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 (memberType.isClass()) { - relevance += computeRelevanceForClass(); - } else if(memberType.isEnum()) { - relevance += computeRelevanceForEnum(); - } else if (memberType.isInterface()) { - relevance += computeRelevanceForInterface(); + 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; } - this.noProposal = false; - if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { - createTypeProposal( - memberType, - memberType.qualifiedSourceName(), - IAccessRule.K_ACCESSIBLE, - completionName, - relevance, - null, - null, - null, - false); + + if (isQualified) { + completionName = + CharOperation.concat( + memberPackageName, + CharOperation.concat( + memberEnclosingTypeNames, + memberTypeName, + '.'), + '.'); } } - } - private void findImportsOfStaticFields(char[] fieldName, ReferenceBinding ref) { - FieldBinding[] fields = ref.availableFields(); + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForCaseMatching(typeName, exceptionType.sourceName); + relevance += computeRelevanceForExpectingType(exceptionType); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + if(!this.insideQualifiedReference) { + relevance += computeRelevanceForQualification(isQualified); + } + relevance += computeRelevanceForClass(); + relevance += computeRelevanceForException(); - int fieldLength = fieldName.length; - next : for (int m = fields.length; --m >= 0;) { - FieldBinding field = fields[m]; + 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) { - if (fieldLength > field.name.length) - continue next; + for (int i = 0; i <= this.expectedTypesPtr; i++) { + ReferenceBinding exceptionType = (ReferenceBinding)this.expectedTypes[i]; - if (field.isSynthetic()) - continue next; + findExceptionFromTryStatement(typeName, exceptionType, receiverType, invocationType, scope, typesFound, true); + } + } + private void findExplicitConstructors( + char[] name, + ReferenceBinding currentType, + MethodScope scope, + InvocationSite invocationSite) { - if (!field.isStatic()) - continue next; + ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration)scope.referenceContext; + MethodBinding enclosingConstructor = constructorDeclaration.binding; - if (!CharOperation.prefixEquals(fieldName, field.name, false/* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) - continue next; + // 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 (this.options.checkDeprecation && field.isViewedAsDeprecated()) continue next; + if (constructor.isSynthetic()) continue next; - if (this.options.checkVisibility - && !field.canBeSeenBy(this.unitScope.fPackage)) - continue next; + if (this.options.checkDeprecation && + constructor.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(constructor.declaringClass)) + continue next; - char[] completionName = CharOperation.concat(field.name, SEMICOLON); + if (this.options.checkVisibility + && !constructor.canBeSeenBy(invocationSite, scope)) continue next; - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForCaseMatching(fieldName, field.name); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + TypeBinding[] parameters = constructor.parameters; + int paramLength = parameters.length; - 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); + 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) { - private void findImportsOfStaticMethods(char[] methodName, ReferenceBinding ref) { - MethodBinding[] methods = ref.availableMethods(); + ObjectVector newFieldsFound = new ObjectVector(); + // Inherited fields 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 m = methods.length; --m >= 0;) { - MethodBinding method = methods[m]; + int fieldLength = fieldName.length; + next : for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; - if (method.isSynthetic()) continue next; + if (field.isSynthetic()) continue next; - if (method.isDefaultAbstract()) continue next; + if (onlyStaticFields && !field.isStatic()) continue next; - if (method.isConstructor()) continue next; + if (fieldLength > field.name.length) continue next; - if (!method.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 && method.isViewedAsDeprecated()) continue next; + if (this.options.checkDeprecation && + field.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(field.declaringClass)) + continue next; if (this.options.checkVisibility - && !method.canBeSeenBy(this.unitScope.fPackage)) continue next; + && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; - if (methodLength > method.selector.length) - continue next; + boolean prefixRequired = false; - if (!CharOperation.prefixEquals(methodName, method.selector, false/* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) - continue next; + 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; + } + } + } - int length = method.parameters.length; - char[][] parameterPackageNames = new char[length][]; - char[][] parameterTypeNames = new char[length][]; + for (int l = localsFound.size; --l >= 0;) { + LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l); - for (int i = 0; i < length; i++) { - TypeBinding type = method.original().parameters[i]; - parameterPackageNames[i] = type.qualifiedPackageName(); - parameterTypeNames[i] = type.qualifiedSourceName(); + 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; + } } - char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); - char[] completionName = CharOperation.concat(method.selector, SEMICOLON); + 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(); - relevance += computeRelevanceForCaseMatching(methodName, method.selector); + relevance += computeRelevanceForInterestingProposal(field); + if (fieldName != null) relevance += computeRelevanceForCaseMatching(fieldName, field.name); + relevance += computeRelevanceForExpectingType(field.type); + relevance += computeRelevanceForEnumConstant(field.type); + relevance += computeRelevanceForStatic(onlyStaticFields, field.isStatic()); + 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(!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); - } - } - } - } - - /* - * 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 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); + // 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); } - 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); + // 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(proposal); + this.printDebug(valueProposal); } } } - } - 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]); + } 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); @@ -5076,607 +5042,851 @@ } } } - } - - 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; - } + 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) { - if(canBeField) { - // transient - if((modifiers & ClassFileConstants.AccTransient) == 0) { - keywords[count++] = Keywords.TRANSIENT; - } + boolean notInJavadoc = this.assistNodeInJavadoc == 0; + if (fieldName == null && notInJavadoc) + return; - // volatile - if((modifiers & ClassFileConstants.AccVolatile) == 0) { - keywords[count++] = Keywords.VOLATILE; + 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; + } } } - if(canBeMethod) { - // native - if((modifiers & ClassFileConstants.AccNative) == 0) { - keywords[count++] = Keywords.NATIVE; - } + 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); - // strictfp - if((modifiers & ClassFileConstants.AccStrictfp) == 0) { - keywords[count++] = Keywords.STRICTFP; + 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); } - // synchronized - if((modifiers & ClassFileConstants.AccSynchronized) == 0) { - keywords[count++] = Keywords.SYNCHRONIZED; + 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; + } } } + } + } - if(canBeType) { - keywords[count++] = Keywords.CLASS; - keywords[count++] = Keywords.INTERFACE; + 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((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); + if (token == null) + return; - findKeywords(token, keywords, false, false); - } + if (receiverType.isBaseType()) + return; // nothing else is possible with base types - protected void findMembers( - char[] token, - ReferenceBinding receiverType, - Scope scope, - InvocationSite invocationSite, - boolean isInsideAnnotationAttribute, - Binding[] missingElements, - int[] missingElementsStarts, - int[] missingElementsEnds, - boolean missingElementsHaveProblems) { + 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 (!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); - } + if (receiverType.isArrayType()) { + if (proposeField + && token.length <= lengthField.length + && CharOperation.prefixEquals(token, lengthField, false /* ignore case */ + )) { - 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; - + 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 (!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 (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(); - if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { + 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, - receiverType, + (ReferenceBinding) receiverType, scope, + fieldsFound, new ObjectVector(), - new ObjectVector(), - true, - invocationSite, - scope, false, + invocationSite, + invocationScope, + implicitCall, false, missingElements, missingElementsStarts, missingElementsEnds, missingElementsHaveProblems, - null, - -1, - -1); + castedReceiver, + receiverStart, + receiverEnd); } - if (!isInsideAnnotationAttribute && !this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { + if(proposeMethod) { findMethods( token, null, null, - receiverType, + (ReferenceBinding) receiverType, scope, - new ObjectVector(), - true, + methodsFound, false, false, invocationSite, - scope, - false, - false, + invocationScope, + implicitCall, + superCall, false, missingElements, missingElementsStarts, missingElementsEnds, missingElementsHaveProblems, - null, - -1, - -1); + castedReceiver, + receiverStart, + receiverEnd); } } - 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); - } + 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) { - // 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) { + if (receiverType.resolvedType == null) return; - // 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; + TypeBinding receiverTypeBinding = receiverType.resolvedType; + char[] castedReceiver = null; - if (staticOnly && !memberType.isStatic()) continue next; + char[] castedTypeChars = CharOperation.concatWith(receiverType.getTypeName(), '.'); + if(this.source != null) { + int memberRefStart = this.startPosition; - if (isForbidden(memberType)) continue next; + char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd); + char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart); - if (typeLength > memberType.sourceName.length) - continue next; + 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 (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName))) - continue next; + if (castedReceiver == null) return; - if (this.options.checkDeprecation && - memberType.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(memberType)) - continue next; + int oldStartPosition = this.startPosition; + this.startPosition = receiverStart; - if (this.options.checkVisibility) { - if (invocationType != null && !memberType.canBeSeenBy(receiverType, invocationType)) { - continue next; - } else if(invocationType == null && !memberType.canBeSeenBy(this.unitScope.fPackage)) { - continue next; - } - } + findFieldsAndMethods( + token, + receiverTypeBinding, + scope, + fieldsFound, + methodsFound, + invocationSite, + invocationScope, + implicitCall, + superCall, + missingElements, + missingElementsStarts, + missingElementsEnds, + missingElementsHaveProblems, + castedReceiver, + receiverStart, + receiverEnd); - if (this.insideQualifiedReference && - receiverType.isParameterizedType() && - memberType.isStatic()) { - continue next; - } + this.startPosition = oldStartPosition; + } + private void findFieldsAndMethodsFromCastedReceiver( + ASTNode enclosingNode, + Binding qualifiedBinding, + Scope scope, + ObjectVector fieldsFound, + ObjectVector methodsFound, + InvocationSite invocationSite, + Scope invocationScope, + Expression receiver) { - for (int i = typesFound.size; --i >= 0;) { - ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i); + if (enclosingNode == null || !(enclosingNode instanceof IfStatement)) return; - if (memberType == otherType) - continue next; + IfStatement ifStatement = (IfStatement)enclosingNode; - if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) { + if (!(ifStatement.condition instanceof InstanceOfExpression)) return; - if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType())) - continue next; + InstanceOfExpression instanceOfExpression = (InstanceOfExpression) ifStatement.condition; - if (otherType.enclosingType().isInterface()) - if (memberType.enclosingType() - .implementsInterface(otherType.enclosingType(), true)) - continue next; + TypeReference instanceOfType = instanceOfExpression.type; - if (memberType.enclosingType().isInterface()) - if (otherType.enclosingType() - .implementsInterface(memberType.enclosingType(), true)) - continue next; - } + 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; } - typesFound.add(memberType); + // if (this.field instanceof X) field.| + if (instanceOfExpression.expression instanceof FieldReference) { + FieldReference fieldReference = (FieldReference)instanceOfExpression.expression; - if(!this.insideQualifiedReference) { - if(this.assistNodeIsClass) { - 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; + if (fieldReference.receiver instanceof ThisReference && + qualifiedBinding instanceof FieldBinding && + fieldReference.binding == qualifiedBinding) { + findFromAnotherReceiver = true; } } + } else if (receiver instanceof FieldReference) { + FieldReference fieldReference1 = (FieldReference) receiver; - char[] completionName = memberType.sourceName(); + receiverStart = fieldReference1.sourceStart; + receiverEnd = fieldReference1.sourceEnd + 1; - 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, - '.'), - '.'); + 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; } - } - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - 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 (this.field instanceof X) this.field.| + if (instanceOfExpression.expression instanceof FieldReference) { + FieldReference fieldReference2 = (FieldReference)instanceOfExpression.expression; - 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 (fieldReference2.receiver instanceof ThisReference && + fieldReference2.binding == fieldReference1.binding) { + findFromAnotherReceiver = true; + } + } } + } - if (missingElements != null) { - relevance += computeRelevanceForMissingElements(missingElementsHaveProblems); - } + if (findFromAnotherReceiver) { + TypeBinding receiverTypeBinding = instanceOfType.resolvedType; + char[] castedReceiver = null; - this.noProposal = false; - createTypeProposal( - memberType, - memberType.qualifiedSourceName(), - IAccessRule.K_ACCESSIBLE, - completionName, - relevance, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems); - } - } + char[] castedTypeChars = CharOperation.concatWith(instanceOfType.getTypeName(), '.'); + if(this.source != null) { + int memberRefStart = this.startPosition; - 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); - } - 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) { + char[] receiverChars = CharOperation.subarray(this.source, receiverStart, receiverEnd); + char[] dotChars = CharOperation.subarray(this.source, receiverEnd, memberRefStart); - ReferenceBinding currentType = receiverType; - if (typeName == null) - return; + 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 (this.insideQualifiedReference - || typeName.length == 0) { // do not search up the hierarchy + if (castedReceiver == null) return; - findMemberTypes( - typeName, - currentType.memberTypes(), - typesFound, - receiverType, - typeInvocation, - staticOnly, - staticFieldsAndMethodOnly, - fromStaticImport, - checkQualification, - scope, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems); - return; - } + int oldStartPosition = this.startPosition; + this.startPosition = receiverStart; - ReferenceBinding[] interfacesToVisit = null; - int nextPosition = 0; + findFieldsAndMethods( + this.completionToken, + receiverTypeBinding, + scope, + fieldsFound, + methodsFound, + invocationSite, + invocationScope, + false, + false, + null, + null, + null, + false, + castedReceiver, + receiverStart, + receiverEnd); - 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; - } - } - } + this.startPosition = oldStartPosition; + } + } + private void findFieldsAndMethodsFromFavorites( + char[] token, + Scope scope, + InvocationSite invocationSite, + Scope invocationScope, + ObjectVector localsFound, + ObjectVector fieldsFound, + ObjectVector methodsFound) { - findMemberTypes( - typeName, - currentType.memberTypes(), - typesFound, - receiverType, - typeInvocation, - staticOnly, - staticFieldsAndMethodOnly, - fromStaticImport, - checkQualification, - scope, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems); + ObjectVector methodsFoundFromFavorites = new ObjectVector(); - currentType = currentType.superclass(); - } while (currentType != null); + ImportBinding[] favoriteBindings = getFavoriteReferenceBindings(invocationScope); - 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 (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; } } } - 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); + methodsFound.addAll(methodsFoundFromFavorites); + } - 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; + private boolean findFieldsAndMethodsFromMissingFieldType( + char[] token, + Scope scope, + InvocationSite invocationSite, + boolean insideTypeAnnotation) { + + boolean foundSomeFields = false; + + boolean staticsOnly = false; + Scope currentScope = scope; + + done : 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(!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; + } + } } - } + staticsOnly |= enclosingType.isStatic(); + insideTypeAnnotation = false; + break; + case Scope.COMPILATION_UNIT_SCOPE : + break done; } + currentScope = currentScope.parent; } + return foundSomeFields; } - 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); + private void findFieldsAndMethodsFromMissingReturnType( + char[] token, + TypeBinding[] arguments, + Scope scope, + InvocationSite invocationSite, + boolean insideTypeAnnotation) { + + boolean staticsOnly = false; + Scope currentScope = scope; + + done : 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(!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; + } + } + } + + } + } } - } - }; - SingleTypeReference typeRef = new SingleTypeReference(typeName, pos); - typeRef.resolvedType = new ProblemReferenceBinding(new char[][]{ typeName }, null, ProblemReasons.NotFound); - missingTypesConverter.guess(typeRef, scope, substitutionRequestor); + staticsOnly |= enclosingType.isStatic(); + insideTypeAnnotation = false; + break; + case Scope.COMPILATION_UNIT_SCOPE : + break done; + } + currentScope = currentScope.parent; + } } - private void findMemberTypesFromMissingType( + private void findFieldsAndMethodsFromMissingType( TypeReference typeRef, - final long pos, - final Scope scope) { + final Scope scope, + final InvocationSite invocationSite, + final Scope invocationScope) { MissingTypesGuesser missingTypesConverter = new MissingTypesGuesser(this); MissingTypesGuesser.GuessedTypeRequestor substitutionRequestor = new MissingTypesGuesser.GuessedTypeRequestor() { @@ -5686,211 +5896,296 @@ 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); - } + 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); } - /* - * 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') : 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); - } + 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)) { + + findLocalMethodsFromStaticImports( + methodBinding.selector, + methodBinding.declaringClass.methods(), + scope, + exactMatch, + methodsFound, + methodBinding.declaringClass, + invocationSite); + } + } + } + } } } } } - private void findSubMemberTypes( - char[] typeName, - ReferenceBinding receiverType, - Scope scope, - SourceTypeBinding typeInvocation, - boolean staticOnly, - boolean staticFieldsAndMethodOnly, - boolean fromStaticImport, - ObjectVector typesFound) { + private void findFieldsFromFavorites( + char[] fieldName, + FieldBinding[] fields, + Scope scope, + ObjectVector fieldsFound, + ObjectVector localsFound, + ReferenceBinding receiverType, + InvocationSite invocationSite, + Scope invocationScope) { - ReferenceBinding currentType = receiverType; - if (typeName == null || typeName.length == 0) - return; + char[] typeName = CharOperation.concatWith(receiverType.compoundName, '.'); - if (this.assistNodeIsSuperType && !this.insideQualifiedReference && isForbidden(currentType)) return; // we're trying to find a supertype + int fieldLength = fieldName.length; + next : for (int f = fields.length; --f >= 0;) { + FieldBinding field = fields[f]; - findMemberTypes( - typeName, - currentType.memberTypes(), - typesFound, - receiverType, - typeInvocation, - staticOnly, - staticFieldsAndMethodOnly, - fromStaticImport, - true, - scope, - null, - null, - null, - false); + if (field.isSynthetic()) continue next; - 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); - } - } + // only static fields must be proposed + if (!field.isStatic()) continue next; - private void findInterfacesMethods( - char[] selector, - TypeBinding[] typeArgTypes, - TypeBinding[] argTypes, - ReferenceBinding receiverType, - ReferenceBinding[] itsInterfaces, - Scope scope, - ObjectVector methodsFound, - boolean onlyStaticMethods, - boolean exactMatch, - boolean isCompletingDeclaration, - 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 (fieldLength > field.name.length) continue next; - if (selector == null) - return; + if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) continue next; - if (itsInterfaces != Binding.NO_SUPERINTERFACES) { - ReferenceBinding[] interfacesToVisit = itsInterfaces; - int nextPosition = interfacesToVisit.length; + if (this.options.checkDeprecation && + field.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(field.declaringClass)) + continue next; - for (int i = 0; i < nextPosition; i++) { - ReferenceBinding currentType = interfacesToVisit[i]; - MethodBinding[] methods = currentType.availableMethods(); - if(methods != null) { - if(isCompletingDeclaration) { - findLocalMethodDeclarations( - selector, - methods, - scope, - methodsFound, - exactMatch, - receiverType); - } else { - findLocalMethods( - selector, - typeArgTypes, - argTypes, - methods, - scope, - methodsFound, - onlyStaticMethods, - exactMatch, - receiverType, - invocationSite, - invocationScope, - implicitCall, - superCall, - canBePrefixed, - missingElements, - missingElementssStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); - } - } + if (this.options.checkVisibility + && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; - 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; - } - } + for (int i = fieldsFound.size; --i >= 0;) { + Object[] other = (Object[])fieldsFound.elementAt(i); + FieldBinding otherField = (FieldBinding) other[0]; + + if (field == otherField) continue next; } - } - } - private void findImplicitMessageSends( - char[] token, - TypeBinding[] argTypes, - Scope scope, - InvocationSite invocationSite, - Scope invocationScope, - ObjectVector methodsFound) { + fieldsFound.add(new Object[]{field, receiverType}); - if (token == null) - return; + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(field); + if (fieldName != null) 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) @@ -5917,7 +6212,6 @@ methodsFound, staticsOnly, true, - false, invocationSite, invocationScope, true, @@ -5939,137 +6233,188 @@ scope = scope.parent; } } + private void findImports(CompletionOnImportReference importReference, boolean findMembers) { + char[][] tokens = importReference.tokens; - // 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) { + char[] importName = CharOperation.concatWith(tokens, '.'); - ObjectVector newMethodsFound = new ObjectVector(); - // Inherited methods which are hidden by subclasses are filtered out - // No visibility checks can be performed without the scope & invocationSite + if (importName.length == 0) + return; - int methodLength = methodName.length; - int minTypeArgLength = typeArgTypes == null ? 0 : typeArgTypes.length; - int minArgLength = argTypes == null ? 0 : argTypes.length; + char[] lastToken = tokens[tokens.length - 1]; + if(lastToken != null && lastToken.length == 0) + importName = CharOperation.concat(importName, new char[]{'.'}); - next : for (int f = methods.length; --f >= 0;) { - MethodBinding method = methods[f]; + this.resolvingImports = true; + this.resolvingStaticImports = importReference.isStatic(); - if (method.isSynthetic()) continue next; + this.completionToken = lastToken; + this.qualifiedCompletionToken = importName; - if (method.isDefaultAbstract()) continue next; + // 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); + acceptTypes(null); + } + } - if (method.isConstructor()) continue next; + private void findImportsOfMemberTypes(char[] typeName, ReferenceBinding ref, boolean onlyStatic) { + ReferenceBinding[] memberTypes = ref.memberTypes(); - if (this.options.checkDeprecation && - method.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(method.declaringClass)) + 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; - //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 (typeLength > memberType.sourceName.length) + continue next; - if (onlyStaticMethods && !method.isStatic()) continue next; + if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName))) + continue next; - if (this.options.checkVisibility - && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next; + if (this.options.checkDeprecation && memberType.isViewedAsDeprecated()) continue next; - if(superCall && method.isAbstract()) { - methodsFound.add(new Object[]{method, receiverType}); + if (this.options.checkVisibility + && !memberType.canBeSeenBy(this.unitScope.fPackage)) 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; - } - } + char[] completionName = CharOperation.concat(memberType.sourceName, SEMICOLON); - if (minTypeArgLength != 0 && minTypeArgLength != method.typeVariables.length) - continue next; + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - if (minTypeArgLength != 0) { - method = scope.environment().createParameterizedGenericMethod(method, typeArgTypes); + 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); } + } + } - if (minArgLength > method.parameters.length) + 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; - 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; - } - } - } + if (field.isSynthetic()) + continue next; - boolean prefixRequired = false; + if (!field.isStatic()) + 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.prefixEquals(fieldName, field.name, false/* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(fieldName, field.name))) + 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 (this.options.checkDeprecation && field.isViewedAsDeprecated()) continue next; - if(!superCall) { - if(!canBePrefixed) continue next; + if (this.options.checkVisibility + && !field.canBeSeenBy(this.unitScope.fPackage)) + continue next; - prefixRequired = true; - } - } - } - } - } + char[] completionName = CharOperation.concat(field.name, SEMICOLON); - newMethodsFound.add(new Object[]{method, receiverType}); + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForCaseMatching(fieldName, field.name); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - 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]; - } + 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][]; @@ -6082,647 +6427,552 @@ } 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; t0) 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; p0) 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,'.'); - } - } + char[] completionName = CharOperation.concat(method.selector, SEMICOLON); int relevance = computeBaseRelevance(); relevance += computeRelevanceForResolution(); relevance += computeRelevanceForInterestingProposal(); - if (methodName != null) relevance += computeRelevanceForCaseMatching(methodName, method.selector); - relevance += computeRelevanceForExpectingType(method.returnType); - relevance += computeRelevanceForEnumConstant(method.returnType); - relevance += computeRelevanceForStatic(onlyStaticMethods, method.isStatic()); - relevance += computeRelevanceForQualification(prefixRequired); + relevance += computeRelevanceForCaseMatching(methodName, method.selector); 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); - } + 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); } } - this.startPosition = previousStartPosition; - this.tokenStart = previousTokenStart; } - - methodsFound.addAll(newMethodsFound); } + + private void findInterfacesMethodDeclarations( + char[] selector, + ReferenceBinding receiverType, + ReferenceBinding[] itsInterfaces, + Scope scope, + ObjectVector methodsFound, + Binding[] missingElements, + int[] missingElementssStarts, + int[] missingElementsEnds, + boolean missingElementsHaveProblems) { - 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 (selector == null) + return; - if (methodLength > method.selector.length) continue next; + if (itsInterfaces != Binding.NO_SUPERINTERFACES) { + ReferenceBinding[] interfacesToVisit = itsInterfaces; + int nextPosition = interfacesToVisit.length; - if (!CharOperation.prefixEquals(methodName, method.selector, false /* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) { - continue next; + 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); } - 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; - } + 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) { - for (int i = methodsFound.size; --i >= 0;) { - Object[] other = (Object[]) methodsFound.elementAt(i); - MethodBinding otherMethod = (MethodBinding) other[0]; + if (selector == null) + return; - if (method == otherMethod) continue next; + if (itsInterfaces != Binding.NO_SUPERINTERFACES) { + ReferenceBinding[] interfacesToVisit = itsInterfaces; + int nextPosition = interfacesToVisit.length; - if (CharOperation.equals(method.selector, otherMethod.selector, true)) { - if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) { - continue next; - } - } + 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); } - 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; - } - } + 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; } } - - 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]; - } - } + } + } + } + /* + * 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 this.endPosition - && this.source[this.endPosition] == '(') { - completion = method.selector; - } else { - completion = CharOperation.concat(method.selector, new char[] { '(', ')' }); - } + if (missingParams == null) return; - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - if (methodName != null) 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); + // Get relevance + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for param name + if (!isTypeParam) relevance += R_INTERESTING; - CompilationUnitDeclaration cu = this.unitScope.referenceContext; - int importStart = cu.types[0].declarationSourceStart; - int importEnd = importStart; + // Propose missing param + int length = missingParams.length; + relevance += length; + for (int i=0; i') : 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); + } + } + } + } + } - 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); + // 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; - 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, '.'); + 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; - 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); + 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); - 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); + } + } + private void findKeywordsForMember(char[] token, int modifiers) { + char[][] keywords = new char[Keywords.COUNT][]; + int count = 0; - proposal.setRequiredProposals(new CompletionProposal[]{methodImportProposal}); + // 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; + } + } - this.requestor.accept(proposal); - if(DEBUG) { - this.printDebug(proposal); - } - } + 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; } - this.startPosition = previousStartPosition; - this.tokenStart = previousTokenStart; + // volatile + if((modifiers & ClassFileConstants.AccVolatile) == 0) { + keywords[count++] = Keywords.VOLATILE; + } } - } - private CompletionProposal createRequiredTypeProposal(Binding binding, int start, int end, int relevance) { - InternalCompletionProposal proposal = null; - if (binding instanceof ReferenceBinding) { - ReferenceBinding typeBinding = (ReferenceBinding) binding; + if(canBeMethod) { + // native + if((modifiers & ClassFileConstants.AccNative) == 0) { + keywords[count++] = Keywords.NATIVE; + } - char[] packageName = typeBinding.qualifiedPackageName(); - char[] typeName = typeBinding.qualifiedSourceName(); - char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.'); + // strictfp + if((modifiers & ClassFileConstants.AccStrictfp) == 0) { + keywords[count++] = Keywords.STRICTFP; + } - 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; + // synchronized + if((modifiers & ClassFileConstants.AccSynchronized) == 0) { + keywords[count++] = Keywords.SYNCHRONIZED; + } + } - char[] packageName = CharOperation.concatWith(packageBinding.compoundName, '.'); + if(canBeType) { + keywords[count++] = Keywords.CLASS; + keywords[count++] = Keywords.INTERFACE; - 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); + if((modifiers & ClassFileConstants.AccFinal) == 0) { + keywords[count++] = Keywords.ENUM; + } + } + } else { + // class + keywords[count++] = Keywords.CLASS; + keywords[count++] = Keywords.INTERFACE; } - return proposal; + 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; - // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean) - private void findLocalMethodsFromStaticImports( + 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, - boolean exactMatch, ObjectVector methodsFound, - ReferenceBinding receiverType, - InvocationSite invocationSite) { + // 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; + MethodBinding method = methods[f]; + if (method.isSynthetic()) continue next; - if (method.isDefaultAbstract()) continue next; + if (method.isDefaultAbstract()) continue next; if (method.isConstructor()) continue next; - if (!method.isStatic()) continue next; + if (method.isFinal()) { + newMethodsFound.add(method); + 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; + // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next; + if(method.isStatic()) continue next; - if (!CharOperation.equals(methodName, method.selector, false /* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) - 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;) { - Object[] other = (Object[]) methodsFound.elementAt(i); - MethodBinding otherMethod = (MethodBinding) other[0]; - ReferenceBinding otherReceiverType = (ReferenceBinding) other[1]; - if (method == otherMethod && receiverType == otherReceiverType) + MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i); + if (method == otherMethod) continue next; - if (CharOperation.equals(method.selector, otherMethod.selector, true)) { - if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) { - continue next; - } + if (CharOperation.equals(method.selector, otherMethod.selector, true) + && this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) { + continue next; } } - newMethodsFound.add(new Object[]{method, receiverType}); + newMethodsFound.add(method); int length = method.parameters.length; char[][] parameterPackageNames = new char[length][]; - char[][] parameterTypeNames = new char[length][]; + char[][] parameterFullTypeNames = new char[length][]; for (int i = 0; i < length; i++) { - TypeBinding type = method.original().parameters[i]; + TypeBinding type = method.parameters[i]; parameterPackageNames[i] = type.qualifiedPackageName(); - parameterTypeNames[i] = type.qualifiedSourceName(); + parameterFullTypeNames[i] = type.qualifiedSourceName(); } - char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); - - char[] completion = CharOperation.NO_CHAR; - int previousStartPosition = this.startPosition; - int previousTokenStart = this.tokenStart; + char[][] parameterNames = findMethodParameterNames(method, parameterFullTypeNames); - 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; + 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 += computeRelevanceForExpectingType(method.returnType); - relevance += computeRelevanceForEnumConstant(method.returnType); - relevance += computeRelevanceForStatic(true, method.isStatic()); - relevance += computeRelevanceForQualification(false); + 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_REF)) { - InternalCompletionProposal proposal = createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition); + 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(parameterTypeNames); + proposal.setParameterTypeNames(parameterFullTypeNames); proposal.setPackageName(method.returnType.qualifiedPackageName()); proposal.setTypeName(method.returnType.qualifiedSourceName()); + proposal.setCompletion(completion.toString().toCharArray()); 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); @@ -6733,3290 +6983,3307 @@ this.printDebug(proposal); } } - this.startPosition = previousStartPosition; - this.tokenStart = previousTokenStart; } - methodsFound.addAll(newMethodsFound); } - 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 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; - } - private int computeRelevanceForClass(){ - if(this.assistNodeIsClass) { - return R_CLASS; - } - return 0; - } - private int computeRelevanceForEnum(){ - if(this.assistNodeIsEnum) { - return R_ENUM; - } - return 0; - } - 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 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 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; - } + // 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) { - } - } - return 0; - } - private int computeRelevanceForException(){ - if (this.assistNodeIsException) { - return R_EXCEPTION; - } - return 0; - } - private int computeRelevanceForException(char[] proposalName){ + ObjectVector newMethodsFound = new ObjectVector(); + // Inherited methods which are hidden by subclasses are filtered out + // No visibility checks can be performed without the scope & invocationSite - 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(TypeBinding proposalType){ - if(this.expectedTypes != null && proposalType != null) { - int relevance = 0; - for (int i = 0; i <= this.expectedTypesPtr; i++) { - if((this.expectedTypesFilter & SUBTYPE) != 0 - && proposalType.isCompatibleWith(this.expectedTypes[i])) { + int methodLength = methodName.length; + int minTypeArgLength = typeArgTypes == null ? 0 : typeArgTypes.length; + int minArgLength = argTypes == null ? 0 : argTypes.length; - if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) && - CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) { - return R_EXACT_EXPECTED_TYPE; - } + next : for (int f = methods.length; --f >= 0;) { + MethodBinding method = methods[f]; - relevance = R_EXPECTED_TYPE; - } - if((this.expectedTypesFilter & SUPERTYPE) != 0 - && this.expectedTypes[i].isCompatibleWith(proposalType)) { + if (method.isSynthetic()) continue next; - if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) && - CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) { - return R_EXACT_EXPECTED_TYPE; - } + if (method.isDefaultAbstract()) continue next; - relevance = R_EXPECTED_TYPE; - } + 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; } - return relevance; - } - 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 (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(this.hasJavaLangObjectAsExpectedType) { - return R_EXPECTED_TYPE; + + if (minTypeArgLength != 0 && minTypeArgLength != method.typeVariables.length) + continue next; + + if (minTypeArgLength != 0) { + method = scope.environment().createParameterizedGenericMethod(method, typeArgTypes); } - } - return 0; - } - private int computeRelevanceForInheritance(ReferenceBinding receiverType, ReferenceBinding declaringClass) { - if (receiverType == declaringClass) return R_NON_INHERITED; - return 0; - } + if (minArgLength > method.parameters.length) + continue next; - 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; - } - } - } - return R_INTERESTING; - } - private void computeUninterestingBindings(ASTNode parent, Scope scope){ - if(parent instanceof LocalDeclaration) { - addUninterestingBindings(((LocalDeclaration)parent).binding); - } else if (parent instanceof FieldDeclaration) { - addUninterestingBindings(((FieldDeclaration)parent).binding); - } - } - - 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); + 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; } } } - } - } - - // 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; + boolean prefixRequired = false; - if (exactMatch) { - if (!CharOperation.equals(methodName, method.selector, false /* ignore case */ - )) + 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; - } else { + 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 (methodLength > method.selector.length) - continue next; + if(!superCall) { + if(!canBePrefixed) continue next; - if (!CharOperation.prefixEquals(methodName, method.selector, false/* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) - continue next; + prefixRequired = true; + } + } + } + } } - for (int i = methodsFound.size; --i >= 0;) { - MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i); - if (method == otherMethod) - continue next; + newMethodsFound.add(new Object[]{method, receiverType}); - if (CharOperation.equals(method.selector, otherMethod.selector, true) - && this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) { - continue next; + 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]; + } } } - newMethodsFound.add(method); - int length = method.parameters.length; char[][] parameterPackageNames = new char[length][]; - char[][] parameterFullTypeNames = new char[length][]; + char[][] parameterTypeNames = new char[length][]; for (int i = 0; i < length; i++) { - TypeBinding type = method.parameters[i]; + TypeBinding type = method.original().parameters[i]; parameterPackageNames[i] = type.qualifiedPackageName(); - parameterFullTypeNames[i] = type.qualifiedSourceName(); + parameterTypeNames[i] = type.qualifiedSourceName(); } + char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); - char[][] parameterNames = findMethodParameterNames(method, parameterFullTypeNames); + char[] completion = CharOperation.NO_CHAR; - 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()); + 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; t0) 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; p0) 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[] { '(', ')' }); - StringBuffer completion = new StringBuffer(10); - if (!exactMatch) { - createMethod(method, parameterPackageNames, parameterFullTypeNames, parameterNames, scope, completion); + 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 += R_METHOD_OVERIDE; - if(method.isAbstract()) relevance += R_ABSTRACT_METHOD; + if (methodName != null) 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(!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)); + + 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); + } } - 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); + + // 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) { - private void createTypeVariable(TypeVariableBinding typeVariable, Scope scope, StringBuffer completion) { - completion.append(typeVariable.sourceName); + char[] typeName = CharOperation.concatWith(receiverType.compoundName, '.'); - 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); - } - } - } + int methodLength = methodName.length; - 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) { + next : for (int f = methods.length; --f >= 0;) { + MethodBinding method = methods[f]; - int length = wildcardBinding.otherBounds.length; - for (int i = 0; i < length; i++) { - completion.append(' '); - completion.append('&'); - completion.append(' '); - createType(wildcardBinding.otherBounds[i], scope, completion); - } + 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; } - 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(']'); + + 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; + } + } } - 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; - } - } - - 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 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 + boolean proposeStaticImport = !(this.compilerOptions.complianceLevel < ClassFileConstants.JDK1_5) && + this.options.suggestStaticImport; - 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(' '); + 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; + } + } + } } - createTypeVariable(typeVariableBindings[i], scope, completion); - } - completion.append('>'); - completion.append(' '); - } - //// Return type - createType(method.returnType, scope, completion); - completion.append(' '); + methodsFoundFromFavorites.add(new Object[]{method, receiverType}); - //// Selector - completion.append(method.selector); + 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]; + } + } + } - completion.append('('); + int length = method.parameters.length; + char[][] parameterPackageNames = new char[length][]; + char[][] parameterTypeNames = new char[length][]; - ////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('%'); - } - } + 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); - completion.append(')'); + char[] completion = CharOperation.NO_CHAR; - //// Exceptions - ReferenceBinding[] exceptions = method.thrownExceptions; + int previousStartPosition = this.startPosition; + int previousTokenStart = this.tokenStart; - 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(','); + if (this.source != null + && this.source.length > this.endPosition + && this.source[this.endPosition] == '(') { + completion = method.selector; + } else { + completion = CharOperation.concat(method.selector, new char[] { '(', ')' }); } - createType(exceptions[i], scope, completion); - } - } - } - private boolean isIgnored(int kind, boolean missingTypes) { - return this.requestor.isIgnored(kind) || - (missingTypes && !this.requestor.isAllowingRequiredProposals(kind, CompletionProposal.TYPE_REF)); - } + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + if (methodName != null) 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); - private boolean isIgnored(int kind) { - return this.requestor.isIgnored(kind); - } + CompilationUnitDeclaration cu = this.unitScope.referenceContext; + int importStart = cu.types[0].declarationSourceStart; + int importEnd = importStart; - private boolean isIgnored(int kind, int requiredProposalKind) { - return this.requestor.isIgnored(kind) || - !this.requestor.isAllowingRequiredProposals(kind, requiredProposalKind); - } + this.noProposal = false; - private void findMethods( - char[] selector, - TypeBinding[] typeArgTypes, - TypeBinding[] argTypes, - ReferenceBinding receiverType, - Scope scope, - ObjectVector methodsFound, - boolean onlyStaticMethods, - boolean exactMatch, - boolean isCompletingDeclaration, - InvocationSite invocationSite, - Scope invocationScope, - boolean implicitCall, - boolean superCall, - boolean canBePrefixed, - Binding[] missingElements, - int[] missingElementsStarts, - int[] missingElementsEnds, - boolean missingElementsHaveProblems, - char[] castedReceiver, - int receiverStart, - int receiverEnd) { + if (!proposeStaticImport) { + if (isAlreadyImported) { + if (!isIgnored(CompletionProposal.METHOD_REF)) { + completion = CharOperation.concat(receiverType.sourceName, completion, '.'); - boolean notInJavadoc = this.assistNodeInJavadoc == 0; - if (selector == null && notInJavadoc) { - return; - } + 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); - if(isCompletingDeclaration) { - MethodBinding[] methods = receiverType.availableMethods(); - if (methods != null){ - for (int i = 0; i < methods.length; i++) { - if(!methods[i].isDefaultAbstract()) { - methodsFound.add(methods[i]); - } - } - } - } + 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, '.'); - ReferenceBinding currentType = receiverType; - if (notInJavadoc) { - if (receiverType.isInterface()) { - if (isCompletingDeclaration) { - findInterfacesMethods( - selector, - typeArgTypes, - argTypes, - receiverType, - currentType.superInterfaces(), - scope, - methodsFound, - onlyStaticMethods, - exactMatch, - isCompletingDeclaration, - invocationSite, - invocationScope, - implicitCall, - superCall, - canBePrefixed, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); - } else { - findInterfacesMethods( - selector, - typeArgTypes, - argTypes, - receiverType, - new ReferenceBinding[]{currentType}, - scope, - methodsFound, - onlyStaticMethods, - exactMatch, - isCompletingDeclaration, - invocationSite, - invocationScope, - implicitCall, - superCall, - canBePrefixed, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); - } - - currentType = scope.getJavaLangObject(); - } else { - if (isCompletingDeclaration){ - findInterfacesMethods( - selector, - typeArgTypes, - argTypes, - receiverType, - currentType.superInterfaces(), - scope, - methodsFound, - onlyStaticMethods, - exactMatch, - isCompletingDeclaration, - invocationSite, - invocationScope, - implicitCall, - superCall, - canBePrefixed, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); + 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); - currentType = receiverType.superclass(); - } - } - } - boolean hasPotentialDefaultAbstractMethods = true; - while (currentType != null) { + char[] typeImportCompletion = createImportCharArray(typeName, false, false); - MethodBinding[] methods = currentType.availableMethods(); - if (methods != null) { - if (isCompletingDeclaration){ - findLocalMethodDeclarations( - selector, - methods, - scope, - methodsFound, - exactMatch, - receiverType); - } else{ - findLocalMethods( - selector, - typeArgTypes, - argTypes, - methods, - scope, - methodsFound, - onlyStaticMethods, - exactMatch, - receiverType, - invocationSite, - invocationScope, - implicitCall, - superCall, - canBePrefixed, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); - } - } + 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); - if (hasPotentialDefaultAbstractMethods && - (currentType.isAbstract() || - currentType.isTypeVariable() || - currentType.isIntersectionType() || - currentType.isEnum())){ + proposal.setRequiredProposals(new CompletionProposal[]{typeImportProposal}); - 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()); + this.requestor.accept(proposal); + if(DEBUG) { + this.printDebug(proposal); + } } - } - - findInterfacesMethods( - selector, - typeArgTypes, - argTypes, - receiverType, - superInterfaces, - scope, - methodsFound, - onlyStaticMethods, - exactMatch, - isCompletingDeclaration, - invocationSite, - invocationScope, - implicitCall, - superCall, - canBePrefixed, - missingElements, - missingElementsStarts, - missingElementsEnds, - missingElementsHaveProblems, - castedReceiver, - receiverStart, - receiverEnd); - } 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; + } 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); - if (sourceType.scope != null){ - TypeDeclaration parsedType; + char[] methodImportCompletion = createImportCharArray(CharOperation.concat(typeName, method.selector, '.'), true, false); - if ((parsedType = sourceType.scope.referenceContext) != null){ - AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method.original()); + 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); - if (methodDecl != null){ - Argument[] arguments = methodDecl.arguments; - parameterNames = new char[length][]; + proposal.setRequiredProposals(new CompletionProposal[]{methodImportProposal}); - for(int i = 0 ; i < length ; i++){ - parameterNames[i] = arguments[i].name; + this.requestor.accept(proposal); + if(DEBUG) { + this.printDebug(proposal); } } } + + this.startPosition = previousStartPosition; + this.tokenStart = previousTokenStart; } } - // look into the model - if(parameterNames == null){ - ReferenceBinding bindingType = (ReferenceBinding)erasure; + // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean) + private void findLocalMethodsFromStaticImports( + char[] methodName, + MethodBinding[] methods, + Scope scope, + boolean exactMatch, + ObjectVector methodsFound, + ReferenceBinding receiverType, + InvocationSite invocationSite) { - char[] compoundName = CharOperation.concatWith(bindingType.compoundName, '.'); - Object type = this.typeCache.get(compoundName); + ObjectVector newMethodsFound = new ObjectVector(); - 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 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 f = methods.length; --f >= 0;) { + MethodBinding method = methods[f]; - next : for (int i = 0, length = blockScope.subscopeCount; i < length; i++) { + if (method.isSynthetic()) continue next; - if (blockScope.subscopes[i] instanceof ClassScope) { - SourceTypeBinding localType = - ((ClassScope) blockScope.subscopes[i]).referenceContext.binding; + if (method.isDefaultAbstract()) continue next; - if (!localType.isAnonymousType()) { - if (isForbidden(localType)) - continue next; + if (method.isConstructor()) 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; + if (!method.isStatic()) continue next; - for (int j = typesFound.size; --j >= 0;) { - ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j); + if (this.options.checkDeprecation && + method.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(method.declaringClass)) + continue next; - if (localType == otherType) - continue next; - } + if (this.options.checkVisibility + && !method.canBeSeenBy(receiverType, invocationSite, scope)) 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; - } + if (!CharOperation.equals(methodName, method.selector, false /* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(methodName, method.selector))) + continue next; - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - 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); + 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; - 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 (CharOperation.equals(method.selector, otherMethod.selector, true)) { + if (this.lookupEnvironment.methodVerifier().isMethodSubsignature(otherMethod, method)) { + continue next; } - 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) { + newMethodsFound.add(new Object[]{method, receiverType}); - this.completionToken = CharOperation.concatWith(packageStatement.tokens, '.'); - if (this.completionToken.length == 0) - return; + int length = method.parameters.length; + char[][] parameterPackageNames = new char[length][]; + char[][] parameterTypeNames = new char[length][]; - 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); - } + 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); - 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; + char[] completion = CharOperation.NO_CHAR; - 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 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(refBinding.sourceName, refBinding.sourceName); - relevance += computeRelevanceForExpectingType(refBinding); + relevance += computeRelevanceForCaseMatching(methodName, method.selector); + relevance += computeRelevanceForExpectingType(method.returnType); + relevance += computeRelevanceForEnumConstant(method.returnType); + relevance += computeRelevanceForStatic(true, method.isStatic()); 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 findTypeParameters(char[] token, Scope scope) { - if (this.compilerOptions.sourceLevel < ClassFileConstants.JDK1_5) return; + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); - 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); - } + 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); } } - scope = scope.parent; + this.startPosition = previousStartPosition; + this.tokenStart = previousTokenStart; } + + methodsFound.addAll(newMethodsFound); } - private void findTypesAndPackages(char[] token, Scope scope, boolean proposeBaseTypes, boolean proposeVoidType, ObjectVector typesFound) { - if (token == null) - return; + 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) { - // do not propose type if completion token is empty - boolean skip = false; - if (token.length == 0 && NO_TYPE_COMPLETION_ON_EMPTY_TOKEN) { - if(!this.assistNodeIsConstructor && (this.assistNodeInJavadoc & CompletionOnJavadoc.EXCEPTION) == 0) { - return; - } - skip = true; + if (!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { + findMemberTypes( + token, + receiverType, + scope, + scope.enclosingSourceType(), + false, + true, + new ObjectVector(), + missingElements, + missingElementsStarts, + missingElementsEnds, + missingElementsHaveProblems); } - - boolean proposeType = - !this.requestor.isIgnored(CompletionProposal.TYPE_REF) || - ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)); - - boolean proposeAllMemberTypes = !this.assistNodeIsConstructor; - - if (!skip && proposeType && scope.enclosingSourceType() != null) { - findNestedTypes(token, scope.enclosingSourceType(), scope, proposeAllMemberTypes, typesFound); - if(!this.assistNodeIsInterface && - !this.assistNodeIsConstructor && - !this.assistNodeIsAnnotation && - this.assistNodeInJavadoc == 0) { - // don't propose type parameters if the completion is a constructor ('new |') - findTypeParameters(token, scope); - } + if (!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { + findClassField( + token, + receiverType, + scope, + missingElements, + missingElementsStarts, + missingElementsEnds, + missingElementsHaveProblems); } - boolean isEmptyPrefix = token.length == 0; - - if (!skip && proposeType && 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++) { - 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; - - 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; - } - - this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this); - - 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 (isEmptyPrefix && this.assistNodeIsException) { - if (sourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null) { - continue next; - } - } - + 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(token, sourceType.sourceName); - relevance += computeRelevanceForExpectingType(sourceType); - relevance += computeRelevanceForQualification(false); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for type in the current unit + relevance += computeRelevanceForCaseMatching(this.completionToken, Keywords.THIS); + relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywords + relevance += R_NON_INHERITED; - 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) { - char[] typeName = sourceType.sourceName(); - createTypeProposal( - sourceType, - typeName, - IAccessRule.K_ACCESSIBLE, - typeName, - relevance, - null, - null, - null, - 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(!skip && proposeType) { - findTypesFromStaticImports(token, scope, proposeAllMemberTypes, typesFound); + 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 (isEmptyPrefix && !this.assistNodeIsAnnotation) { - if(proposeType && this.expectedTypesPtr > -1) { - next : for (int i = 0; i <= this.expectedTypesPtr; i++) { - if(this.expectedTypes[i] instanceof ReferenceBinding) { - ReferenceBinding refBinding = (ReferenceBinding)this.expectedTypes[i]; - - 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; - } - } - } - - for (int j = 0; j < typesFound.size(); j++) { - ReferenceBinding typeFound = (ReferenceBinding)typesFound.elementAt(j); - if (typeFound == refBinding) { - continue next; - } - } + 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); + } + } - boolean inSameUnit = this.unitScope.isDefinedInSameUnit(refBinding); + 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); + } - // top level types of the current unit are already proposed. - if(skip || !inSameUnit || (inSameUnit && refBinding.isMemberType())) { - char[] packageName = refBinding.qualifiedPackageName(); - char[] typeName = refBinding.sourceName(); - char[] completionName = typeName; + 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) { - 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; - } - } + ReferenceBinding currentType = receiverType; + if (typeName == null) + return; - 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; - } + if (this.insideQualifiedReference + || typeName.length == 0) { // do not search up the hierarchy - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForCaseMatching(token, typeName); - relevance += computeRelevanceForExpectingType(refBinding); - relevance += computeRelevanceForQualification(isQualified); - relevance += computeRelevanceForRestrictions(accessibility); + findMemberTypes( + typeName, + currentType.memberTypes(), + typesFound, + receiverType, + typeInvocation, + staticOnly, + staticFieldsAndMethodOnly, + fromStaticImport, + checkQualification, + scope, + missingElements, + missingElementsStarts, + missingElementsEnds, + missingElementsHaveProblems); + return; + } - if(refBinding.isClass()) { - relevance += computeRelevanceForClass(); - relevance += computeRelevanceForException(typeName); - } else if(refBinding.isEnum()) { - relevance += computeRelevanceForEnum(); - } else if(refBinding.isInterface()) { - relevance += computeRelevanceForInterface(); - } + ReferenceBinding[] interfacesToVisit = null; + int nextPosition = 0; - 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); - } - } - } - } - } - } - } 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); - } + 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; } } } - 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, this); - } - int searchFor = IJavaSearchConstants.TYPE; - if(this.assistNodeIsClass) { - searchFor = IJavaSearchConstants.CLASS; - } else if(this.assistNodeIsInterface) { - searchFor = IJavaSearchConstants.INTERFACE_AND_ANNOTATION; - } else if(this.assistNodeIsEnum) { - searchFor = IJavaSearchConstants.ENUM; - } else if(this.assistNodeIsAnnotation) { - searchFor = IJavaSearchConstants.ANNOTATION_TYPE; + + 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); } - this.nameEnvironment.findTypes( - token, - proposeAllMemberTypes, - this.options.camelCaseMatch, - searchFor, - this); - acceptTypes(scope); } - if(!isEmptyPrefix && !this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { - this.nameEnvironment.findPackages(token, this); + } + + 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; + } + } } } } - private void findTypesAndSubpackages( - char[] token, - PackageBinding packageBinding, - Scope scope) { + 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) { - boolean proposeType = - !this.requestor.isIgnored(CompletionProposal.TYPE_REF) || - ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)); + // 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; - char[] qualifiedName = - CharOperation.concatWith(packageBinding.compoundName, token, '.'); + if (staticOnly && !memberType.isStatic()) continue next; - if (token == null || token.length == 0) { - int length = qualifiedName.length; - System.arraycopy( - qualifiedName, - 0, - qualifiedName = new char[length + 1], - 0, - length); - qualifiedName[length] = '.'; - } + if (isForbidden(memberType)) continue next; - this.qualifiedCompletionToken = qualifiedName; + if (typeLength > memberType.sourceName.length) + continue next; - if (proposeType && this.unitScope != null) { - int typeLength = qualifiedName.length; - SourceTypeBinding[] types = this.unitScope.topLevelTypes; + if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false/* ignore case */) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(typeName, memberType.sourceName))) + continue next; - for (int i = 0, length = types.length; i < length; i++) { - SourceTypeBinding sourceType = types[i]; + if (this.options.checkDeprecation && + memberType.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(memberType)) + continue next; - char[] qualifiedSourceTypeName = CharOperation.concatWith(sourceType.compoundName, '.'); + 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 (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 (this.insideQualifiedReference && + receiverType.isParameterizedType() && + memberType.isStatic()) { + continue next; + } - if (!CharOperation.prefixEquals(qualifiedName, qualifiedSourceTypeName, false) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, sourceType.sourceName))) continue; + for (int i = typesFound.size; --i >= 0;) { + ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i); - if (this.options.checkDeprecation && - sourceType.isViewedAsDeprecated() && - !scope.isDefinedInSameUnit(sourceType)) - continue; + if (memberType == otherType) + continue next; - 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; - } - } - } + if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) { - this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this); + if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType())) + continue next; - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForCaseMatching(qualifiedName, qualifiedSourceTypeName); - relevance += computeRelevanceForExpectingType(sourceType); - relevance += computeRelevanceForQualification(false); - relevance += computeRelevanceForRestrictions(accessibility); + if (otherType.enclosingType().isInterface()) + if (memberType.enclosingType() + .implementsInterface(otherType.enclosingType(), true)) + continue next; - if (sourceType.isAnnotationType()) { - relevance += computeRelevanceForAnnotation(); - } else if (sourceType.isInterface()) { - relevance += computeRelevanceForInterface(); - } else if (sourceType.isClass()) { - relevance += computeRelevanceForClass(); - relevance += computeRelevanceForException(sourceType.sourceName); + if (memberType.enclosingType().isInterface()) + if (otherType.enclosingType() + .implementsInterface(memberType.enclosingType(), true)) + continue next; } - this.noProposal = false; - if(proposeType) { - char[] typeName = sourceType.sourceName(); - createTypeProposal( - sourceType, - typeName, - IAccessRule.K_ACCESSIBLE, - typeName, - relevance, - null, - null, - null, - false); - } - } - } - - if(proposeType) { - int searchFor = IJavaSearchConstants.TYPE; - if(this.assistNodeIsClass) { - searchFor = IJavaSearchConstants.CLASS; - } else if(this.assistNodeIsInterface) { - searchFor = IJavaSearchConstants.INTERFACE_AND_ANNOTATION; - } else if(this.assistNodeIsEnum) { - searchFor = IJavaSearchConstants.ENUM; - } else if(this.assistNodeIsAnnotation) { - searchFor = IJavaSearchConstants.ANNOTATION_TYPE; } - this.nameEnvironment.findTypes( - qualifiedName, - false, - this.options.camelCaseMatch, - searchFor, - this); - acceptTypes(scope); - } - if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { - this.nameEnvironment.findPackages(qualifiedName, this); - } - } - - 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.length) continue; + typesFound.add(memberType); - if (!CharOperation.prefixEquals(token, typeBinding.sourceName, false) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeBinding.sourceName))) continue; + if(!this.insideQualifiedReference) { + if(this.assistNodeIsClass) { + 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; + } + } - if (typesFound.contains(typeBinding)) continue; + char[] completionName = memberType.sourceName(); - typesFound.add(typeBinding); + 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, + '.'), + '.'); + } + } - 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(); + 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. - int relevance = computeBaseRelevance(); - relevance += computeRelevanceForResolution(); - relevance += computeRelevanceForInterestingProposal(); - relevance += computeRelevanceForCaseMatching(token, typeBinding.sourceName); - relevance += computeRelevanceForExpectingType(typeBinding); - relevance += computeRelevanceForQualification(false); - relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); + 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 (typeBinding.isClass()) { - relevance += computeRelevanceForClass(); - relevance += computeRelevanceForException(typeBinding.sourceName); - } else if(typeBinding.isEnum()) { - relevance += computeRelevanceForEnum(); - } else if(typeBinding.isInterface()) { - relevance += computeRelevanceForInterface(); - } + if (missingElements != null) { + relevance += computeRelevanceForMissingElements(missingElementsHaveProblems); + } - 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); - } - } - } + this.noProposal = false; + createTypeProposal( + memberType, + memberType.qualifiedSourceName(), + IAccessRule.K_ACCESSIBLE, + completionName, + relevance, + missingElements, + missingElementsStarts, + missingElementsEnds, + missingElementsHaveProblems); + } + } + 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 findVariablesAndMethods( - char[] token, + + 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, - InvocationSite invocationSite, - Scope invocationScope, - boolean insideTypeAnnotation, - boolean insideAnnotationAttribute) { + ObjectVector methodsFound, + Binding[] missingElements, + int[] missingElementsStarts, + int[] missingElementsEnds, + boolean missingElementsHaveProblems) { - if (token == null) + if (selector == 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(); + MethodBinding[] receiverTypeMethods = receiverType.availableMethods(); + if (receiverTypeMethods != null){ + for (int i = 0; i < receiverTypeMethods.length; i++) { + if(!receiverTypeMethods[i].isDefaultAbstract()) { + methodsFound.add(receiverTypeMethods[i]); + } + } + } - Scope currentScope = scope; + 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) { - if (!this.requestor.isIgnored(CompletionProposal.LOCAL_VARIABLE_REF)) { - done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + MethodBinding[] methods = currentType.availableMethods(); + if (methods != null) { + findLocalMethodDeclarations( + selector, + methods, + scope, + methodsFound, + false, + receiverType); + } - switch (currentScope.kind) { + if (hasPotentialDefaultAbstractMethods && + (currentType.isAbstract() || + currentType.isTypeVariable() || + currentType.isIntersectionType() || + currentType.isEnum())){ - 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; + ReferenceBinding[] superInterfaces = currentType.superInterfaces(); - //$FALL-THROUGH$ - case Scope.BLOCK_SCOPE : - BlockScope blockScope = (BlockScope) currentScope; + 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; - next : for (int i = 0, length = blockScope.locals.length; i < length; i++) { - LocalVariableBinding local = blockScope.locals[i]; + char[][] parameterNames = null; - if (local == null) - break next; + int length = parameterTypeNames.length; - if (tokenLength > local.name.length) - continue next; + 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 (!CharOperation.prefixEquals(token, local.name, false /* ignore case */) - && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, local.name))) - continue next; + if (sourceType.scope != null){ + TypeDeclaration parsedType; - if (local.isSecret()) - continue next; + if ((parsedType = sourceType.scope.referenceContext) != null){ + AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method.original()); - 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); + if (methodDecl != null){ + Argument[] arguments = methodDecl.arguments; + parameterNames = new char[length][]; - 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 - 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); - } - } + for(int i = 0 ; i < length ; i++){ + parameterNames[i] = arguments[i].name; } - break; - - case Scope.COMPILATION_UNIT_SCOPE : - break done1; + } } - currentScope = currentScope.parent; } } + // look into the model + if(parameterNames == null){ - 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 + ReferenceBinding bindingType = (ReferenceBinding)erasure; - 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, - false, - invocationSite, - invocationScope, - true, - false, - true, - null, - null, - null, - false, - null, - -1, - -1); - } - } - staticsOnly |= enclosingType.isStatic(); - insideTypeAnnotation = false; - // } - break; + char[] compoundName = CharOperation.concatWith(bindingType.compoundName, '.'); + Object type = this.typeCache.get(compoundName); - case Scope.COMPILATION_UNIT_SCOPE : - break done2; + 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); } - currentScope = currentScope.parent; } - findFieldsAndMethodsFromStaticImports( - token, - scope, - invocationSite, - invocationScope, - false, - insideAnnotationAttribute, - localsFound, - fieldsFound, - methodsFound, - proposeField, - proposeMethod); + if(sourceType != null) { + IType typeHandle = ((SourceTypeElementInfo) sourceType).getHandle(); - if (this.assistNodeInJavadoc == 0) { - // search in favorites import - findFieldsAndMethodsFromFavorites( - token, - scope, - invocationSite, - invocationScope, - localsFound, - fieldsFound, - methodsFound); - } + 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); - findEnumConstantsFromExpectedTypes( - token, - invocationScope, - fieldsFound); - } - } - - 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); - } - - 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, - false, - 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)) { - - findLocalMethodsFromStaticImports( - methodBinding.selector, - methodBinding.declaringClass.methods(), - scope, - exactMatch, - methodsFound, - methodBinding.declaringClass, - invocationSite); - } - } + 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 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(); + 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) { - 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 + boolean notInJavadoc = this.assistNodeInJavadoc == 0; + if (selector == null && notInJavadoc) { + return; + } - // 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); - } - }; + 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); - ReferenceContext referenceContext = scope.referenceContext(); - if (referenceContext instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration md = (AbstractMethodDeclaration)referenceContext; + currentType = scope.getJavaLangObject(); + } + } + boolean hasPotentialDefaultAbstractMethods = true; + while (currentType != null) { - 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; - } - } + 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()); } } - } - int proposedNamesCount = proposedNames.size(); - if (proposedNamesCount > 0) { - return (char[][])proposedNames.toArray(new char[proposedNamesCount][]); + 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(); } - - return null; } - 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); - } - }; + private void findNestedTypes( + char[] typeName, + SourceTypeBinding currentType, + Scope scope, + boolean proposeAllMemberTypes, + ObjectVector typesFound) { + + if (typeName == null) + return; - ReferenceContext referenceContext = scope.referenceContext(); - if (referenceContext instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration md = (AbstractMethodDeclaration)referenceContext; + int typeLength = typeName.length; - 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; - } - } - } - } - } + SourceTypeBinding nextTypeToIgnore = null; + while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found - int proposedNamesCount = proposedNames.size(); - if (proposedNamesCount > 0) { - return (char[][])proposedNames.toArray(new char[proposedNamesCount][]); - } + switch (scope.kind) { - return null; - } + case Scope.METHOD_SCOPE : + case Scope.BLOCK_SCOPE : + BlockScope blockScope = (BlockScope) scope; - 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); - } + next : for (int i = 0, length = blockScope.subscopeCount; i < length; i++) { - private char[][] findUnresolvedReferenceBefore(int recordTo, int parseTo, BlockScope scope, final char[][] discouragedNames) { - final ArrayList proposedNames = new ArrayList(); + if (blockScope.subscopes[i] instanceof ClassScope) { + SourceTypeBinding localType = + ((ClassScope) blockScope.subscopes[i]).referenceContext.binding; - UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor nameRequestor = - new UnresolvedReferenceNameFinder.UnresolvedReferenceNameRequestor() { - public void acceptName(char[] name) { - CompletionEngine.this.acceptUnresolvedName(name); - proposedNames.add(name); - } - }; + if (!localType.isAnonymousType()) { + if (isForbidden(localType)) + continue next; - BlockScope upperScope = scope; - while (upperScope.enclosingMethodScope() != null) { - upperScope = upperScope.enclosingMethodScope(); - } + 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; - ReferenceContext referenceContext = upperScope.referenceContext(); - if (referenceContext instanceof AbstractMethodDeclaration) { - AbstractMethodDeclaration md = (AbstractMethodDeclaration)referenceContext; + for (int j = typesFound.size; --j >= 0;) { + ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j); - 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; + if (localType == otherType) + 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; + } - 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) { + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + 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); - UnresolvedReferenceNameFinder nameFinder = new UnresolvedReferenceNameFinder(this); - nameFinder.findBefore( - this.completionToken, - typeDeclaration.scope, - typeDeclaration.scope, - initializer.block.sourceStart, - recordTo, - parseTo, - discouragedNames, - nameRequestor); - break done; + this.noProposal = false; + if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { + createTypeProposal( + localType, + localType.sourceName, + IAccessRule.K_ACCESSIBLE, + localType.sourceName, + relevance, + null, + null, + null, + false); + } } } } - } - } - } - - int proposedNamesCount = proposedNames.size(); - if (proposedNamesCount > 0) { - return (char[][])proposedNames.toArray(new char[proposedNamesCount][]); - } + break; - return null; - } - // 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, - int modifiers){ - findVariableName( - token, - qualifiedPackageName, - qualifiedSourceName, - sourceName, - typeBinding, - discouragedNames, - forbiddenNames, - false, - dim, - kind, - modifiers); - } - 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, - int modifiers){ - - if(sourceName == null || sourceName.length == 0) - return; + 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; - // 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; + case Scope.COMPILATION_UNIT_SCOPE : + return; } - } else { - displayName = typeBinding.qualifiedSourceName(); + scope = scope.parent; } + } - final char[] t = token; - final char[] q = qualifiedPackageName; - INamingRequestor namingRequestor = new INamingRequestor() { - 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 acceptNameWithPrefix(char[] name, boolean isFirstPrefix, int reusedCharacters) { - accept(name, isFirstPrefix ? R_NAME_FIRST_PREFIX : R_NAME_PREFIX, reusedCharacters); - } + private void findPackages(CompletionOnPackageReference packageStatement) { - public void acceptNameWithSuffix(char[] name, boolean isFirstSuffix, int reusedCharacters) { - accept(name, isFirstSuffix ? R_NAME_FIRST_SUFFIX : R_NAME_SUFFIX, reusedCharacters); - } + this.completionToken = CharOperation.concatWith(packageStatement.tokens, '.'); + if (this.completionToken.length == 0) + return; - public void acceptNameWithoutPrefixAndSuffix(char[] name,int reusedCharacters) { - accept(name, 0, reusedCharacters); - } - 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; - } + 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); + } - 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 + 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; - // 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); - } + 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; } } } - }; - switch (kind) { - case FIELD : - InternalNamingConventions.suggestFieldNames( - this.javaProject, - qualifiedPackageName, - qualifiedSourceName, - dim, - modifiers, - token, - discouragedNames, - namingRequestor); - break; - case LOCAL : - InternalNamingConventions.suggestLocalVariableNames( - this.javaProject, - qualifiedPackageName, - qualifiedSourceName, - dim, - token, - discouragedNames, - namingRequestor); - break; - case ARGUMENT : - InternalNamingConventions.suggestArgumentNames( - this.javaProject, - qualifiedPackageName, - qualifiedSourceName, - dim, - token, - discouragedNames, - namingRequestor); - 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 findVariableNameForCollection( - char[] token, - char[] qualifiedPackageName, - char[] qualifiedSourceName, - char[] sourceName, - final TypeBinding typeBinding, - char[][] discouragedNames, - final char[][] forbiddenNames, - int kind, - int modifiers){ - findVariableName( - token, - qualifiedPackageName, - qualifiedSourceName, - sourceName, - typeBinding, - discouragedNames, - forbiddenNames, - false, - 1, - kind, - modifiers); - } + private void findSubMemberTypes( + char[] typeName, + ReferenceBinding receiverType, + Scope scope, + SourceTypeBinding typeInvocation, + boolean staticOnly, + boolean staticFieldsAndMethodOnly, + boolean fromStaticImport, + ObjectVector typesFound) { - private void findVariableNames(char[] name, TypeReference type , char[][] discouragedNames, char[][] forbiddenNames, int kind, int modifiers){ - if(type != null && - type.resolvedType != null) { - TypeBinding tb = type.resolvedType; + ReferenceBinding currentType = receiverType; + if (typeName == null || typeName.length == 0) + return; - 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, - modifiers); - - 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, - modifiers); - } + 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 ImportBinding[] getFavoriteReferenceBindings(Scope scope) { - if (this.favoriteReferenceBindings != null) return this.favoriteReferenceBindings; + private void findTrueOrFalseKeywords(char[][] choices) { + if(choices == null || choices.length == 0) return; - String[] favoriteReferences = this.requestor.getFavoriteReferences(); + if(this.expectedTypesPtr != 0 || this.expectedTypes[0] != TypeBinding.BOOLEAN) return; - if (favoriteReferences == null || favoriteReferences.length == 0) return null; + 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; - ImportBinding[] resolvedImports = new ImportBinding[favoriteReferences.length]; + 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); + } + } + } + } + } - int count = 0; - next : for (int i = 0; i < favoriteReferences.length; i++) { - String favoriteReference = favoriteReferences[i]; + private void findTypeParameters(char[] token, Scope scope) { + if (this.compilerOptions.sourceLevel < ClassFileConstants.JDK1_5) return; - int length; - if (favoriteReference == null || (length = favoriteReference.length()) == 0) continue next; + 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]; - boolean onDemand = favoriteReference.charAt(length - 1) == '*'; + if(typeParameter.binding == null) continue; - char[][] compoundName = CharOperation.splitOn('.', favoriteReference.toCharArray()); - if (onDemand) { - compoundName = CharOperation.subarray(compoundName, 0, compoundName.length - 1); - } + if (typeLength > typeParameter.name.length) continue; - // remove duplicate and conflicting - for (int j = 0; j < count; j++) { - ImportReference f = resolvedImports[j].reference; + if (!CharOperation.prefixEquals(token, typeParameter.name, false) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, typeParameter.name))) continue; - if (CharOperation.equals(f.tokens, compoundName)) continue next; + 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 - if (!onDemand && ((f.bits & ASTNode.OnDemand) == 0)) { - if (CharOperation.equals(f.tokens[f.tokens.length - 1], compoundName[compoundName.length - 1])) - continue next; + this.noProposal = false; + if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { + createTypeParameterProposal(typeParameter, relevance); + } } } + scope = scope.parent; + } + } - boolean isStatic = true; - - ImportReference importReference = - new ImportReference( - compoundName, - new long[compoundName.length], - onDemand, - isStatic ? ClassFileConstants.AccStatic : ClassFileConstants.AccDefault); + private void findTypesAndPackages(char[] token, Scope scope, boolean proposeBaseTypes, boolean proposeVoidType, ObjectVector typesFound) { - Binding importBinding = this.unitScope.findImport(compoundName, isStatic, onDemand); + if (token == null) + return; - if (!importBinding.isValidBinding()) { - continue next; + // do not propose type if completion token is empty + boolean skip = false; + if (token.length == 0 && NO_TYPE_COMPLETION_ON_EMPTY_TOKEN) { + if(!this.assistNodeIsConstructor && (this.assistNodeInJavadoc & CompletionOnJavadoc.EXCEPTION) == 0) { + return; } + skip = true; + } - if (importBinding instanceof PackageBinding) { - continue next; - } + boolean proposeType = + !this.requestor.isIgnored(CompletionProposal.TYPE_REF) || + ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)); - resolvedImports[count++] = - new ImportBinding(compoundName, onDemand, importBinding, importReference); + boolean proposeAllMemberTypes = !this.assistNodeIsConstructor; + + if (!skip && proposeType && 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); + } } - if (resolvedImports.length > count) - System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[count], 0, count); + boolean isEmptyPrefix = token.length == 0; - return this.favoriteReferenceBindings = resolvedImports; - } + if (!skip && proposeType && this.unitScope != null) { + + ReferenceBinding outerInvocationType = scope.enclosingSourceType(); + if(outerInvocationType != null) { + ReferenceBinding temp = outerInvocationType.enclosingType(); + while(temp != null) { + outerInvocationType = temp; + temp = temp.enclosingType(); + } + } - public AssistParser getParser() { + int typeLength = token.length; + SourceTypeBinding[] types = this.unitScope.topLevelTypes; - return this.parser; - } + next : for (int i = 0, length = types.length; i < length; i++) { + + checkCancel(); + + SourceTypeBinding sourceType = types[i]; - 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 + if(isForbidden(sourceType)) continue next; - 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); + if(proposeAllMemberTypes && + sourceType != outerInvocationType) { + findSubMemberTypes( + token, + sourceType, + scope, + scope.enclosingSourceType(), + false, + false, + false, + typesFound); } - 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 static char[] getRequiredTypeSignature(TypeBinding typeBinding) { - char[] result = null; - StringBuffer sig = new StringBuffer(10); + if (sourceType.sourceName == CompletionParser.FAKE_TYPE_NAME) continue next; + if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME) continue next; - sig.append(typeBinding.signature()); + if (typeLength > sourceType.sourceName.length) continue next; - int sigLength = sig.length(); - result = new char[sigLength]; - sig.getChars(0, sigLength, result, 0); - result = CharOperation.replaceOnCopy(result, '/', '.'); - return result; - } + if (!CharOperation.prefixEquals(token, sourceType.sourceName, false) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, sourceType.sourceName))) continue; - 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; - } + if (this.assistNodeIsAnnotation && !hasPossibleAnnotationTarget(sourceType, scope)) { + continue next; } - } - } - return true; - } - protected void reset() { + for (int j = typesFound.size; --j >= 0;) { + ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(j); - super.reset(false); - this.knownPkgs = new HashtableOfObject(10); - this.knownTypes = new HashtableOfObject(10); - } + if (sourceType == otherType) continue next; + } - private void setSourceAndTokenRange(int start, int end) { - this.setSourceAndTokenRange(start, end, true); - } + this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this); - private void setSourceAndTokenRange(int start, int end, boolean emptyTokenAdjstment) { - this.setSourceRange(start, end, emptyTokenAdjstment); - this.setTokenRange(start, end, emptyTokenAdjstment); - } + 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 (isEmptyPrefix && this.assistNodeIsException) { + if (sourceType.findSuperTypeOriginatingFrom(TypeIds.T_JavaLangThrowable, true) == null) { + continue next; + } + } - private void setSourceRange(int start, int end) { - this.setSourceRange(start, end, true); - } + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + 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 - 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; + 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) { + char[] typeName = sourceType.sourceName(); + createTypeProposal( + sourceType, + typeName, + IAccessRule.K_ACCESSIBLE, + typeName, + relevance, + null, + null, + null, + false); + } + } } - } - 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; + if(!skip && proposeType) { + + checkCancel(); + + findTypesFromStaticImports(token, scope, proposeAllMemberTypes, typesFound); } - } - private char[][] computeAlreadyDefinedName( - BlockScope scope, - InvocationSite invocationSite) { - ArrayList result = new ArrayList(); + if (isEmptyPrefix && !this.assistNodeIsAnnotation) { + if(proposeType && this.expectedTypesPtr > -1) { + next : for (int i = 0; i <= this.expectedTypesPtr; i++) { + + checkCancel(); + + if(this.expectedTypes[i] instanceof ReferenceBinding) { + ReferenceBinding refBinding = (ReferenceBinding)this.expectedTypes[i]; - boolean staticsOnly = false; + 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; - Scope currentScope = scope; + 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; + } + } + } - done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found + for (int j = 0; j < typesFound.size(); j++) { + ReferenceBinding typeFound = (ReferenceBinding)typesFound.elementAt(j); + if (typeFound == refBinding) { + continue next; + } + } - switch (currentScope.kind) { + boolean inSameUnit = this.unitScope.isDefinedInSameUnit(refBinding); - 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; + // top level types of the current unit are already proposed. + if(skip || !inSameUnit || (inSameUnit && refBinding.isMemberType())) { + char[] packageName = refBinding.qualifiedPackageName(); + char[] typeName = refBinding.sourceName(); + char[] completionName = typeName; - //$FALL-THROUGH$ - case Scope.BLOCK_SCOPE : - BlockScope blockScope = (BlockScope) currentScope; + 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; + } + } - next : for (int i = 0, length = blockScope.locals.length; i < length; i++) { - LocalVariableBinding local = blockScope.locals[i]; + 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; + } - if (local == null) - break next; + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + relevance += computeRelevanceForCaseMatching(token, typeName); + relevance += computeRelevanceForExpectingType(refBinding); + relevance += computeRelevanceForQualification(isQualified); + relevance += computeRelevanceForRestrictions(accessibility); - if (local.isSecret()) - continue next; + if(refBinding.isClass()) { + relevance += computeRelevanceForClass(); + relevance += computeRelevanceForException(typeName); + } else if(refBinding.isEnum()) { + relevance += computeRelevanceForEnum(); + } else if(refBinding.isInterface()) { + relevance += computeRelevanceForInterface(); + } - result.add(local.name); + 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); + } + } + } } - 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( - 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; + } 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); + } } } } - - 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); + 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, this); } - - 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 searchFor = IJavaSearchConstants.TYPE; + if(this.assistNodeIsClass) { + searchFor = IJavaSearchConstants.CLASS; + } 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); + acceptTypes(scope); + } + if(!isEmptyPrefix && !this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { + + checkCancel(); + + this.nameEnvironment.findPackages(token, this); } } } - 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; + private void findTypesAndSubpackages( + char[] token, + PackageBinding packageBinding, + Scope scope) { - if (onlyStaticFields && !field.isStatic()) continue next; + boolean proposeType = + !this.requestor.isIgnored(CompletionProposal.TYPE_REF) || + ((this.assistNodeInJavadoc & CompletionOnJavadoc.TEXT) != 0 && !this.requestor.isIgnored(CompletionProposal.JAVADOC_TYPE_REF)); - if (!field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; + char[] qualifiedName = + CharOperation.concatWith(packageBinding.compoundName, token, '.'); - result.add(field.name); + if (token == null || token.length == 0) { + int length = qualifiedName.length; + System.arraycopy( + qualifiedName, + 0, + qualifiedName = new char[length + 1], + 0, + length); + qualifiedName[length] = '.'; } - } - int computeBaseRelevance(){ - return R_DEFAULT; - } - int computeRelevanceForResolution(){ - return computeRelevanceForResolution(true); - } - int computeRelevanceForResolution(boolean isResolved){ - if (isResolved) { - return R_RESOLVED; - } - return 0; - } - private void computeExpectedTypes(ASTNode parent, ASTNode node, Scope scope){ + this.qualifiedCompletionToken = qualifiedName; - // default filter - this.expectedTypesFilter = SUBTYPE; - this.hasJavaLangObjectAsExpectedType = false; + if (proposeType && this.unitScope != null) { + int typeLength = qualifiedName.length; + SourceTypeBinding[] types = this.unitScope.topLevelTypes; - // find types from parent - if(parent instanceof AbstractVariableDeclaration) { - AbstractVariableDeclaration variable = (AbstractVariableDeclaration)parent; - TypeBinding binding = variable.type.resolvedType; - if(binding != null) { - if(!(variable.initialization instanceof ArrayInitializer)) { - 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) { - Expression 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; + for (int i = 0, length = types.length; i < length; i++) { + + checkCancel(); + + SourceTypeBinding sourceType = types[i]; - if(messageSend.actualReceiverType instanceof ReferenceBinding) { - ReferenceBinding binding = (ReferenceBinding)messageSend.actualReceiverType; - boolean isStatic = messageSend.receiver.isTypeReference(); + char[] qualifiedSourceTypeName = CharOperation.concatWith(sourceType.compoundName, '.'); - 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; + 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; - ReferenceBinding binding = (ReferenceBinding)allocationExpression.type.resolvedType; + if (!CharOperation.prefixEquals(qualifiedName, qualifiedSourceTypeName, false) + && !(this.options.camelCaseMatch && CharOperation.camelCaseMatch(token, sourceType.sourceName))) continue; - 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); - } + if (this.options.checkDeprecation && + sourceType.isViewedAsDeprecated() && + !scope.isDefinedInSameUnit(sourceType)) + 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; } } } - } 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; + + this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this); + + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + 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) { + char[] typeName = sourceType.sourceName(); + createTypeProposal( + sourceType, + typeName, + IAccessRule.K_ACCESSIBLE, + typeName, + relevance, + null, + null, + null, + false); } } - } 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; - 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); + if(proposeType) { + int searchFor = IJavaSearchConstants.TYPE; + if(this.assistNodeIsClass) { + searchFor = IJavaSearchConstants.CLASS; + } else if(this.assistNodeIsInterface) { + searchFor = IJavaSearchConstants.INTERFACE_AND_ANNOTATION; + } else if(this.assistNodeIsEnum) { + searchFor = IJavaSearchConstants.ENUM; + } else if(this.assistNodeIsAnnotation) { + searchFor = IJavaSearchConstants.ANNOTATION_TYPE; } - } else if(parent instanceof ParameterizedQualifiedTypeReference) { - ParameterizedQualifiedTypeReference ref = (ParameterizedQualifiedTypeReference) parent; - TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables(); - TypeReference[][] arguments = ref.typeArguments; - 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; + + checkCancel(); + + this.foundTypesCount = 0; + this.nameEnvironment.findTypes( + qualifiedName, + false, + this.options.camelCaseMatch, + searchFor, + this); + acceptTypes(scope); + } + if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { + this.nameEnvironment.findPackages(qualifiedName, this); + } + } + + 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(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; + } else { + if ((binding.kind() & Binding.TYPE) != 0) { + ReferenceBinding typeBinding = (ReferenceBinding) binding; + int typeLength = token.length; + + if (!typeBinding.isStatic()) continue; + + if (typeLength > typeBinding.sourceName.length) continue; + + 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.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(); + 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; } } - if (canBeSingleMemberAnnotation) { - this.assistNodeCanBeSingleMemberAnnotation = canBeSingleMemberAnnotation; - addExpectedType(methodBindings[0].returnType, scope); + } + } + } + } + + 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, + int modifiers){ + + 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); + } + }; + + switch (kind) { + case FIELD : + InternalNamingConventions.suggestFieldNames( + this.javaProject, + qualifiedPackageName, + qualifiedSourceName, + dim, + modifiers, + token, + discouragedNames, + namingRequestor); + break; + case LOCAL : + InternalNamingConventions.suggestLocalVariableNames( + this.javaProject, + qualifiedPackageName, + qualifiedSourceName, + dim, + token, + discouragedNames, + namingRequestor); + break; + case ARGUMENT : + InternalNamingConventions.suggestArgumentNames( + this.javaProject, + qualifiedPackageName, + qualifiedSourceName, + dim, + token, + discouragedNames, + namingRequestor); + break; + } + } + + // 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, + int modifiers){ + findVariableName( + token, + qualifiedPackageName, + qualifiedSourceName, + sourceName, + typeBinding, + discouragedNames, + forbiddenNames, + false, + dim, + kind, + modifiers); + } + private void findVariableNameForCollection( + char[] token, + char[] qualifiedPackageName, + char[] qualifiedSourceName, + char[] sourceName, + final TypeBinding typeBinding, + char[][] discouragedNames, + final char[][] forbiddenNames, + int kind, + int modifiers){ + + findVariableName( + token, + qualifiedPackageName, + qualifiedSourceName, + sourceName, + typeBinding, + discouragedNames, + forbiddenNames, + false, + 1, + kind, + modifiers); + } + private void findVariableNames(char[] name, TypeReference type , char[][] discouragedNames, char[][] forbiddenNames, int kind, int modifiers){ + 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, + modifiers); + + 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, + modifiers); + } + } + } + } + + } + 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; + + 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 + 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); + } + } } - } - } - } - } 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(); - ReferenceBinding[] bindings = thrownExceptionFinder.find((TryStatement) parent, (BlockScope)scope); - if (bindings != null && bindings.length > 0) { - for (int i = 0; i < bindings.length; i++) { - addExpectedType(bindings[i], scope); - } - this.expectedTypesFilter = SUPERTYPE; - } - } - } else if (parent instanceof SwitchStatement) { - SwitchStatement switchStatement = (SwitchStatement) parent; - if (switchStatement.expression != null && - switchStatement.expression.resolvedType != null) { - addExpectedType(switchStatement.expression.resolvedType, scope); - } + break; - // 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); - } - } + case Scope.COMPILATION_UNIT_SCOPE : + break done1; } + currentScope = currentScope.parent; } } + + checkCancel(); - 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; + boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF); + boolean proposeMethod = !this.requestor.isIgnored(CompletionProposal.METHOD_REF); - if (this.options.checkVisibility && !method.canBeSeenBy(invocationSite, scope)) continue nextMethod; + staticsOnly = false; + currentScope = scope; - TypeBinding[] parameters = method.parameters; - if(parameters.length < arguments.length) - continue nextMethod; + if(proposeField || proposeMethod) { + done2 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found - int length = arguments.length - 1; + 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; - for (int j = 0; j < length; j++) { - Expression argument = arguments[j]; - TypeBinding argType = argument.resolvedType; - if(argType != null && !argType.isCompatibleWith(parameters[j])) - continue nextMethod; + case Scope.COMPILATION_UNIT_SCOPE : + break done2; + } + currentScope = currentScope.parent; } + + checkCancel(); + + findFieldsAndMethodsFromStaticImports( + token, + scope, + invocationSite, + invocationScope, + false, + insideAnnotationAttribute, + localsFound, + fieldsFound, + methodsFound, + proposeField, + proposeMethod); - TypeBinding expectedType = method.parameters[arguments.length - 1]; - if(expectedType != null) { - addExpectedType(expectedType, scope); + if (this.assistNodeInJavadoc == 0) { + + checkCancel(); + + // search in favorites import + findFieldsAndMethodsFromFavorites( + token, + scope, + invocationSite, + invocationScope, + localsFound, + fieldsFound, + methodsFound); } + + checkCancel(); + + findEnumConstantsFromExpectedTypes( + token, + invocationScope, + fieldsFound); } } - private void computeExpectedTypesForMessageSendForInterface( - ReferenceBinding binding, - char[] selector, - Expression[] arguments, - ReferenceBinding receiverType, - Scope scope, - InvocationSite invocationSite, - boolean isStatic) { + 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 - ReferenceBinding[] itsInterfaces = binding.superInterfaces(); - if (itsInterfaces != Binding.NO_SUPERINTERFACES) { - ReferenceBinding[] interfacesToVisit = itsInterfaces; - int nextPosition = interfacesToVisit.length; + 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); - for (int i = 0; i < nextPosition; i++) { - ReferenceBinding currentType = interfacesToVisit[i]; - computeExpectedTypesForMessageSend( - currentType, - selector, - arguments, - receiverType, - scope, - invocationSite, - 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); + } + } else { + char[] typeSig = referenceBinding.signature(); + sig.append(typeSig, 0, typeSig.length-1); // copy all but trailing semicolon - 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; + 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 void computeExpectedTypesForMessageSend( - ReferenceBinding binding, - char[] selector, - Expression[] arguments, - ReferenceBinding receiverType, - Scope scope, - InvocationSite invocationSite, - boolean isStatic) { + private ImportBinding[] getFavoriteReferenceBindings(Scope scope) { + if (this.favoriteReferenceBindings != null) return this.favoriteReferenceBindings; - MethodBinding[] methods = binding.availableMethods(); - nextMethod : for (int i = 0; i < methods.length; i++) { - MethodBinding method = methods[i]; + String[] favoriteReferences = this.requestor.getFavoriteReferences(); - if (method.isSynthetic()) continue nextMethod; + if (favoriteReferences == null || favoriteReferences.length == 0) return null; - if (method.isDefaultAbstract()) continue nextMethod; + ImportBinding[] resolvedImports = new ImportBinding[favoriteReferences.length]; - if (method.isConstructor()) continue nextMethod; + int count = 0; + next : for (int i = 0; i < favoriteReferences.length; i++) { + String favoriteReference = favoriteReferences[i]; - if (isStatic && !method.isStatic()) continue nextMethod; + int length; + if (favoriteReference == null || (length = favoriteReference.length()) == 0) continue next; - if (this.options.checkVisibility && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue nextMethod; + boolean onDemand = favoriteReference.charAt(length - 1) == '*'; - if(!CharOperation.equals(method.selector, selector)) continue nextMethod; + char[][] compoundName = CharOperation.splitOn('.', favoriteReference.toCharArray()); + if (onDemand) { + compoundName = CharOperation.subarray(compoundName, 0, compoundName.length - 1); + } - TypeBinding[] parameters = method.parameters; - if(parameters.length < arguments.length) - continue nextMethod; + // remove duplicate and conflicting + for (int j = 0; j < count; j++) { + ImportReference f = resolvedImports[j].reference; - int length = arguments.length - 1; + if (CharOperation.equals(f.tokens, compoundName)) continue next; - for (int j = 0; j < length; j++) { - Expression argument = arguments[j]; - TypeBinding argType = argument.resolvedType; - if(argType != null && !argType.isCompatibleWith(parameters[j])) - continue nextMethod; + if (!onDemand && ((f.bits & ASTNode.OnDemand) == 0)) { + if (CharOperation.equals(f.tokens[f.tokens.length - 1], compoundName[compoundName.length - 1])) + continue next; + } } - TypeBinding expectedType = method.parameters[arguments.length - 1]; - if(expectedType != null) { - addExpectedType(expectedType, scope); + 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; } - } - } - 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; + if (importBinding instanceof PackageBinding) { + continue next; + } + + resolvedImports[count++] = + new ImportBinding(compoundName, onDemand, importBinding, importReference); } - 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 (resolvedImports.length > count) + System.arraycopy(resolvedImports, 0, resolvedImports = new ImportBinding[count], 0, count); - if(type == scope.getJavaLangObject()) { - this.hasJavaLangObjectAsExpectedType = true; - } + return this.favoriteReferenceBindings = resolvedImports; } - 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; + public AssistParser getParser() { - 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; + return this.parser; } - - private Scope computeForbiddenBindings(ASTNode astNode, ASTNode astNodeParent, Scope scope) { - this.forbbidenBindingsFilter = NONE; - if(scope instanceof ClassScope) { - TypeDeclaration typeDeclaration = ((ClassScope)scope).referenceContext; - if(typeDeclaration.superclass == astNode) { - addForbiddenBindings(typeDeclaration.binding); - return scope.parent; - } - TypeReference[] superInterfaces = typeDeclaration.superInterfaces; - int length = superInterfaces == null ? 0 : superInterfaces.length; - for (int i = 0; i < length; i++) { - if(superInterfaces[i] == astNode) { - addForbiddenBindings(typeDeclaration.binding); - return scope.parent; - } + 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 (astNodeParent != null && astNodeParent 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) { - Argument[] catchArguments = ((TryStatement) astNodeParent).catchArguments; - int length = catchArguments == null ? 0 : catchArguments.length; - for (int i = 0; i < length; i++) { - TypeBinding caughtException = catchArguments[i].type.resolvedType; - if (caughtException != null) { - addForbiddenBindings(caughtException); - this.knownTypes.put(CharOperation.concat(caughtException.qualifiedPackageName(), caughtException.qualifiedSourceName(), '.'), this); - } + } 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; } - this.forbbidenBindingsFilter = SUBTYPE; } } } -// else if(scope instanceof MethodScope) { -// MethodScope methodScope = (MethodScope) scope; -// if(methodScope.insideTypeAnnotation) { -// return methodScope.parent.parent; -// } -// } - return scope; - } - 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(); + return true; } - - 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); - } - } + /** + * 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 isForbidden(Binding binding) { for (int i = 0; i <= this.forbbidenBindingsPtr; i++) { @@ -10033,6 +10300,19 @@ } return false; } + + private boolean isIgnored(int kind) { + return this.requestor.isIgnored(kind); + } + private 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) { @@ -10112,260 +10392,41 @@ } return true; } - 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); - } - - 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[] 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); - } - - 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; - } - - /* - * 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); - } + 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$ } - - // 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); - } + 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(';'); } - } - - /* - * 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); - } - } + char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$ + this.offset = prefix.length(); - // 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); - } - } - } + String encoding = this.compilerOptions.defaultEncoding; + BasicCompilationUnit fakeUnit = new BasicCompilationUnit( + fakeSource, + null, + "FakeType.java", //$NON-NLS-1$ + encoding); - /** - * 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; - } + 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$ @@ -10373,18 +10434,12 @@ System.out.println(")"); //$NON-NLS-1$ } } - - private void printDebugTab(int tab, StringBuffer buffer) { - for (int i = 0; i < tab; i++) { - buffer.append('\t'); - } - } - 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$ @@ -10509,42 +10564,169 @@ buffer.append("}\n");//$NON-NLS-1$ } - private char[][] substituteMethodTypeParameterNames(TypeVariableBinding[] typeVariables, char[][] excludedNames) { - char[][] substituedParameterNames = new char[typeVariables.length][]; + private void printDebugTab(int tab, StringBuffer buffer) { + for (int i = 0; i < tab; i++) { + buffer.append('\t'); + } + } - for (int i = 0; i < substituedParameterNames.length; i++) { - substituedParameterNames[i] = typeVariables[i].sourceName; + 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); + } } + } - boolean foundConflicts = false; + 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; + } - nextTypeParameter : for (int i = 0; i < typeVariables.length; i++) { - TypeVariableBinding typeVariableBinding = typeVariables[i]; - char[] methodParameterName = typeVariableBinding.sourceName; + TypeBinding guessedType = null; + if ((modifiers & ClassFileConstants.AccAnnotation) != 0 && + this.assistNodeIsAnnotation && + (this.targetedElement & TagBits.AnnotationTargetMASK) != 0) { + char[][] cn = CharOperation.splitOn('.', fullyQualifiedName); - 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; + TypeReference ref; + if (cn.length == 1) { + ref = new SingleTypeReference(simpleTypeName, 0); + } else { + ref = new QualifiedTypeReference(cn,new long[cn.length]); + } - foundConflicts = true; - continue nextTypeParameter; - } + 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; } - if(foundConflicts) return substituedParameterNames; - return null; + int relevance = computeBaseRelevance(); + relevance += computeRelevanceForResolution(); + relevance += computeRelevanceForInterestingProposal(); + 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); + } + + 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) { @@ -10596,4 +10778,42 @@ } 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; + } } \ No newline at end of file Index: model/org/eclipse/jdt/internal/core/util/messages.properties =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/messages.properties,v retrieving revision 1.72 diff -u -r1.72 messages.properties --- model/org/eclipse/jdt/internal/core/util/messages.properties 27 May 2008 23:40:19 -0000 1.72 +++ model/org/eclipse/jdt/internal/core/util/messages.properties 9 Oct 2008 11:46:23 -0000 @@ -368,3 +368,6 @@ classfileformat_exceptiontableentry = [pc: {0}, pc: {1}] -> {2} when : {3} classfileformat_linenumbertableentry = [pc: {0}, line: {1}] classfileformat_localvariabletableentry = [pc: {0}, pc: {1}] local: {2} index: {3} type: {4} + +### Eclipse Java Core completion messages. +engine_completing = Computing proposals... Index: model/org/eclipse/jdt/internal/core/util/Messages.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/util/Messages.java,v retrieving revision 1.23 diff -u -r1.23 Messages.java --- model/org/eclipse/jdt/internal/core/util/Messages.java 27 Jun 2008 16:03:56 -0000 1.23 +++ model/org/eclipse/jdt/internal/core/util/Messages.java 9 Oct 2008 11:46:23 -0000 @@ -218,6 +218,7 @@ public static String importRewrite_processDescription; public static String correction_nullRequestor; public static String correction_nullUnit; + public static String engine_completing; public static String engine_searching; public static String engine_searching_indexing; public static String engine_searching_matching; Index: model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java,v retrieving revision 1.60 diff -u -r1.60 EvaluationContextWrapper.java --- model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java 9 Oct 2008 08:45:46 -0000 1.60 +++ model/org/eclipse/jdt/internal/core/eval/EvaluationContextWrapper.java 9 Oct 2008 11:46:23 -0000 @@ -15,13 +15,6 @@ import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.*; -import org.eclipse.jdt.core.ICompilationUnit; -import org.eclipse.jdt.core.IImportDeclaration; -import org.eclipse.jdt.core.IJavaElement; -import org.eclipse.jdt.core.IJavaModelStatusConstants; -import org.eclipse.jdt.core.IJavaProject; -import org.eclipse.jdt.core.IType; -import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.compiler.IProblem; import org.eclipse.jdt.core.eval.ICodeSnippetRequestor; import org.eclipse.jdt.core.eval.IEvaluationContext; @@ -30,12 +23,6 @@ import org.eclipse.jdt.internal.compiler.env.INameEnvironment; import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; import org.eclipse.jdt.internal.core.*; -import org.eclipse.jdt.internal.core.BinaryType; -import org.eclipse.jdt.internal.core.ClassFile; -import org.eclipse.jdt.internal.core.JavaModelStatus; -import org.eclipse.jdt.internal.core.JavaProject; -import org.eclipse.jdt.internal.core.SelectionRequestor; -import org.eclipse.jdt.internal.core.SourceMapper; import org.eclipse.jdt.internal.core.builder.NameEnvironment; import org.eclipse.jdt.internal.core.builder.ProblemFactory; import org.eclipse.jdt.internal.eval.EvaluationContext; @@ -100,9 +87,26 @@ codeComplete(codeSnippet, position, requestor, DefaultWorkingCopyOwner.PRIMARY); } /** + * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeComplete(String, int, CompletionRequestor, IProgressMonitor) + */ +public void codeComplete(String codeSnippet, int position, CompletionRequestor requestor, IProgressMonitor monitor) throws JavaModelException { + codeComplete(codeSnippet, position, requestor, DefaultWorkingCopyOwner.PRIMARY, null); +} +/** * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeComplete(String, int, CompletionRequestor, WorkingCopyOwner) */ public void codeComplete(String codeSnippet, int position, CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException { + codeComplete(codeSnippet, position, requestor, owner, null); +} +/** + * @see org.eclipse.jdt.core.eval.IEvaluationContext#codeComplete(String, int, CompletionRequestor, WorkingCopyOwner, IProgressMonitor) + */ +public void codeComplete( + String codeSnippet, + int position, + CompletionRequestor requestor, + WorkingCopyOwner owner, + IProgressMonitor monitor) throws JavaModelException { SearchableEnvironment environment = this.project.newSearchableNameEnvironment(owner); this.context.complete( codeSnippet.toCharArray(), @@ -111,7 +115,8 @@ requestor, this.project.getOptions(true), this.project, - owner + owner, + monitor ); } /** Index: model/org/eclipse/jdt/core/ICodeAssist.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/ICodeAssist.java,v retrieving revision 1.35 diff -u -r1.35 ICodeAssist.java --- model/org/eclipse/jdt/core/ICodeAssist.java 27 Jun 2008 16:04:01 -0000 1.35 +++ model/org/eclipse/jdt/core/ICodeAssist.java 9 Oct 2008 11:46:21 -0000 @@ -10,6 +10,8 @@ *******************************************************************************/ package org.eclipse.jdt.core; +import org.eclipse.core.runtime.IProgressMonitor; + /** * Common protocol for Java elements that support source code assist and code * resolve. @@ -82,6 +84,29 @@ */ void codeComplete(int offset, CompletionRequestor requestor) throws JavaModelException; + + /** + * Performs code completion at the given offset position in this compilation unit, + * reporting results to the given completion requestor. The offset + * is the 0-based index of the character, after which code assist is desired. + * An offset of -1 indicates to code assist at the beginning of this + * compilation unit. + *

+ * + * @param offset the given offset position + * @param requestor the given completion requestor + * @param monitor the progress monitor used to report progress + * @exception JavaModelException if code assist could not be performed. Reasons include:

    + *
  • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
  • + *
  • The position specified is < -1 or is greater than this compilation unit's + * source length (INDEX_OUT_OF_BOUNDS) + *
+ * + * @exception IllegalArgumentException if requestor is null + * @since 3.5 + */ + void codeComplete(int offset, CompletionRequestor requestor, IProgressMonitor monitor) + throws JavaModelException; /** * Performs code completion at the given offset position in this compilation unit, @@ -141,6 +166,36 @@ */ void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException; + + /** + * Performs code completion at the given offset position in this compilation unit, + * reporting results to the given completion requestor. The offset + * is the 0-based index of the character, after which code assist is desired. + * An offset of -1 indicates to code assist at the beginning of this + * compilation unit. + * It considers types in the working copies with the given owner first. In other words, + * the owner's working copies will take precedence over their original compilation units + * in the workspace. + *

+ * Note that if a working copy is empty, it will be as if the original compilation + * unit had been deleted. + *

+ * + * @param offset the given offset position + * @param requestor the given completion requestor + * @param owner the owner of working copies that take precedence over their original compilation units + * @param monitor the progress monitor used to report progress + * @exception JavaModelException if code assist could not be performed. Reasons include:
    + *
  • This Java element does not exist (ELEMENT_DOES_NOT_EXIST)
  • + *
  • The position specified is < -1 or is greater than this compilation unit's + * source length (INDEX_OUT_OF_BOUNDS) + *
+ * + * @exception IllegalArgumentException if requestor is null + * @since 3.5 + */ + void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor) + throws JavaModelException; /** * Returns the Java elements corresponding to the given selected text in this compilation unit. Index: model/org/eclipse/jdt/core/IType.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/model/org/eclipse/jdt/core/IType.java,v retrieving revision 1.63 diff -u -r1.63 IType.java --- model/org/eclipse/jdt/core/IType.java 27 Jun 2008 16:04:01 -0000 1.63 +++ model/org/eclipse/jdt/core/IType.java 9 Oct 2008 11:46:22 -0000 @@ -154,6 +154,44 @@ boolean isStatic, CompletionRequestor requestor) throws JavaModelException; + + /** + * Do code completion inside a code snippet in the context of the current type. + * + * If the type can access to his source code and the insertion position is valid, + * then completion is performed against source. Otherwise the completion is performed + * against type structure and given locals variables. + * + * @param snippet the code snippet + * @param insertion the position with in source where the snippet + * is inserted. This position must not be in comments. + * A possible value is -1, if the position is not known. + * @param position the position within snippet where the user + * is performing code assist. + * @param localVariableTypeNames an array (possibly empty) of fully qualified + * type names of local variables visible at the current scope + * @param localVariableNames an array (possibly empty) of local variable names + * that are visible at the current scope + * @param localVariableModifiers an array (possible empty) of modifiers for + * local variables + * @param isStatic whether the current scope is in a static context + * @param requestor the completion requestor + * @param monitor the progress monitor used to report progress + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @since 3.5 + */ + void codeComplete( + char[] snippet, + int insertion, + int position, + char[][] localVariableTypeNames, + char[][] localVariableNames, + int[] localVariableModifiers, + boolean isStatic, + CompletionRequestor requestor, + IProgressMonitor monitor) + throws JavaModelException; /** * Do code completion inside a code snippet in the context of the current type. @@ -199,6 +237,53 @@ CompletionRequestor requestor, WorkingCopyOwner owner) throws JavaModelException; + + /** + * Do code completion inside a code snippet in the context of the current type. + * It considers types in the working copies with the given owner first. In other words, + * the owner's working copies will take precedence over their original compilation units + * in the workspace. + *

+ * Note that if a working copy is empty, it will be as if the original compilation + * unit had been deleted. + *

+ * If the type can access to his source code and the insertion position is valid, + * then completion is performed against source. Otherwise the completion is performed + * against type structure and given locals variables. + *

+ * + * @param snippet the code snippet + * @param insertion the position with in source where the snippet + * is inserted. This position must not be in comments. + * A possible value is -1, if the position is not known. + * @param position the position with in snippet where the user + * is performing code assist. + * @param localVariableTypeNames an array (possibly empty) of fully qualified + * type names of local variables visible at the current scope + * @param localVariableNames an array (possibly empty) of local variable names + * that are visible at the current scope + * @param localVariableModifiers an array (possible empty) of modifiers for + * local variables + * @param isStatic whether the current scope is in a static context + * @param requestor the completion requestor + * @param owner the owner of working copies that take precedence over their original compilation units + * @param monitor the progress monitor used to report progress + * @exception JavaModelException if this element does not exist or if an + * exception occurs while accessing its corresponding resource. + * @since 3.5 + */ + void codeComplete( + char[] snippet, + int insertion, + int position, + char[][] localVariableTypeNames, + char[][] localVariableNames, + int[] localVariableModifiers, + boolean isStatic, + CompletionRequestor requestor, + WorkingCopyOwner owner, + IProgressMonitor monitor) + throws JavaModelException; /** Index: eval/org/eclipse/jdt/internal/eval/EvaluationContext.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core/eval/org/eclipse/jdt/internal/eval/EvaluationContext.java,v retrieving revision 1.62 diff -u -r1.62 EvaluationContext.java --- eval/org/eclipse/jdt/internal/eval/EvaluationContext.java 9 Oct 2008 08:45:46 -0000 1.62 +++ eval/org/eclipse/jdt/internal/eval/EvaluationContext.java 9 Oct 2008 11:46:21 -0000 @@ -13,6 +13,7 @@ import java.util.Locale; import java.util.Map; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.CompletionRequestor; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.WorkingCopyOwner; @@ -104,8 +105,19 @@ * * @param owner * the owner of working copies that take precedence over their original compilation units - */ -public void complete(char[] codeSnippet, int completionPosition, SearchableEnvironment environment, CompletionRequestor requestor, Map options, final IJavaProject project, WorkingCopyOwner owner) { + * + * @param monitor + * the progress monitor used to report progress + */ +public void complete( + char[] codeSnippet, + int completionPosition, + SearchableEnvironment environment, + CompletionRequestor requestor, + Map options, + final IJavaProject project, + WorkingCopyOwner owner, + IProgressMonitor monitor) { try { IRequestor variableRequestor = new IRequestor() { public boolean acceptClassFiles(ClassFile[] classFiles, char[] codeSnippetClassName) { @@ -148,7 +160,7 @@ } }; - CompletionEngine engine = new CompletionEngine(environment, mapper.getCompletionRequestor(requestor), options, project, owner); + CompletionEngine engine = new CompletionEngine(environment, mapper.getCompletionRequestor(requestor), options, project, owner, monitor); if (this.installedVars != null) { IBinaryType binaryType = getRootCodeSnippetBinary(); Index: codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java =================================================================== RCS file: codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java diff -N codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ codeassist/org/eclipse/jdt/internal/codeassist/complete/CompletionOnBranchStatementLabel.java 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2005, 2006 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.complete; + +import org.eclipse.jdt.internal.compiler.ast.BranchStatement; +import org.eclipse.jdt.internal.compiler.flow.FlowContext; +import org.eclipse.jdt.internal.compiler.flow.FlowInfo; +import org.eclipse.jdt.internal.compiler.lookup.BlockScope; + +public class CompletionOnBranchStatementLabel extends BranchStatement { + public static final int BREAK = 1; + public static final int CONTINUE = 2; + + private int kind; + public char[][] possibleLabels; + + public CompletionOnBranchStatementLabel(int kind, char[] l, int s, int e, char[][] possibleLabels) { + super(l, s, e); + this.kind = kind; + this.possibleLabels = possibleLabels; + } + + public FlowInfo analyseCode(BlockScope currentScope, + FlowContext flowContext, FlowInfo flowInfo) { + // Is never called + return null; + } + + public void resolve(BlockScope scope) { + throw new CompletionNodeFound(this, scope); + } + public StringBuffer printStatement(int indent, StringBuffer output) { + printIndent(indent, output); + if(this.kind == CONTINUE) { + output.append("continue "); //$NON-NLS-1$ + } else { + output.append("break "); //$NON-NLS-1$ + } + output.append(";"); //$NON-NLS-1$ + } + +} #P org.eclipse.jdt.core.tests.model Index: src/org/eclipse/jdt/core/tests/model/CompletionTests.java =================================================================== RCS file: /cvsroot/eclipse/org.eclipse.jdt.core.tests.model/src/org/eclipse/jdt/core/tests/model/CompletionTests.java,v retrieving revision 1.188 diff -u -r1.188 CompletionTests.java --- src/org/eclipse/jdt/core/tests/model/CompletionTests.java 9 Sep 2008 12:43:37 -0000 1.188 +++ src/org/eclipse/jdt/core/tests/model/CompletionTests.java 9 Oct 2008 11:46:36 -0000 @@ -16,6 +16,9 @@ import junit.framework.Test; import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.jdt.core.CompletionContext; import org.eclipse.jdt.core.CompletionProposal; import org.eclipse.jdt.core.CompletionRequestor; @@ -55,6 +58,63 @@ char[] varClassName = ((EvaluationContextWrapper)context).getVarClassName(); return Signature.createTypeSignature(varClassName, true); } +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=247433 +public void testAbortCompletion1() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/AbortCompletion.java", + "public class AbortCompletion {\n"+ + " void foo() {\n"+ + " Objec\n"+ + " }\n"+ + "}\n"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "Objec"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + IProgressMonitor monitor = new NullProgressMonitor(); + try { + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, monitor); + assertResults( + "Object[TYPE_REF]{Object, java.lang, Ljava.lang.Object;, null, " + (R_DEFAULT + R_RESOLVED + R_INTERESTING + R_CASE + R_UNQUALIFIED + R_NON_RESTRICTED) + "}", + requestor.getResults()); + } catch (OperationCanceledException e) { + assertTrue("Should not be cancelled", false); + } + +} + +//https://bugs.eclipse.org/bugs/show_bug.cgi?id=247433 +public void testAbortCompletion2() throws JavaModelException { + this.workingCopies = new ICompilationUnit[1]; + this.workingCopies[0] = getWorkingCopy( + "/Completion/src/AbortCompletion.java", + "public class AbortCompletion {\n"+ + " void foo() {\n"+ + " Objec\n"+ + " }\n"+ + "}\n"); + + CompletionTestsRequestor2 requestor = new CompletionTestsRequestor2(); + + String str = this.workingCopies[0].getSource(); + String completeBehind = "Objec"; + int cursorLocation = str.lastIndexOf(completeBehind) + completeBehind.length(); + + try { + IProgressMonitor monitor = new NullProgressMonitor(); + monitor.setCanceled(true); /*force completion to abort*/ + this.workingCopies[0].codeComplete(cursorLocation, requestor, this.wcOwner, monitor); + assertTrue("Should not be cancelled", false); + } catch (OperationCanceledException e) { + assertResults( + "", + requestor.getResults()); + } +} + //https://bugs.eclipse.org/bugs/show_bug.cgi?id=164311 public void testBug164311() throws JavaModelException { this.workingCopies = new ICompilationUnit[1];