| /******************************************************************************* |
| * Copyright (c) 2000, 2005 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.codeassist; |
| |
| import java.util.Locale; |
| import java.util.Map; |
| |
| import org.eclipse.jdt.core.CompletionContext; |
| import org.eclipse.jdt.core.CompletionProposal; |
| import org.eclipse.jdt.core.CompletionRequestor; |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.IAccessRule; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.Signature; |
| import org.eclipse.jdt.core.compiler.CharOperation; |
| import org.eclipse.jdt.core.compiler.IProblem; |
| |
| import org.eclipse.jdt.internal.codeassist.complete.*; |
| import org.eclipse.jdt.internal.codeassist.impl.AssistParser; |
| import org.eclipse.jdt.internal.codeassist.impl.Engine; |
| import org.eclipse.jdt.internal.codeassist.impl.Keywords; |
| import org.eclipse.jdt.internal.compiler.CompilationResult; |
| import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; |
| import org.eclipse.jdt.internal.compiler.ast.*; |
| import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; |
| import org.eclipse.jdt.internal.compiler.env.*; |
| import org.eclipse.jdt.internal.compiler.lookup.*; |
| import org.eclipse.jdt.internal.compiler.parser.Scanner; |
| import org.eclipse.jdt.internal.compiler.parser.SourceTypeConverter; |
| import org.eclipse.jdt.internal.compiler.parser.TerminalTokens; |
| import org.eclipse.jdt.internal.compiler.problem.AbortCompilation; |
| import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; |
| import org.eclipse.jdt.internal.compiler.problem.ProblemReporter; |
| import org.eclipse.jdt.internal.compiler.util.SuffixConstants; |
| import org.eclipse.jdt.internal.compiler.util.HashtableOfObject; |
| import org.eclipse.jdt.internal.compiler.util.ObjectVector; |
| import org.eclipse.jdt.internal.core.BasicCompilationUnit; |
| import org.eclipse.jdt.internal.core.INamingRequestor; |
| import org.eclipse.jdt.internal.core.InternalNamingConventions; |
| import org.eclipse.jdt.internal.core.SourceMethod; |
| import org.eclipse.jdt.internal.core.SourceMethodElementInfo; |
| import org.eclipse.jdt.internal.core.SourceType; |
| import org.eclipse.jdt.internal.core.BinaryTypeConverter; |
| import org.eclipse.jdt.internal.core.SearchableEnvironment; |
| import org.eclipse.jdt.internal.core.SourceTypeElementInfo; |
| |
| /** |
| * This class is the entry point for source completions. |
| * It contains two public APIs used to call CodeAssist on a given source with |
| * a given environment, assisting position and storage (and possibly options). |
| */ |
| public final class CompletionEngine |
| extends Engine |
| implements ISearchRequestor, TypeConstants , TerminalTokens , RelevanceConstants, SuffixConstants { |
| |
| public HashtableOfObject typeCache; |
| |
| public static boolean DEBUG = false; |
| public static boolean PERF = 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 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; |
| int uninterestingBindingsPtr = -1; |
| Binding[] uninterestingBindings = new Binding[1]; |
| int forbbidenBindingsPtr = -1; |
| Binding[] forbbidenBindings = new Binding[1]; |
| |
| boolean assistNodeIsClass; |
| boolean assistNodeIsEnum; |
| boolean assistNodeIsException; |
| boolean assistNodeIsInterface; |
| boolean assistNodeIsAnnotation; |
| |
| IJavaProject javaProject; |
| CompletionParser parser; |
| CompletionRequestor requestor; |
| ProblemReporter problemReporter; |
| char[] source; |
| char[] completionToken; |
| char[] qualifiedCompletionToken; |
| boolean resolvingImports = false; |
| boolean insideQualifiedReference = false; |
| boolean noProposal = true; |
| IProblem problem = null; |
| int startPosition, actualCompletionPosition, endPosition, offset; |
| HashtableOfObject knownPkgs = new HashtableOfObject(10); |
| HashtableOfObject knownTypes = new HashtableOfObject(10); |
| Scanner nameScanner; |
| |
| /* |
| static final char[][] mainDeclarations = |
| new char[][] { |
| "package".toCharArray(), |
| "import".toCharArray(), |
| "abstract".toCharArray(), |
| "final".toCharArray(), |
| "public".toCharArray(), |
| "class".toCharArray(), |
| "interface".toCharArray()}; |
| |
| static final char[][] modifiers = // may want field, method, type & member type modifiers |
| new char[][] { |
| "abstract".toCharArray(), |
| "final".toCharArray(), |
| "native".toCharArray(), |
| "public".toCharArray(), |
| "protected".toCharArray(), |
| "private".toCharArray(), |
| "static".toCharArray(), |
| "strictfp".toCharArray(), |
| "synchronized".toCharArray(), |
| "transient".toCharArray(), |
| "volatile".toCharArray()}; |
| */ |
| static final char[][] baseTypes = new char[][] { |
| "boolean".toCharArray(), //$NON-NLS-1$ |
| "byte".toCharArray(), //$NON-NLS-1$ |
| "char".toCharArray(), //$NON-NLS-1$ |
| "double".toCharArray(), //$NON-NLS-1$ |
| "float".toCharArray(), //$NON-NLS-1$ |
| "int".toCharArray(), //$NON-NLS-1$ |
| "long".toCharArray(), //$NON-NLS-1$ |
| "short".toCharArray(), //$NON-NLS-1$ |
| "void".toCharArray(), //$NON-NLS-1$ |
| }; |
| |
| static final char[] classField = "class".toCharArray(); //$NON-NLS-1$ |
| static final char[] lengthField = "length".toCharArray(); //$NON-NLS-1$ |
| static final char[] cloneMethod = "clone".toCharArray(); //$NON-NLS-1$ |
| static final char[] THIS = "this".toCharArray(); //$NON-NLS-1$ |
| static final char[] THROWS = "throws".toCharArray(); //$NON-NLS-1$ |
| |
| static InvocationSite FakeInvocationSite = new InvocationSite(){ |
| public TypeBinding[] genericTypeArguments() { return null; } |
| public boolean isSuperAccess(){ return false; } |
| public boolean isTypeAccess(){ return false; } |
| public void setActualReceiverType(ReferenceBinding receiverType) {} |
| public void setDepth(int depth){} |
| public void setFieldIndex(int depth){} |
| public int sourceStart() { return 0; } |
| public int sourceEnd() { return 0; } |
| }; |
| |
| /** |
| * The CompletionEngine is responsible for computing source completions. |
| * |
| * It requires a searchable name environment, which supports some |
| * specific search APIs, and a requestor to feed back the results to a UI. |
| * |
| * @param nameEnvironment org.eclipse.jdt.internal.codeassist.ISearchableNameEnvironment |
| * used to resolve type/package references and search for types/packages |
| * based on partial names. |
| * |
| * @param requestor org.eclipse.jdt.internal.codeassist.ICompletionRequestor |
| * since the engine might produce answers of various forms, the engine |
| * is associated with a requestor able to accept all possible completions. |
| * |
| * @param settings java.util.Map |
| * set of options used to configure the code assist engine. |
| */ |
| public CompletionEngine( |
| SearchableEnvironment nameEnvironment, |
| CompletionRequestor requestor, |
| Map settings, |
| IJavaProject javaProject) { |
| super(settings); |
| this.javaProject = javaProject; |
| this.requestor = requestor; |
| this.nameEnvironment = nameEnvironment; |
| this.typeCache = new HashtableOfObject(5); |
| |
| this.problemReporter = new ProblemReporter( |
| DefaultErrorHandlingPolicies.proceedWithAllProblems(), |
| this.compilerOptions, |
| new DefaultProblemFactory(Locale.getDefault()) { |
| int lastErrorStart; |
| |
| public IProblem createProblem( |
| char[] originatingFileName, |
| int problemId, |
| String[] problemArguments, |
| String[] messageArguments, |
| int severity, |
| int start, |
| int end, |
| int lineNumber) { |
| |
| IProblem pb = super.createProblem( |
| originatingFileName, |
| problemId, |
| problemArguments, |
| messageArguments, |
| severity, |
| start, |
| end, |
| lineNumber); |
| // TODO (david) problems could be detected in other units which got requested (see CompilationUnitProblemFinder) |
| if(CompletionEngine.this.actualCompletionPosition > start |
| && this.lastErrorStart < start |
| && pb.isError() |
| && (pb.getID() & IProblem.Syntax) == 0) { |
| |
| CompletionEngine.this.problem = pb; |
| this.lastErrorStart = start; |
| } |
| |
| return pb; |
| } |
| |
| }); |
| this.lookupEnvironment = |
| new LookupEnvironment(this, this.compilerOptions, this.problemReporter, nameEnvironment); |
| this.parser = |
| new CompletionParser(this.problemReporter); |
| this.nameScanner = |
| new Scanner( |
| false /*comment*/, |
| false /*whitespace*/, |
| false /*nls*/, |
| this.compilerOptions.sourceLevel, |
| null /*taskTags*/, |
| null/*taskPriorities*/, |
| true/*taskCaseSensitive*/); |
| } |
| |
| /** |
| * One result of the search consists of a new type. |
| * |
| * NOTE - All package and type names are presented in their readable form: |
| * Package names are in the form "a.b.c". |
| * Nested type names are in the qualified form "A.I". |
| * The default package is represented by an empty array. |
| */ |
| public void acceptType( |
| char[] packageName, |
| char[] typeName, |
| int modifiers, |
| AccessRestriction accessRestriction) { |
| |
| char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.'); |
| char[] completionName = fullyQualifiedName; |
| |
| if (this.knownTypes.containsKey(completionName)) return; |
| |
| this.knownTypes.put(completionName, this); |
| |
| int accessibility = IAccessRule.K_ACCESSIBLE; |
| if(accessRestriction != null) { |
| switch (accessRestriction.getProblemId()) { |
| case IProblem.ForbiddenReference: |
| if(this.options.checkForbiddenReference) return; |
| accessibility = IAccessRule.K_NON_ACCESSIBLE; |
| break; |
| case IProblem.DiscouragedReference: |
| if(this.options.checkDiscouragedReference) return; |
| accessibility = IAccessRule.K_DISCOURAGED; |
| break; |
| } |
| } |
| |
| boolean isQualified = true; |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForRestrictions(accessibility); |
| if (this.resolvingImports) { |
| completionName = CharOperation.concat(completionName, new char[] { ';' }); |
| relevance += computeRelevanceForCaseMatching(this.completionToken, fullyQualifiedName); |
| } else { |
| if (mustQualifyType(packageName, typeName)) { |
| 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 = typeName; |
| isQualified = false; |
| } |
| relevance += computeRelevanceForCaseMatching(this.completionToken, typeName); |
| relevance += computeRelevanceForExpectingType(packageName, typeName); |
| relevance += computeRelevanceForQualification(isQualified); |
| |
| int kind = modifiers & (IConstants.AccInterface | IConstants.AccEnum | IConstants.AccAnnotation); |
| switch (kind) { |
| case IConstants.AccAnnotation: |
| case IConstants.AccAnnotation | IConstants.AccInterface: |
| relevance += computeRelevanceForAnnotation(); |
| relevance += computeRelevanceForInterface(); |
| break; |
| case IConstants.AccEnum: |
| relevance += computeRelevanceForEnum(); |
| break; |
| case IConstants.AccInterface: |
| relevance += computeRelevanceForInterface(); |
| break; |
| default: |
| relevance += computeRelevanceForClass(); |
| relevance += computeRelevanceForException(typeName); |
| break; |
| } |
| } |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| 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.setRelevance(relevance); |
| proposal.setAccessibility(accessibility); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| |
| /** |
| * 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); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(this.qualifiedCompletionToken == null ? this.completionToken : this.qualifiedCompletionToken, packageName); |
| relevance += computeRelevanceForQualification(true); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.PACKAGE_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(packageName); |
| proposal.setPackageName(packageName); |
| proposal.setCompletion( |
| this.resolvingImports |
| ? CharOperation.concat(packageName, new char[] { '.', '*', ';' }) |
| : packageName); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| |
| private void buildContext() { |
| CompletionContext context = new CompletionContext(); |
| |
| // build expected types context |
| if (this.expectedTypesPtr > -1) { |
| int length = this.expectedTypesPtr + 1; |
| char[][] expTypes = new char[length][]; |
| char[][] expKeys = new char[length][]; |
| for (int i = 0; i < length; i++) { |
| expTypes[i] = getSignature(this.expectedTypes[i]); |
| expKeys[i] = this.expectedTypes[i].computeUniqueKey(); |
| } |
| context.setExpectedTypesSignatures(expTypes); |
| context.setExpectedTypesKeys(expKeys); |
| } |
| |
| this.requestor.acceptContext(context); |
| } |
| |
| private void complete(ASTNode astNode, ASTNode astNodeParent, Binding qualifiedBinding, Scope scope, boolean insideTypeAnnotation) { |
| |
| setSourceRange(astNode.sourceStart, astNode.sourceEnd); |
| |
| scope = computeForbiddenBindings(astNode, astNodeParent, scope); |
| computeUninterestingBindings(astNodeParent, scope); |
| if(astNodeParent != null) { |
| if(!isValidParent(astNodeParent, astNode, scope)) return; |
| computeExpectedTypes(astNodeParent, astNode, scope); |
| } |
| |
| buildContext(); |
| |
| if (astNode instanceof CompletionOnFieldType) { |
| |
| CompletionOnFieldType field = (CompletionOnFieldType) astNode; |
| CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) field.type; |
| this.completionToken = type.token; |
| setSourceRange(type.sourceStart, type.sourceEnd); |
| |
| findTypesAndPackages(this.completionToken, scope); |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| findKeywordsForMember(this.completionToken, field.modifiers); |
| } |
| |
| if(!field.isLocalVariable && field.modifiers == CompilerModifiers.AccDefault) { |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) { |
| findMethods(this.completionToken,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false,false,true); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) { |
| proposeNewMethod(this.completionToken, scope.enclosingSourceType()); |
| } |
| } |
| } else { |
| if(astNode instanceof CompletionOnMethodReturnType) { |
| |
| CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode; |
| SingleTypeReference type = (CompletionOnSingleTypeReference) method.returnType; |
| this.completionToken = type.token; |
| setSourceRange(type.sourceStart, type.sourceEnd); |
| findTypesAndPackages(this.completionToken, scope.parent); |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| findKeywordsForMember(this.completionToken, method.modifiers); |
| } |
| |
| if(method.modifiers == CompilerModifiers.AccDefault) { |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) { |
| findMethods(this.completionToken,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false,false,true); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) { |
| proposeNewMethod(this.completionToken, scope.enclosingSourceType()); |
| } |
| } |
| } else { |
| |
| if (astNode instanceof CompletionOnSingleNameReference) { |
| 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.findEnumConstant(this.completionToken, (SwitchStatement) astNodeParent); |
| } |
| } else { |
| if(this.expectedTypesPtr > -1 && this.expectedTypes[0].isAnnotationType()) { |
| findTypesAndPackages(this.completionToken, scope); |
| } else { |
| findVariablesAndMethods( |
| this.completionToken, |
| scope, |
| singleNameReference, |
| scope, |
| insideTypeAnnotation, |
| singleNameReference.isInsideAnnotationAttribute); |
| // can be the start of a qualified type name |
| findTypesAndPackages(this.completionToken, scope); |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| if(this.completionToken != null && this.completionToken.length != 0) { |
| findKeywords(this.completionToken, singleNameReference.possibleKeywords); |
| } 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); |
| } |
| } |
| } |
| } |
| } else { |
| |
| if (astNode instanceof CompletionOnSingleTypeReference) { |
| |
| this.completionToken = ((CompletionOnSingleTypeReference) astNode).token; |
| |
| this.assistNodeIsClass = astNode instanceof CompletionOnClassReference; |
| this.assistNodeIsEnum = this.assistNodeIsClass; |
| this.assistNodeIsException = astNode instanceof CompletionOnExceptionReference; |
| this.assistNodeIsInterface = astNode instanceof CompletionOnInterfaceReference; |
| |
| // can be the start of a qualified type name |
| if (qualifiedBinding == null) { |
| findTypesAndPackages(this.completionToken, scope); |
| } else { |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| findMemberTypes( |
| this.completionToken, |
| (ReferenceBinding) qualifiedBinding, |
| scope, |
| scope.enclosingSourceType(), |
| false, |
| new ObjectVector()); |
| } |
| } |
| } else { |
| |
| if (astNode instanceof CompletionOnQualifiedNameReference) { |
| |
| this.insideQualifiedReference = true; |
| CompletionOnQualifiedNameReference ref = |
| (CompletionOnQualifiedNameReference) astNode; |
| this.completionToken = ref.completionIdentifier; |
| long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1]; |
| |
| if (qualifiedBinding instanceof VariableBinding) { |
| |
| setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); |
| TypeBinding receiverType = ((VariableBinding) qualifiedBinding).type; |
| if (receiverType != null) { |
| findFieldsAndMethods(this.completionToken, receiverType, scope, ref, scope,false,false); |
| } |
| |
| } else { |
| |
| if (qualifiedBinding instanceof ReferenceBinding) { |
| boolean isInsideAnnotationAttribute = ref.isInsideAnnotationAttribute; |
| ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding; |
| setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); |
| |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| findMemberTypes(this.completionToken, receiverType, scope, scope.enclosingSourceType(), false, new ObjectVector()); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| findClassField(this.completionToken, (TypeBinding) qualifiedBinding, scope); |
| } |
| |
| MethodScope methodScope = null; |
| if(!isInsideAnnotationAttribute && |
| !this.requestor.isIgnored(CompletionProposal.KEYWORD) && |
| ((scope instanceof MethodScope && !((MethodScope)scope).isStatic) |
| || ((methodScope = scope.enclosingMethodScope()) != null && !methodScope.isStatic))) { |
| if(this.completionToken.length > 0) { |
| findKeywords(this.completionToken, new char[][]{Keywords.THIS}); |
| } else { |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(this.completionToken, Keywords.THIS); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywords |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition); |
| proposal.setName(Keywords.THIS); |
| proposal.setCompletion(Keywords.THIS); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| findFields( |
| this.completionToken, |
| receiverType, |
| scope, |
| new ObjectVector(), |
| new ObjectVector(), |
| true, |
| ref, |
| scope, |
| false, |
| true); |
| } |
| |
| if(!isInsideAnnotationAttribute && !this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| findMethods( |
| this.completionToken, |
| null, |
| receiverType, |
| scope, |
| new ObjectVector(), |
| true, |
| false, |
| false, |
| ref, |
| scope, |
| false, |
| false, |
| true); |
| } |
| |
| } else { |
| |
| if (qualifiedBinding instanceof PackageBinding) { |
| |
| setSourceRange(astNode.sourceStart, (int) completionPosition); |
| // replace to the end of the completion identifier |
| findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding); |
| } |
| } |
| } |
| |
| } else { |
| |
| if (astNode instanceof CompletionOnQualifiedTypeReference) { |
| |
| this.insideQualifiedReference = true; |
| |
| this.assistNodeIsClass = astNode instanceof CompletionOnQualifiedClassReference; |
| this.assistNodeIsEnum = this.assistNodeIsClass; |
| this.assistNodeIsException = astNode instanceof CompletionOnQualifiedExceptionReference; |
| this.assistNodeIsInterface = astNode instanceof CompletionOnQualifiedInterfaceReference; |
| |
| CompletionOnQualifiedTypeReference ref = |
| (CompletionOnQualifiedTypeReference) astNode; |
| this.completionToken = ref.completionIdentifier; |
| long completionPosition = ref.sourcePositions[ref.tokens.length]; |
| |
| // get the source positions of the completion identifier |
| if (qualifiedBinding instanceof ReferenceBinding) { |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); |
| findMemberTypes( |
| this.completionToken, |
| (ReferenceBinding) qualifiedBinding, |
| scope, |
| scope.enclosingSourceType(), |
| false, |
| new ObjectVector()); |
| } |
| |
| } else { |
| |
| if (qualifiedBinding instanceof PackageBinding) { |
| |
| setSourceRange(astNode.sourceStart, (int) completionPosition); |
| // replace to the end of the completion identifier |
| findTypesAndSubpackages(this.completionToken, (PackageBinding) qualifiedBinding); |
| } |
| } |
| |
| } else { |
| |
| if (astNode instanceof CompletionOnMemberAccess) { |
| this.insideQualifiedReference = true; |
| CompletionOnMemberAccess access = (CompletionOnMemberAccess) astNode; |
| long completionPosition = access.nameSourcePosition; |
| setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); |
| |
| this.completionToken = access.token; |
| |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| findKeywords(this.completionToken, new char[][]{Keywords.NEW}); |
| } |
| |
| findFieldsAndMethods( |
| this.completionToken, |
| (TypeBinding) qualifiedBinding, |
| scope, |
| access, |
| scope, |
| false, |
| access.receiver instanceof SuperReference); |
| |
| } else { |
| |
| if (astNode instanceof CompletionOnMessageSend) { |
| setSourceRange(astNode.sourceStart, astNode.sourceEnd, false); |
| |
| CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode; |
| TypeBinding[] argTypes = |
| computeTypes(messageSend.arguments, (BlockScope) scope); |
| this.completionToken = messageSend.selector; |
| if (qualifiedBinding == null) { |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| findImplicitMessageSends(this.completionToken, argTypes, scope, messageSend, scope); |
| } |
| } else { |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| findMethods( |
| this.completionToken, |
| argTypes, |
| (ReferenceBinding) qualifiedBinding, |
| scope, |
| new ObjectVector(), |
| false, |
| true, |
| false, |
| messageSend, |
| scope, |
| false, |
| messageSend.receiver instanceof SuperReference, |
| true); |
| } |
| } |
| |
| } else { |
| |
| if (astNode instanceof CompletionOnExplicitConstructorCall) { |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| setSourceRange(astNode.sourceStart, astNode.sourceEnd, false); |
| |
| CompletionOnExplicitConstructorCall constructorCall = |
| (CompletionOnExplicitConstructorCall) astNode; |
| TypeBinding[] argTypes = |
| computeTypes(constructorCall.arguments, (BlockScope) scope); |
| findConstructors( |
| (ReferenceBinding) qualifiedBinding, |
| argTypes, |
| scope, |
| constructorCall, |
| false); |
| } |
| } else { |
| |
| if (astNode instanceof CompletionOnQualifiedAllocationExpression) { |
| setSourceRange(astNode.sourceStart, astNode.sourceEnd, false); |
| |
| CompletionOnQualifiedAllocationExpression allocExpression = |
| (CompletionOnQualifiedAllocationExpression) astNode; |
| TypeBinding[] argTypes = |
| computeTypes(allocExpression.arguments, (BlockScope) scope); |
| |
| ReferenceBinding ref = (ReferenceBinding) qualifiedBinding; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF) |
| && ref.isClass() |
| && !ref.isAbstract()) { |
| findConstructors( |
| ref, |
| argTypes, |
| scope, |
| allocExpression, |
| false); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION) |
| && !ref.isFinal() |
| && !ref.isEnum()){ |
| findAnonymousType( |
| ref, |
| argTypes, |
| scope, |
| allocExpression); |
| } |
| |
| } else { |
| |
| if (astNode instanceof CompletionOnClassLiteralAccess) { |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode; |
| setSourceRange(access.classStart, access.sourceEnd); |
| |
| this.completionToken = access.completionIdentifier; |
| |
| findClassField(this.completionToken, (TypeBinding) qualifiedBinding, scope); |
| } |
| } else { |
| if(astNode instanceof CompletionOnMethodName) { |
| if(!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { |
| CompletionOnMethodName method = (CompletionOnMethodName) astNode; |
| |
| setSourceRange(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, FIELD, method.modifiers); |
| } |
| } else { |
| if (astNode instanceof CompletionOnFieldName) { |
| if(!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { |
| CompletionOnFieldName field = (CompletionOnFieldName) astNode; |
| |
| FieldBinding[] fields = scope.enclosingSourceType().fields(); |
| char[][] excludeNames = new char[fields.length][]; |
| for(int i = 0 ; i < fields.length ; i++){ |
| excludeNames[i] = fields[i].name; |
| } |
| |
| this.completionToken = field.realName; |
| |
| findVariableNames(field.realName, field.type, excludeNames, FIELD, field.modifiers); |
| } |
| } else { |
| if (astNode instanceof CompletionOnLocalName || |
| astNode instanceof CompletionOnArgumentName){ |
| if(!this.requestor.isIgnored(CompletionProposal.VARIABLE_DECLARATION)) { |
| LocalDeclaration variable = (LocalDeclaration) astNode; |
| |
| LocalVariableBinding[] locals = ((BlockScope)scope).locals; |
| char[][] excludeNames = new char[locals.length][]; |
| int localCount = 0; |
| for(int i = 0 ; i < locals.length ; i++){ |
| if(locals[i] != null) { |
| excludeNames[localCount++] = locals[i].name; |
| } |
| } |
| System.arraycopy(excludeNames, 0, excludeNames = new char[localCount][], 0, localCount); |
| |
| if(variable instanceof CompletionOnLocalName){ |
| this.completionToken = ((CompletionOnLocalName) variable).realName; |
| findVariableNames(this.completionToken, variable.type, excludeNames, LOCAL, variable.modifiers); |
| } else { |
| CompletionOnArgumentName arg = (CompletionOnArgumentName) variable; |
| this.completionToken = arg.realName; |
| findVariableNames(this.completionToken, variable.type, excludeNames, arg.isCatchArgument ? LOCAL : ARGUMENT, variable.modifiers); |
| } |
| } |
| } else { |
| if(astNode instanceof CompletionOnKeyword) { |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| CompletionOnKeyword keyword = (CompletionOnKeyword)astNode; |
| findKeywords(keyword.getToken(), keyword.getPossibleKeywords()); |
| } |
| } 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.completionToken = ref.completionIdentifier; |
| long completionPosition = ref.sourcePositions[ref.tokens.length]; |
| setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); |
| findMemberTypes( |
| this.completionToken, |
| (ReferenceBinding) qualifiedBinding, |
| scope, |
| scope.enclosingSourceType(), |
| false, |
| new ObjectVector()); |
| } |
| } else if(astNode instanceof CompletionOnMarkerAnnotationName) { |
| CompletionOnMarkerAnnotationName annot = (CompletionOnMarkerAnnotationName) astNode; |
| |
| this.assistNodeIsAnnotation = true; |
| if(annot.type instanceof CompletionOnSingleTypeReference) { |
| CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) annot.type; |
| this.completionToken = type.token; |
| setSourceRange(type.sourceStart, type.sourceEnd); |
| |
| findTypesAndPackages(this.completionToken, scope); |
| } else if(annot.type instanceof CompletionOnQualifiedTypeReference) { |
| CompletionOnQualifiedTypeReference type = (CompletionOnQualifiedTypeReference) annot.type; |
| this.completionToken = type.completionIdentifier; |
| long completionPosition = type.sourcePositions[type.tokens.length]; |
| setSourceRange((int) (completionPosition >>> 32), (int) completionPosition); |
| |
| findMemberTypes( |
| this.completionToken, |
| (ReferenceBinding) qualifiedBinding, |
| scope, |
| scope.enclosingSourceType(), |
| false, |
| new ObjectVector()); |
| } |
| } else if (astNode instanceof CompletionOnMemberValueName) { |
| if(!this.requestor.isIgnored(CompletionProposal.ANNOTATION_ATTRIBUTE_REF)) { |
| CompletionOnMemberValueName memberValuePair = (CompletionOnMemberValueName) astNode; |
| Annotation annotation = (Annotation) astNodeParent; |
| |
| this.completionToken = memberValuePair.name; |
| |
| MemberValuePair[] memberValuePairs = annotation.memberValuePairs(); |
| this.findAnnotationAttributes(this.completionToken, annotation.memberValuePairs(), (ReferenceBinding)annotation.resolvedType); |
| if(memberValuePairs == null || memberValuePairs.length == 0) { |
| if(annotation.resolvedType instanceof ReferenceBinding) { |
| MethodBinding[] methodBindings = |
| ((ReferenceBinding)annotation.resolvedType).availableMethods(); |
| if(methodBindings != null && |
| methodBindings.length == 1 && |
| CharOperation.equals(methodBindings[0].selector, VALUE)) { |
| if(this.expectedTypesPtr > -1 && this.expectedTypes[0].isAnnotationType()) { |
| findTypesAndPackages(this.completionToken, scope); |
| } else { |
| findVariablesAndMethods( |
| this.completionToken, |
| scope, |
| FakeInvocationSite, |
| scope, |
| insideTypeAnnotation, |
| true); |
| // can be the start of a qualified type name |
| findTypesAndPackages(this.completionToken, scope); |
| } |
| } |
| } |
| |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| 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(); |
| } |
| |
| CompilationResult compilationResult = new CompilationResult(topLevelType.getParent().getElementName().toCharArray(), 1, 1, this.compilerOptions.maxProblemsPerUnit); |
| |
| CompilationUnitDeclaration compilationUnit = null; |
| |
| try { |
| // TypeConverter is used instead of SourceTypeConverter because the type |
| // to convert can be a binary type or a source type |
| TypeDeclaration typeDeclaration = null; |
| if (type instanceof SourceType) { |
| SourceType sourceType = (SourceType) type; |
| ISourceType info = (ISourceType) sourceType.getElementInfo(); |
| compilationUnit = SourceTypeConverter.buildCompilationUnit( |
| new ISourceType[] {info},//sourceTypes[0] is always toplevel here |
| SourceTypeConverter.FIELD_AND_METHOD // need field and methods |
| | SourceTypeConverter.MEMBER_TYPE, // need member types |
| // no need for field initialization |
| this.problemReporter, |
| compilationResult); |
| if (compilationUnit.types != null) |
| typeDeclaration = compilationUnit.types[0]; |
| } else { |
| compilationUnit = new CompilationUnitDeclaration(this.problemReporter, compilationResult, 0); |
| typeDeclaration = BinaryTypeConverter.buildTypeDeclaration(type, compilationUnit, compilationResult); |
| } |
| |
| 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) { |
| contextAccepted = true; |
| // if null then we found a problem in the completion node |
| complete(e.astNode, this.parser.assistNodeParent, e.qualifiedBinding, e.scope, e.insideTypeAnnotation); |
| } |
| } |
| } |
| if(this.noProposal && this.problem != null) { |
| if(!contextAccepted) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| } |
| this.requestor.completionFailure(this.problem); |
| if(DEBUG) { |
| this.printDebug(this.problem); |
| } |
| } |
| } |
| } catch(JavaModelException e) { |
| // Do nothing |
| } |
| if(!contextAccepted) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| } |
| if(this.requestor != null){ |
| this.requestor.endReporting(); |
| } |
| } |
| |
| private Initializer parseSnippeInitializer(char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){ |
| StringBuffer prefix = new StringBuffer(); |
| prefix.append("public class FakeType {\n "); //$NON-NLS-1$ |
| if(isStatic) { |
| prefix.append("static "); //$NON-NLS-1$ |
| } |
| prefix.append("{\n"); //$NON-NLS-1$ |
| for (int i = 0; i < localVariableTypeNames.length; i++) { |
| ASTNode.printModifiers(localVariableModifiers[i], prefix); |
| prefix.append(' '); |
| prefix.append(localVariableTypeNames[i]); |
| prefix.append(' '); |
| prefix.append(localVariableNames[i]); |
| prefix.append(';'); |
| } |
| |
| char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$ |
| this.offset = prefix.length(); |
| |
| String encoding = this.compilerOptions.defaultEncoding; |
| BasicCompilationUnit fakeUnit = new BasicCompilationUnit( |
| fakeSource, |
| null, |
| "FakeType.java", //$NON-NLS-1$ |
| encoding); |
| |
| this.actualCompletionPosition = prefix.length() + position - 1; |
| |
| CompilationResult fakeResult = new CompilationResult(fakeUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); |
| CompilationUnitDeclaration fakeAST = this.parser.dietParse(fakeUnit, fakeResult, this.actualCompletionPosition); |
| |
| parseBlockStatements(fakeAST, this.actualCompletionPosition); |
| |
| return (Initializer)fakeAST.types[0].fields[0]; |
| } |
| |
| /** |
| * 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) { |
| |
| 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.actualCompletionPosition = completionPosition - 1; |
| this.offset = pos; |
| // for now until we can change the UI. |
| CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit); |
| CompilationUnitDeclaration parsedUnit = this.parser.dietParse(sourceUnit, result, this.actualCompletionPosition); |
| |
| // boolean completionNodeFound = false; |
| if (parsedUnit != null) { |
| if(DEBUG) { |
| System.out.println("COMPLETION - Diet AST :"); //$NON-NLS-1$ |
| System.out.println(parsedUnit.toString()); |
| } |
| |
| // scan the package & import statements first |
| if (parsedUnit.currentPackage instanceof CompletionOnPackageReference) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { |
| findPackages((CompletionOnPackageReference) parsedUnit.currentPackage); |
| } |
| if(this.noProposal && this.problem != null) { |
| this.requestor.completionFailure(this.problem); |
| if(DEBUG) { |
| this.printDebug(this.problem); |
| } |
| } |
| return; |
| } |
| |
| ImportReference[] imports = parsedUnit.imports; |
| if (imports != null) { |
| for (int i = 0, length = imports.length; i < length; i++) { |
| ImportReference importReference = imports[i]; |
| if (importReference instanceof CompletionOnImportReference) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| findImports((CompletionOnImportReference) importReference); |
| if(this.noProposal && this.problem != null) { |
| this.requestor.completionFailure(this.problem); |
| if(DEBUG) { |
| this.printDebug(this.problem); |
| } |
| } |
| if(importReference.isStatic()) { |
| this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); |
| if ((this.unitScope = parsedUnit.scope) != null) { |
| char[][] oldTokens = importReference.tokens; |
| int tokenCount = oldTokens.length; |
| char[] lastToken = oldTokens[tokenCount - 1]; |
| char[][] qualifierTokens = CharOperation.subarray(oldTokens, 0, tokenCount - 1); |
| |
| Binding binding = this.unitScope.getTypeOrPackage(qualifierTokens); |
| if(binding != null && binding instanceof ReferenceBinding) { |
| ReferenceBinding ref = (ReferenceBinding) binding; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| this.findImportsOfMemberTypes(lastToken, ref); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| this.findImportsOfStaticFields(lastToken, ref); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) { |
| this.findImportsOfStaticMethdods(lastToken, ref); |
| } |
| } |
| } |
| } |
| return; |
| } else if(importReference instanceof CompletionOnKeyword) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| setSourceRange(importReference.sourceStart, importReference.sourceEnd); |
| CompletionOnKeyword keyword = (CompletionOnKeyword)importReference; |
| findKeywords(keyword.getToken(), keyword.getPossibleKeywords()); |
| } |
| if(this.noProposal && this.problem != null) { |
| this.requestor.completionFailure(this.problem); |
| if(DEBUG) { |
| this.printDebug(this.problem); |
| } |
| } |
| return; |
| } |
| } |
| } |
| |
| if (parsedUnit.types != null) { |
| try { |
| this.lookupEnvironment.buildTypeBindings(parsedUnit, null /*no access restriction*/); |
| |
| if ((this.unitScope = parsedUnit.scope) != null) { |
| this.source = sourceUnit.getContents(); |
| this.lookupEnvironment.completeTypeBindings(parsedUnit, true); |
| parsedUnit.scope.faultInTypes(); |
| parseBlockStatements(parsedUnit, this.actualCompletionPosition); |
| if(DEBUG) { |
| System.out.println("COMPLETION - AST :"); //$NON-NLS-1$ |
| System.out.println(parsedUnit.toString()); |
| } |
| parsedUnit.resolve(); |
| } |
| } catch (CompletionNodeFound e) { |
| // completionNodeFound = true; |
| if (e.astNode != null) { |
| if(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); |
| } |
| } |
| contextAccepted = true; |
| // if null then we found a problem in the completion node |
| complete(e.astNode, this.parser.assistNodeParent, e.qualifiedBinding, e.scope, e.insideTypeAnnotation); |
| } |
| } |
| } |
| } |
| |
| if(this.noProposal && this.problem != null) { |
| if(!contextAccepted) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| } |
| 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 { |
| reset(); |
| if(!contextAccepted) { |
| contextAccepted = true; |
| this.requestor.acceptContext(new CompletionContext()); |
| } |
| this.requestor.endReporting(); |
| } |
| } |
| |
| private TypeBinding[] computeTypes(Expression[] arguments, BlockScope scope) { |
| |
| 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 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)) 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 += 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 = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| private void findAnonymousType( |
| ReferenceBinding currentType, |
| TypeBinding[] argTypes, |
| Scope scope, |
| InvocationSite invocationSite) { |
| |
| if (currentType.isInterface()) { |
| char[] completion = CharOperation.NO_CHAR; |
| // nothing to insert - do not want to replace the existing selector & arguments |
| if (this.source == null |
| || this.source.length <= this.endPosition |
| || this.source[this.endPosition] != ')') |
| completion = new char[] { ')' }; |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)) { |
| CompletionProposal proposal = this.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.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.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) { |
| |
| if (token == null) |
| return; |
| |
| if (token.length <= classField.length |
| && CharOperation.prefixEquals(token, classField, false /* ignore case */ |
| )) { |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(token, classField); |
| relevance += computeRelevanceForExpectingType(scope.getJavaLangClass()); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); //no access restriction for class field |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition); |
| //proposal.setDeclarationSignature(null); |
| proposal.setSignature( |
| createNonGenericTypeSignature( |
| CharOperation.concatWith(JAVA_LANG, '.'), |
| CLASS)); |
| //proposal.setDeclarationPackageName(null); |
| //proposal.setDeclarationTypeName(null); |
| proposal.setPackageName(CharOperation.concatWith(JAVA_LANG, '.')); |
| proposal.setTypeName(CLASS); |
| proposal.setName(classField); |
| proposal.setCompletion(classField); |
| proposal.setFlags(Flags.AccStatic | Flags.AccPublic); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| private void findEnumConstant(char[] enumConstantName, SwitchStatement switchStatement) { |
| TypeBinding expressionType = switchStatement.expression.resolvedType; |
| if(expressionType != null && expressionType.isEnum()) { |
| ReferenceBinding enumType = (ReferenceBinding) expressionType; |
| |
| FieldBinding[] fields = enumType.fields(); |
| |
| int enumConstantLength = enumConstantName.length; |
| next : for (int f = fields.length; --f >= 0;) { |
| FieldBinding field = fields[f]; |
| |
| if (field.isSynthetic()) continue next; |
| |
| if ((field.modifiers & Flags.AccEnum) == 0) continue next; |
| |
| if (enumConstantLength > field.name.length) continue next; |
| |
| if (!CharOperation.prefixEquals(enumConstantName, field.name, false /* ignore case */)) continue next; |
| |
| char[] completion = field.name; |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(field); |
| relevance += R_ENUM_CONSTANT; |
| relevance += computeRelevanceForCaseMatching(enumConstantName, field.name); |
| relevance += computeRelevanceForExpectingType(field.type); |
| relevance += computeRelevanceForQualification(false); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| } |
| private void findExplicitConstructors( |
| char[] name, |
| ReferenceBinding currentType, |
| MethodScope scope, |
| InvocationSite invocationSite) { |
| |
| ConstructorDeclaration constructorDeclaration = (ConstructorDeclaration)scope.referenceContext; |
| MethodBinding enclosingConstructor = constructorDeclaration.binding; |
| |
| // No visibility checks can be performed without the scope & invocationSite |
| MethodBinding[] methods = currentType.availableMethods(); |
| if(methods != null) { |
| next : for (int f = methods.length; --f >= 0;) { |
| MethodBinding constructor = methods[f]; |
| if (constructor != enclosingConstructor && constructor.isConstructor()) { |
| |
| if (constructor.isSynthetic()) continue next; |
| |
| if (this.options.checkVisibility |
| && !constructor.canBeSeenBy(invocationSite, scope)) continue next; |
| |
| TypeBinding[] parameters = constructor.parameters; |
| int paramLength = parameters.length; |
| |
| char[][] parameterPackageNames = new char[paramLength][]; |
| char[][] parameterTypeNames = new char[paramLength][]; |
| for (int i = 0; i < paramLength; i++) { |
| TypeBinding type = parameters[i]; |
| parameterPackageNames[i] = type.qualifiedPackageName(); |
| parameterTypeNames[i] = type.qualifiedSourceName(); |
| } |
| char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames); |
| |
| char[] completion = CharOperation.NO_CHAR; |
| if (this.source != null |
| && this.source.length > this.endPosition |
| && this.source[this.endPosition] == '(') |
| completion = name; |
| else |
| completion = CharOperation.concat(name, new char[] { '(', ')' }); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(this.completionToken, name); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(getSignature(currentType)); |
| proposal.setSignature(getSignature(constructor)); |
| proposal.setDeclarationPackageName(currentType.qualifiedPackageName()); |
| proposal.setDeclarationTypeName(currentType.qualifiedSourceName()); |
| proposal.setParameterPackageNames(parameterPackageNames); |
| proposal.setParameterTypeNames(parameterTypeNames); |
| //proposal.setPackageName(null); |
| //proposal.setTypeName(null); |
| proposal.setName(name); |
| proposal.setCompletion(completion); |
| proposal.setFlags(constructor.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| if(parameterNames != null) proposal.setParameterNames(parameterNames); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| } |
| } |
| 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()) { |
| |
| if (constructor.isSynthetic()) continue next; |
| |
| if (this.options.checkVisibility |
| && !constructor.canBeSeenBy(invocationSite, scope)) { |
| if(!forAnonymousType || !constructor.isProtected()) |
| continue next; |
| } |
| |
| TypeBinding[] parameters = constructor.parameters; |
| int paramLength = parameters.length; |
| if (minArgLength > paramLength) |
| continue next; |
| for (int a = minArgLength; --a >= 0;) |
| if (argTypes[a] != null) // can be null if it could not be resolved properly |
| if (!argTypes[a].isCompatibleWith(constructor.parameters[a])) |
| continue next; |
| |
| char[][] parameterPackageNames = new char[paramLength][]; |
| char[][] parameterTypeNames = new char[paramLength][]; |
| for (int i = 0; i < paramLength; i++) { |
| TypeBinding type = parameters[i]; |
| parameterPackageNames[i] = type.qualifiedPackageName(); |
| parameterTypeNames[i] = type.qualifiedSourceName(); |
| } |
| char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames); |
| |
| char[] completion = CharOperation.NO_CHAR; |
| // nothing to insert - do not want to replace the existing selector & arguments |
| if (this.source == null |
| || this.source.length <= this.endPosition |
| || this.source[this.endPosition] != ')') |
| completion = new char[] { ')' }; |
| |
| if(forAnonymousType){ |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.ANONYMOUS_CLASS_DECLARATION)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.ANONYMOUS_CLASS_DECLARATION, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(getSignature(currentType)); |
| proposal.setDeclarationKey(currentType.computeUniqueKey()); |
| proposal.setSignature(getSignature(constructor)); |
| 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.setRelevance(relevance); |
| if(parameterNames != null) proposal.setParameterNames(parameterNames); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } else { |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(getSignature(currentType)); |
| proposal.setSignature(getSignature(constructor)); |
| 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.setCompletion(completion); |
| proposal.setFlags(constructor.modifiers); |
| proposal.setReplaceRange(this.endPosition - this.offset, this.endPosition - 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) { |
| |
| 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 fieldLength = fieldName.length; |
| next : for (int f = fields.length; --f >= 0;) { |
| FieldBinding field = fields[f]; |
| |
| if (field.isSynthetic()) continue next; |
| |
| if (onlyStaticFields && !field.isStatic()) continue next; |
| |
| if (fieldLength > field.name.length) continue next; |
| |
| if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)) continue next; |
| |
| if (this.options.checkVisibility |
| && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next; |
| |
| boolean prefixRequired = false; |
| |
| for (int i = fieldsFound.size; --i >= 0;) { |
| Object[] other = (Object[])fieldsFound.elementAt(i); |
| FieldBinding otherField = (FieldBinding) other[0]; |
| ReferenceBinding otherReceiverType = (ReferenceBinding) other[1]; |
| if (field == otherField && receiverType == otherReceiverType) |
| continue next; |
| if (CharOperation.equals(field.name, otherField.name, true)) { |
| if (field.declaringClass.isSuperclassOf(otherField.declaringClass)) |
| continue next; |
| if (otherField.declaringClass.isInterface()) { |
| if (field.declaringClass == scope.getJavaLangObject()) |
| continue next; |
| if (field.declaringClass.implementsInterface(otherField.declaringClass, true)) |
| continue next; |
| } |
| if (field.declaringClass.isInterface()) |
| if (otherField.declaringClass.implementsInterface(field.declaringClass, true)) |
| continue next; |
| if(canBePrefixed) { |
| prefixRequired = true; |
| } else { |
| continue next; |
| } |
| } |
| } |
| |
| for (int l = localsFound.size; --l >= 0;) { |
| LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l); |
| |
| if (CharOperation.equals(field.name, local.name, true)) { |
| SourceTypeBinding declarationType = scope.enclosingSourceType(); |
| if (declarationType.isAnonymousType() && declarationType != invocationScope.enclosingSourceType()) { |
| continue next; |
| } |
| if(canBePrefixed) { |
| prefixRequired = true; |
| } else { |
| continue next; |
| } |
| break; |
| } |
| } |
| |
| newFieldsFound.add(new Object[]{field, receiverType}); |
| |
| char[] completion = field.name; |
| |
| if(prefixRequired || this.options.forceImplicitQualification){ |
| char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), field.isStatic()); |
| completion = CharOperation.concat(prefix,completion,'.'); |
| } |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(field); |
| relevance += computeRelevanceForCaseMatching(fieldName, field.name); |
| relevance += computeRelevanceForExpectingType(field.type); |
| relevance += computeRelevanceForStatic(onlyStaticFields, field.isStatic()); |
| relevance += computeRelevanceForQualification(prefixRequired); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| |
| fieldsFound.addAll(newFieldsFound); |
| } |
| |
| private void findFields( |
| char[] fieldName, |
| ReferenceBinding receiverType, |
| Scope scope, |
| ObjectVector fieldsFound, |
| ObjectVector localsFound, |
| boolean onlyStaticFields, |
| InvocationSite invocationSite, |
| Scope invocationScope, |
| boolean implicitCall, |
| boolean canBePrefixed) { |
| |
| if (fieldName == null) |
| return; |
| |
| ReferenceBinding currentType = receiverType; |
| ReferenceBinding[][] interfacesToVisit = null; |
| int lastPosition = -1; |
| do { |
| |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| |
| if (interfacesToVisit == null) |
| interfacesToVisit = new ReferenceBinding[5][]; |
| |
| if (++lastPosition == interfacesToVisit.length) |
| System.arraycopy( |
| interfacesToVisit, |
| 0, |
| interfacesToVisit = new ReferenceBinding[lastPosition * 2][], |
| 0, |
| lastPosition); |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| } |
| |
| FieldBinding[] fields = currentType.availableFields(); |
| if(fields != null) { |
| findFields( |
| fieldName, |
| fields, |
| scope, |
| fieldsFound, |
| localsFound, |
| onlyStaticFields, |
| receiverType, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| canBePrefixed); |
| } |
| currentType = currentType.superclass(); |
| } while (currentType != null); |
| |
| if (interfacesToVisit != null) { |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| for (int j = 0, length = interfaces.length; j < length; j++) { |
| |
| ReferenceBinding anInterface = interfaces[j]; |
| if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) { |
| // if interface as not already been visited |
| anInterface.tagBits |= TagBits.InterfaceVisited; |
| |
| FieldBinding[] fields = anInterface.availableFields(); |
| if(fields != null) { |
| findFields( |
| fieldName, |
| fields, |
| scope, |
| fieldsFound, |
| localsFound, |
| onlyStaticFields, |
| receiverType, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| canBePrefixed); |
| } |
| |
| ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| if (++lastPosition == interfacesToVisit.length) |
| System.arraycopy( |
| interfacesToVisit, |
| 0, |
| interfacesToVisit = new ReferenceBinding[lastPosition * 2][], |
| 0, |
| lastPosition); |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| } |
| } |
| } |
| } |
| |
| // bit reinitialization |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| for (int j = 0, length = interfaces.length; j < length; j++) |
| interfaces[j].tagBits &= ~TagBits.InterfaceVisited; |
| } |
| } |
| } |
| |
| private void findFieldsAndMethods( |
| char[] token, |
| TypeBinding receiverType, |
| Scope scope, |
| InvocationSite invocationSite, |
| Scope invocationScope, |
| boolean implicitCall, |
| boolean superCall) { |
| |
| if (token == null) |
| return; |
| |
| if (receiverType.isBaseType()) |
| return; // nothing else is possible with base types |
| |
| boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF); |
| boolean proposeMethod = !this.requestor.isIgnored(CompletionProposal.METHOD_REF); |
| |
| ObjectVector methodsFound = new ObjectVector(); |
| |
| if (receiverType.isArrayType()) { |
| if (proposeField |
| && token.length <= lengthField.length |
| && CharOperation.prefixEquals(token, lengthField, false /* ignore case */ |
| )) { |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(token,lengthField); |
| relevance += computeRelevanceForExpectingType(BaseTypes.IntBinding); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for length field |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.FIELD_REF, this.actualCompletionPosition); |
| //proposal.setDeclarationSignature(null); |
| proposal.setSignature(INT_SIGNATURE); |
| //proposal.setDeclarationPackageName(null); |
| //proposal.setDeclarationTypeName(null); |
| //proposal.setPackageName(null); |
| proposal.setTypeName(INT); |
| proposal.setName(lengthField); |
| proposal.setCompletion(lengthField); |
| proposal.setFlags(Flags.AccPublic); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| if (proposeMethod |
| && token.length <= cloneMethod.length |
| && CharOperation.prefixEquals(token, cloneMethod, false /* ignore case */ |
| )) { |
| ReferenceBinding objectRef = scope.getJavaLangObject(); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += 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 |
| |
| char[] completion; |
| if (this.source != null |
| && this.source.length > this.endPosition |
| && this.source[this.endPosition] == '(') { |
| completion = cloneMethod; |
| } else { |
| completion = CharOperation.concat(cloneMethod, new char[] { '(', ')' }); |
| } |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, this.actualCompletionPosition); |
| //proposal.setDeclarationSignature(null); |
| proposal.setSignature( |
| createMethodSignature( |
| CharOperation.NO_CHAR_CHAR, |
| CharOperation.NO_CHAR_CHAR, |
| CharOperation.concatWith(JAVA_LANG, '.'), |
| OBJECT)); |
| //proposal.setDeclarationPackageName(null); |
| //proposal.setDeclarationTypeName(null); |
| //proposal.setParameterPackageNames(null); |
| //proposal.setParameterTypeNames(null); |
| proposal.setPackageName(CharOperation.concatWith(JAVA_LANG, '.')); |
| proposal.setTypeName(OBJECT); |
| proposal.setName(cloneMethod); |
| proposal.setCompletion(completion); |
| proposal.setFlags(Flags.AccPublic); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| methodsFound.add(new Object[]{objectRef.getMethods(cloneMethod)[0], objectRef}); |
| } |
| |
| receiverType = scope.getJavaLangObject(); |
| } |
| |
| if(proposeField) { |
| findFields( |
| token, |
| (ReferenceBinding) receiverType, |
| scope, |
| new ObjectVector(), |
| new ObjectVector(), |
| false, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| true); |
| } |
| |
| if(proposeMethod) { |
| findMethods( |
| token, |
| null, |
| (ReferenceBinding) receiverType, |
| scope, |
| methodsFound, |
| false, |
| false, |
| false, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| true); |
| } |
| } |
| |
| private void findImports(CompletionOnImportReference importReference) { |
| char[][] tokens = importReference.tokens; |
| |
| char[] importName = CharOperation.concatWith(tokens, '.'); |
| |
| if (importName.length == 0) |
| return; |
| |
| char[] lastToken = tokens[tokens.length - 1]; |
| if(lastToken != null && lastToken.length == 0) |
| importName = CharOperation.concat(importName, new char[]{'.'}); |
| |
| this.resolvingImports = true; |
| setSourceRange( |
| importReference.sourceStart, |
| importReference.declarationSourceEnd); |
| |
| this.completionToken = importName; |
| // want to replace the existing .*; |
| if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { |
| this.nameEnvironment.findPackages(importName, this); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| this.nameEnvironment.findTypes(importName, this); |
| } |
| } |
| |
| private void findImportsOfMemberTypes(char[] typeName, ReferenceBinding ref) { |
| ReferenceBinding[] memberTypes = ref.memberTypes(); |
| |
| int typeLength = typeName.length; |
| next : for (int m = memberTypes.length; --m >= 0;) { |
| ReferenceBinding memberType = memberTypes[m]; |
| // if (!wantClasses && memberType.isClass()) continue next; |
| // if (!wantInterfaces && memberType.isInterface()) continue next; |
| |
| if (typeLength > memberType.sourceName.length) |
| continue next; |
| |
| if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false |
| /* ignore case */ |
| )) |
| continue next; |
| |
| if (this.options.checkVisibility |
| && !memberType.canBeSeenBy(this.unitScope.fPackage)) |
| continue next; |
| |
| char[] completionName = CharOperation.concat( |
| memberType.qualifiedPackageName(), |
| memberType.qualifiedSourceName(), |
| '.'); |
| |
| completionName = CharOperation.concat(completionName, SEMICOLON); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| if (memberType.isClass()) { |
| relevance += computeRelevanceForClass(); |
| } else if(memberType.isEnum()) { |
| relevance += computeRelevanceForEnum(); |
| } else if (memberType.isInterface()) { |
| relevance += computeRelevanceForInterface(); |
| } |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(memberType.qualifiedPackageName()); |
| proposal.setSignature(getSignature(memberType)); |
| proposal.setPackageName(memberType.qualifiedPackageName()); |
| proposal.setTypeName(memberType.qualifiedSourceName()); |
| proposal.setCompletion(completionName); |
| proposal.setFlags(memberType.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| private void findImportsOfStaticFields(char[] fieldName, ReferenceBinding ref) { |
| FieldBinding[] fields = ref.fields(); |
| |
| int fieldLength = fieldName.length; |
| next : for (int m = fields.length; --m >= 0;) { |
| FieldBinding field = fields[m]; |
| |
| if (fieldLength > field.name.length) |
| continue next; |
| |
| if (field.isSynthetic()) |
| continue next; |
| |
| if (!field.isStatic()) |
| continue next; |
| |
| if (!CharOperation.prefixEquals(fieldName, field.name, false |
| /* ignore case */ |
| )) |
| continue next; |
| |
| if (this.options.checkVisibility |
| && !field.canBeSeenBy(this.unitScope.fPackage)) |
| continue next; |
| |
| char[] completionName = CharOperation.concat( |
| field.declaringClass.qualifiedPackageName(), |
| '.', |
| field.declaringClass.qualifiedSourceName(), |
| '.', |
| field.name); |
| |
| completionName = CharOperation.concat(completionName, SEMICOLON); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(fieldName, field.name); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.FIELD_REF)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| private void findImportsOfStaticMethdods(char[] methodName, ReferenceBinding ref) { |
| MethodBinding[] methods = ref.methods(); |
| |
| 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.checkVisibility |
| && !method.canBeSeenBy(this.unitScope.fPackage)) continue next; |
| |
| if (methodLength > method.selector.length) |
| continue next; |
| |
| if (!CharOperation.prefixEquals(methodName, method.selector, false |
| /* ignore case */ |
| )) |
| continue next; |
| |
| int length = method.parameters.length; |
| char[][] parameterPackageNames = new char[length][]; |
| char[][] parameterTypeNames = new char[length][]; |
| |
| for (int i = 0; i < length; i++) { |
| TypeBinding type = method.original().parameters[i]; |
| parameterPackageNames[i] = type.qualifiedPackageName(); |
| parameterTypeNames[i] = type.qualifiedSourceName(); |
| } |
| char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); |
| |
| |
| char[] completionName = CharOperation.concat( |
| method.declaringClass.qualifiedPackageName(), |
| '.', |
| method.declaringClass.qualifiedSourceName(), |
| '.', |
| method.selector); |
| |
| completionName = CharOperation.concat(completionName, SEMICOLON); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(methodName, method.selector); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_NAME_REFERENCE)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| if(parameterNames != null) proposal.setParameterNames(parameterNames); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| // what about onDemand types? Ignore them since it does not happen! |
| // import p1.p2.A.*; |
| private void findKeywords(char[] keyword, char[][] choices) { |
| if(choices == null || choices.length == 0) return; |
| |
| int length = keyword.length; |
| if (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 += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(keyword, choices[i]); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywors |
| |
| if(CharOperation.equals(choices[i], Keywords.TRUE) || CharOperation.equals(choices[i], Keywords.FALSE)) { |
| relevance += computeRelevanceForExpectingType(BaseTypes.BooleanBinding); |
| relevance += computeRelevanceForQualification(false); |
| } |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition); |
| proposal.setName(choices[i]); |
| proposal.setCompletion(choices[i]); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| private void findTrueOrFalseKeywords(char[][] choices) { |
| if(choices == null || choices.length == 0) return; |
| |
| if(this.expectedTypesPtr != 0 || this.expectedTypes[0] != BaseTypes.BooleanBinding) 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 += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(CharOperation.NO_CHAR, choices[i]); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for keywors |
| relevance += computeRelevanceForExpectingType(BaseTypes.BooleanBinding); |
| relevance += computeRelevanceForQualification(false); |
| relevance += R_TRUE_OR_FALSE; |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.KEYWORD, this.actualCompletionPosition); |
| proposal.setName(choices[i]); |
| proposal.setCompletion(choices[i]); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| } |
| |
| private void findKeywordsForMember(char[] token, int modifiers) { |
| char[][] keywords = new char[Keywords.COUNT][]; |
| int count = 0; |
| |
| // visibility |
| if((modifiers & IConstants.AccPrivate) == 0 |
| && (modifiers & IConstants.AccProtected) == 0 |
| && (modifiers & IConstants.AccPublic) == 0) { |
| keywords[count++] = Keywords.PROTECTED; |
| keywords[count++] = Keywords.PUBLIC; |
| if((modifiers & IConstants.AccAbstract) == 0) { |
| keywords[count++] = Keywords.PRIVATE; |
| } |
| } |
| |
| if((modifiers & IConstants.AccAbstract) == 0) { |
| // abtract |
| if((modifiers & ~(CompilerModifiers.AccVisibilityMASK | IConstants.AccStatic)) == 0) { |
| keywords[count++] = Keywords.ABSTRACT; |
| } |
| |
| // final |
| if((modifiers & IConstants.AccFinal) == 0) { |
| keywords[count++] = Keywords.FINAL; |
| } |
| |
| // static |
| if((modifiers & IConstants.AccStatic) == 0) { |
| keywords[count++] = Keywords.STATIC; |
| } |
| |
| boolean canBeField = true; |
| boolean canBeMethod = true; |
| boolean canBeType = true; |
| if((modifiers & IConstants.AccNative) != 0 |
| || (modifiers & IConstants.AccStrictfp) != 0 |
| || (modifiers & IConstants.AccSynchronized) != 0) { |
| canBeField = false; |
| canBeType = false; |
| } |
| |
| if((modifiers & IConstants.AccTransient) != 0 |
| || (modifiers & IConstants.AccVolatile) != 0) { |
| canBeMethod = false; |
| canBeType = false; |
| } |
| |
| if(canBeField) { |
| // transient |
| if((modifiers & IConstants.AccTransient) == 0) { |
| keywords[count++] = Keywords.TRANSIENT; |
| } |
| |
| // volatile |
| if((modifiers & IConstants.AccVolatile) == 0) { |
| keywords[count++] = Keywords.VOLATILE; |
| } |
| } |
| |
| if(canBeMethod) { |
| // native |
| if((modifiers & IConstants.AccNative) == 0) { |
| keywords[count++] = Keywords.NATIVE; |
| } |
| |
| // strictfp |
| if((modifiers & IConstants.AccStrictfp) == 0) { |
| keywords[count++] = Keywords.STRICTFP; |
| } |
| |
| // synchronized |
| if((modifiers & IConstants.AccSynchronized) == 0) { |
| keywords[count++] = Keywords.SYNCHRONIZED; |
| } |
| } |
| |
| if(canBeType) { |
| keywords[count++] = Keywords.CLASS; |
| keywords[count++] = Keywords.INTERFACE; |
| } |
| } else { |
| // class |
| keywords[count++] = Keywords.CLASS; |
| keywords[count++] = Keywords.INTERFACE; |
| } |
| System.arraycopy(keywords, 0, keywords = new char[count][], 0, count); |
| |
| findKeywords(token, keywords); |
| } |
| |
| // Helper method for findMemberTypes(char[], ReferenceBinding, Scope) |
| private void findMemberTypes( |
| char[] typeName, |
| ReferenceBinding[] memberTypes, |
| ObjectVector typesFound, |
| ReferenceBinding receiverType, |
| SourceTypeBinding invocationType, |
| boolean staticOnly) { |
| |
| // Inherited member types which are hidden by subclasses are filtered out |
| // No visibility checks can be performed without the scope & invocationSite |
| int typeLength = typeName.length; |
| next : for (int m = memberTypes.length; --m >= 0;) { |
| ReferenceBinding memberType = memberTypes[m]; |
| // if (!wantClasses && memberType.isClass()) continue next; |
| // if (!wantInterfaces && memberType.isInterface()) continue next; |
| |
| if (staticOnly && !memberType.isStatic()) continue next; |
| |
| if (isForbidden(memberType)) continue next; |
| |
| if (typeLength > memberType.sourceName.length) |
| continue next; |
| |
| if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false |
| /* ignore case */ |
| )) |
| continue next; |
| |
| if (this.options.checkVisibility) { |
| if (invocationType != null && !memberType.canBeSeenBy(receiverType, invocationType)) { |
| continue next; |
| } else if(invocationType == null && !memberType.canBeSeenBy(this.unitScope.fPackage)) { |
| continue next; |
| } |
| } |
| |
| for (int i = typesFound.size; --i >= 0;) { |
| ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i); |
| |
| if (memberType == otherType) |
| continue next; |
| |
| if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) { |
| |
| if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType())) |
| continue next; |
| |
| if (otherType.enclosingType().isInterface()) |
| if (memberType.enclosingType() |
| .implementsInterface(otherType.enclosingType(), true)) |
| continue next; |
| |
| if (memberType.enclosingType().isInterface()) |
| if (otherType.enclosingType() |
| .implementsInterface(memberType.enclosingType(), true)) |
| continue next; |
| } |
| } |
| |
| typesFound.add(memberType); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName); |
| relevance += computeRelevanceForExpectingType(memberType); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| if (memberType.isClass()) { |
| relevance += computeRelevanceForClass(); |
| relevance += computeRelevanceForException(memberType.sourceName); |
| } else if(memberType.isEnum()) { |
| relevance += computeRelevanceForEnum(); |
| } else if(memberType.isInterface()) { |
| relevance += computeRelevanceForInterface(); |
| } |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(memberType.qualifiedPackageName()); |
| proposal.setSignature(getSignature(memberType)); |
| proposal.setPackageName(memberType.qualifiedPackageName()); |
| proposal.setTypeName(memberType.qualifiedSourceName()); |
| proposal.setCompletion(memberType.sourceName()); |
| proposal.setFlags(memberType.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| private void findMemberTypes( |
| char[] typeName, |
| ReferenceBinding receiverType, |
| Scope scope, |
| SourceTypeBinding typeInvocation, |
| boolean staticOnly, |
| ObjectVector typesFound) { |
| |
| ReferenceBinding currentType = receiverType; |
| if (typeName == null) |
| return; |
| |
| if (currentType.superInterfaces() == null) |
| return; // we're trying to find a supertype |
| |
| if (this.insideQualifiedReference |
| || typeName.length == 0) { // do not search up the hierarchy |
| |
| findMemberTypes( |
| typeName, |
| currentType.memberTypes(), |
| typesFound, |
| receiverType, |
| typeInvocation, |
| staticOnly); |
| return; |
| } |
| |
| ReferenceBinding[][] interfacesToVisit = null; |
| int lastPosition = -1; |
| |
| do { |
| |
| ReferenceBinding[] itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| |
| if (interfacesToVisit == null) |
| interfacesToVisit = new ReferenceBinding[5][]; |
| |
| if (++lastPosition == interfacesToVisit.length) |
| System.arraycopy( |
| interfacesToVisit, |
| 0, |
| interfacesToVisit = new ReferenceBinding[lastPosition * 2][], |
| 0, |
| lastPosition); |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| } |
| |
| findMemberTypes( |
| typeName, |
| currentType.memberTypes(), |
| typesFound, |
| receiverType, |
| typeInvocation, |
| staticOnly); |
| currentType = currentType.superclass(); |
| |
| } while (currentType != null); |
| |
| if (interfacesToVisit != null) { |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| for (int j = 0, length = interfaces.length; j < length; j++) { |
| |
| ReferenceBinding anInterface = interfaces[j]; |
| if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) { |
| // if interface as not already been visited |
| anInterface.tagBits |= TagBits.InterfaceVisited; |
| |
| findMemberTypes( |
| typeName, |
| anInterface.memberTypes(), |
| typesFound, |
| receiverType, |
| typeInvocation, |
| staticOnly); |
| |
| ReferenceBinding[] itsInterfaces = anInterface.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| |
| if (++lastPosition == interfacesToVisit.length) |
| System.arraycopy( |
| interfacesToVisit, |
| 0, |
| interfacesToVisit = new ReferenceBinding[lastPosition * 2][], |
| 0, |
| lastPosition); |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| } |
| } |
| } |
| } |
| |
| // bit reinitialization |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| for (int j = 0, length = interfaces.length; j < length; j++) |
| interfaces[j].tagBits &= ~TagBits.InterfaceVisited; |
| } |
| } |
| } |
| |
| private void findIntefacesMethods( |
| char[] selector, |
| 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) { |
| |
| if (selector == null) |
| return; |
| |
| if (itsInterfaces != NoSuperInterfaces) { |
| ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; |
| int lastPosition = 0; |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| |
| for (int j = 0, length = interfaces.length; j < length; j++) { |
| ReferenceBinding currentType = interfaces[j]; |
| |
| if ((currentType.tagBits & TagBits.InterfaceVisited) == 0) { |
| // if interface as not already been visited |
| currentType.tagBits |= TagBits.InterfaceVisited; |
| |
| MethodBinding[] methods = currentType.availableMethods(); |
| if(methods != null) { |
| if(isCompletingDeclaration){ |
| |
| findLocalMethodDeclarations( |
| selector, |
| methods, |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| receiverType); |
| |
| } else { |
| |
| findLocalMethods( |
| selector, |
| argTypes, |
| methods, |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| receiverType, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| canBePrefixed); |
| } |
| } |
| |
| itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| |
| if (++lastPosition == interfacesToVisit.length) |
| System.arraycopy( |
| interfacesToVisit, |
| 0, |
| interfacesToVisit = new ReferenceBinding[lastPosition * 2][], |
| 0, |
| lastPosition); |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| } |
| } |
| } |
| } |
| |
| // bit reinitialization |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| |
| for (int j = 0, length = interfaces.length; j < length; j++){ |
| interfaces[j].tagBits &= ~TagBits.InterfaceVisited; |
| } |
| } |
| } |
| } |
| |
| private void findImplicitMessageSends( |
| char[] token, |
| TypeBinding[] argTypes, |
| Scope scope, |
| InvocationSite invocationSite, |
| Scope invocationScope) { |
| |
| if (token == null) |
| return; |
| |
| boolean staticsOnly = false; |
| // need to know if we're in a static context (or inside a constructor) |
| ObjectVector methodsFound = new ObjectVector(); |
| |
| done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found |
| |
| switch (scope.kind) { |
| |
| case Scope.METHOD_SCOPE : |
| // handle the error case inside an explicit constructor call (see MethodScope>>findField) |
| MethodScope methodScope = (MethodScope) scope; |
| staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall; |
| break; |
| |
| case Scope.CLASS_SCOPE : |
| ClassScope classScope = (ClassScope) scope; |
| SourceTypeBinding enclosingType = classScope.referenceContext.binding; |
| findMethods( |
| token, |
| argTypes, |
| enclosingType, |
| classScope, |
| methodsFound, |
| staticsOnly, |
| true, |
| false, |
| invocationSite, |
| invocationScope, |
| true, |
| false, |
| true); |
| staticsOnly |= enclosingType.isStatic(); |
| break; |
| |
| case Scope.COMPILATION_UNIT_SCOPE : |
| break done; |
| } |
| scope = scope.parent; |
| } |
| } |
| |
| // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean) |
| private void findLocalMethods( |
| char[] methodName, |
| TypeBinding[] argTypes, |
| MethodBinding[] methods, |
| Scope scope, |
| ObjectVector methodsFound, |
| boolean onlyStaticMethods, |
| boolean exactMatch, |
| ReferenceBinding receiverType, |
| InvocationSite invocationSite, |
| Scope invocationScope, |
| boolean implicitCall, |
| boolean superCall, |
| boolean canBePrefixed) { |
| |
| ObjectVector newMethodsFound = new ObjectVector(); |
| // Inherited methods which are hidden by subclasses are filtered out |
| // No visibility checks can be performed without the scope & invocationSite |
| |
| int methodLength = methodName.length; |
| int minArgLength = argTypes == null ? 0 : argTypes.length; |
| |
| next : for (int f = methods.length; --f >= 0;) { |
| MethodBinding method = methods[f]; |
| |
| if (method.isSynthetic()) continue next; |
| |
| if (method.isDefaultAbstract()) continue next; |
| |
| if (method.isConstructor()) continue next; |
| |
| //TODO (david) perhaps the relevance of a void method must be lesser than other methods |
| //if (expectedTypesPtr > -1 && method.returnType == BaseTypes.VoidBinding) continue next; |
| |
| if (onlyStaticMethods && !method.isStatic()) continue next; |
| |
| if (this.options.checkVisibility |
| && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next; |
| |
| if(superCall && method.isAbstract()) { |
| methodsFound.add(new Object[]{method, receiverType}); |
| continue next; |
| } |
| |
| if (exactMatch) { |
| if (!CharOperation.equals(methodName, method.selector, false /* ignore case */ |
| )) |
| continue next; |
| |
| } else { |
| |
| if (methodLength > method.selector.length) |
| continue next; |
| |
| if (!CharOperation.prefixEquals(methodName, method.selector, false |
| /* ignore case */ |
| )) |
| continue next; |
| } |
| if (minArgLength > method.parameters.length) |
| continue next; |
| |
| for (int a = minArgLength; --a >= 0;){ |
| if (argTypes[a] != null){ // can be null if it could not be resolved properly |
| if (!argTypes[a].isCompatibleWith(method.parameters[a])) { |
| continue next; |
| } |
| } |
| } |
| |
| boolean prefixRequired = false; |
| |
| for (int i = methodsFound.size; --i >= 0;) { |
| Object[] other = (Object[]) methodsFound.elementAt(i); |
| MethodBinding otherMethod = (MethodBinding) other[0]; |
| ReferenceBinding otherReceiverType = (ReferenceBinding) other[1]; |
| if (method == otherMethod && receiverType == otherReceiverType) |
| continue next; |
| |
| if (CharOperation.equals(method.selector, otherMethod.selector, true) |
| && method.areParametersEqual(otherMethod)) { |
| |
| if (method.declaringClass.isSuperclassOf(otherMethod.declaringClass)) |
| continue next; |
| |
| if (otherMethod.declaringClass.isInterface()) { |
| if(method.declaringClass == scope.getJavaLangObject()) |
| continue next; |
| |
| if (method.declaringClass.isInterface()) |
| continue next; |
| |
| if (!superCall && method |
| .declaringClass |
| .implementsInterface(otherMethod.declaringClass, true)) |
| continue next; |
| } |
| |
| if (method.declaringClass.isInterface()) |
| if(otherMethod |
| .declaringClass |
| .implementsInterface(method.declaringClass,true)) |
| continue next; |
| |
| if(receiverType.isAnonymousType()) continue next; |
| |
| if(!superCall) { |
| if(canBePrefixed) { |
| prefixRequired = true; |
| } else { |
| continue next; |
| } |
| } |
| } |
| } |
| |
| newMethodsFound.add(new Object[]{method, receiverType}); |
| int length = method.parameters.length; |
| char[][] parameterPackageNames = new char[length][]; |
| char[][] parameterTypeNames = new char[length][]; |
| |
| for (int i = 0; i < length; i++) { |
| TypeBinding type = method.original().parameters[i]; |
| parameterPackageNames[i] = type.qualifiedPackageName(); |
| parameterTypeNames[i] = type.qualifiedSourceName(); |
| } |
| char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); |
| |
| char[] completion = CharOperation.NO_CHAR; |
| |
| int previousStartPosition = this.startPosition; |
| |
| // 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[] { '(', ')' }); |
| } else { |
| if(prefixRequired && (this.source != null)) { |
| completion = CharOperation.subarray(this.source, this.startPosition, this.endPosition); |
| } else { |
| this.startPosition = this.endPosition; |
| } |
| } |
| |
| if(prefixRequired || this.options.forceImplicitQualification){ |
| char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), method.isStatic()); |
| completion = CharOperation.concat(prefix,completion,'.'); |
| } |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(methodName, method.selector); |
| relevance += computeRelevanceForExpectingType(method.returnType); |
| relevance += computeRelevanceForStatic(onlyStaticMethods, method.isStatic()); |
| relevance += computeRelevanceForQualification(prefixRequired); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, 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(completion); |
| proposal.setFlags(method.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| if(parameterNames != null) proposal.setParameterNames(parameterNames); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| this.startPosition = previousStartPosition; |
| } |
| |
| methodsFound.addAll(newMethodsFound); |
| } |
| |
| // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean) |
| private void findLocalMethodsOfStaticImports( |
| char[] methodName, |
| MethodBinding[] methods, |
| Scope scope, |
| ReferenceBinding receiverType, |
| InvocationSite invocationSite) { |
| |
| next : for (int f = methods.length; --f >= 0;) { |
| MethodBinding method = methods[f]; |
| |
| if (method.isSynthetic()) continue next; |
| |
| if (method.isDefaultAbstract()) continue next; |
| |
| if (method.isConstructor()) continue next; |
| |
| if (!method.isStatic()) continue next; |
| |
| if (this.options.checkVisibility |
| && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next; |
| |
| if (!CharOperation.equals(methodName, method.selector, false /* ignore case */)) |
| continue next; |
| |
| int length = method.parameters.length; |
| char[][] parameterPackageNames = new char[length][]; |
| char[][] parameterTypeNames = new char[length][]; |
| |
| for (int i = 0; i < length; i++) { |
| TypeBinding type = method.original().parameters[i]; |
| parameterPackageNames[i] = type.qualifiedPackageName(); |
| parameterTypeNames[i] = type.qualifiedSourceName(); |
| } |
| char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); |
| |
| char[] completion = CharOperation.NO_CHAR; |
| |
| int previousStartPosition = this.startPosition; |
| |
| // nothing to insert - do not want to replace the existing selector & arguments |
| if (this.source != null |
| && this.source.length > this.endPosition |
| && this.source[this.endPosition] == '(') { |
| completion = method.selector; |
| } else { |
| completion = CharOperation.concat(method.selector, new char[] { '(', ')' }); |
| } |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(methodName, method.selector); |
| relevance += computeRelevanceForExpectingType(method.returnType); |
| relevance += computeRelevanceForStatic(true, method.isStatic()); |
| relevance += computeRelevanceForQualification(false); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_REF, 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(completion); |
| proposal.setFlags(method.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| if(parameterNames != null) proposal.setParameterNames(parameterNames); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| this.startPosition = previousStartPosition; |
| } |
| } |
| |
| int computeRelevanceForCaseMatching(char[] token, char[] proposalName){ |
| 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 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 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 computeRelevanceForStaticOveride(boolean isStatic) { |
| return isStatic ? 0 : R_NON_STATIC_OVERIDE; |
| } |
| private int computeRelevanceForException(char[] proposalName){ |
| |
| if(this.assistNodeIsException && |
| (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) { |
| for (int i = 0; i <= this.expectedTypesPtr; i++) { |
| if(CharOperation.equals(this.expectedTypes[i].qualifiedPackageName(), proposalType.qualifiedPackageName()) && |
| CharOperation.equals(this.expectedTypes[i].qualifiedSourceName(), proposalType.qualifiedSourceName())) { |
| return R_EXACT_EXPECTED_TYPE; |
| } |
| if((this.expectedTypesFilter & SUBTYPE) != 0 |
| && proposalType.isCompatibleWith(this.expectedTypes[i])) { |
| return R_EXPECTED_TYPE; |
| } |
| if((this.expectedTypesFilter & SUPERTYPE) != 0 |
| && this.expectedTypes[i].isCompatibleWith(proposalType)) { |
| return R_EXPECTED_TYPE; |
| } |
| } |
| } |
| 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; |
| } |
| } |
| } |
| return 0; |
| } |
| int computeRelevanceForInterestingProposal(){ |
| return computeRelevanceForInterestingProposal(null); |
| } |
| private int computeRelevanceForInterestingProposal(Binding binding){ |
| if(this.uninterestingBindings != null) { |
| for (int i = 0; i <= this.uninterestingBindingsPtr; i++) { |
| if(this.uninterestingBindings[i] == binding) { |
| return 0; |
| } |
| } |
| } |
| 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); |
| } |
| } |
| // 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 onlyStaticMethods, |
| 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()) continue next; |
| |
| // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next; |
| if(method.isStatic()) { |
| if(receiverType.isAnonymousType()) continue next; |
| |
| if(receiverType.isMemberType() && !receiverType.isStatic()) continue next; |
| |
| if(receiverType.isLocalType()) continue next; |
| } else { |
| if(onlyStaticMethods) continue next; |
| } |
| |
| if (this.options.checkVisibility |
| && !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 */ |
| )) |
| continue next; |
| } |
| |
| for (int i = methodsFound.size; --i >= 0;) { |
| MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i); |
| if (method == otherMethod) |
| continue next; |
| |
| if (CharOperation.equals(method.selector, otherMethod.selector, true) |
| && method.areParametersEqual(otherMethod)) { |
| continue next; |
| } |
| } |
| |
| newMethodsFound.add(method); |
| |
| int length = method.parameters.length; |
| char[][] parameterPackageNames = new char[length][]; |
| char[][] parameterTypeNames = new char[length][]; |
| |
| for (int i = 0; i < length; i++) { |
| TypeBinding type = method.parameters[i]; |
| parameterPackageNames[i] = type.qualifiedPackageName(); |
| parameterTypeNames[i] = type.qualifiedSourceName(); |
| } |
| |
| char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames); |
| |
| StringBuffer completion = new StringBuffer(10); |
| // flush uninteresting modifiers |
| int insertedModifiers = method.modifiers & ~(IConstants.AccNative | IConstants.AccAbstract); |
| |
| if (!exactMatch) { |
| if(insertedModifiers != CompilerModifiers.AccDefault){ |
| ASTNode.printModifiers(insertedModifiers, completion); |
| } |
| char[] returnPackageName = method.returnType.qualifiedPackageName(); |
| char[] returnTypeName = method.returnType.qualifiedSourceName(); |
| if(mustQualifyType(returnPackageName, returnTypeName)) { |
| completion.append(CharOperation.concat(returnPackageName, returnTypeName,'.')); |
| } else { |
| completion.append(method.returnType.sourceName()); |
| } |
| completion.append(' '); |
| completion.append(method.selector); |
| completion.append('('); |
| |
| for(int i = 0; i < length ; i++){ |
| if(mustQualifyType(parameterPackageNames[i], parameterTypeNames[i])){ |
| completion.append(CharOperation.concat(parameterPackageNames[i], parameterTypeNames[i], '.')); |
| } else { |
| completion.append(parameterTypeNames[i]); |
| } |
| completion.append(' '); |
| if(parameterNames != null){ |
| completion.append(parameterNames[i]); |
| } else { |
| completion.append('%'); |
| } |
| if(i != (length - 1)) |
| completion.append(','); |
| } |
| completion.append(')'); |
| |
| ReferenceBinding[] exceptions = method.thrownExceptions; |
| |
| if (exceptions != null && exceptions.length > 0){ |
| completion.append(' '); |
| completion.append(THROWS); |
| completion.append(' '); |
| for(int i = 0; i < exceptions.length ; i++){ |
| ReferenceBinding exception = exceptions[i]; |
| |
| char[] exceptionPackageName = exception.qualifiedPackageName(); |
| char[] exceptionTypeName = exception.qualifiedSourceName(); |
| |
| if(i != 0){ |
| completion.append(','); |
| completion.append(' '); |
| } |
| |
| if(mustQualifyType(exceptionPackageName, exceptionTypeName)){ |
| completion.append(CharOperation.concat(exceptionPackageName, exceptionTypeName, '.')); |
| } else { |
| completion.append(exception.sourceName()); |
| } |
| } |
| } |
| } |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(methodName, method.selector); |
| relevance += computeRelevanceForStaticOveride(method.isStatic()); |
| if(method.isAbstract()) relevance += R_ABSTRACT_METHOD; |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.METHOD_DECLARATION)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.METHOD_DECLARATION, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(getSignature(method.declaringClass)); |
| proposal.setDeclarationKey(method.declaringClass.computeUniqueKey()); |
| proposal.setSignature(getSignature(method)); |
| proposal.setKey(method.computeUniqueKey()); |
| 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.setCompletion(completion.toString().toCharArray()); |
| proposal.setName(method.selector); |
| proposal.setFlags(method.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| if(parameterNames != null) proposal.setParameterNames(parameterNames); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| methodsFound.addAll(newMethodsFound); |
| } |
| private void findMethods( |
| char[] selector, |
| TypeBinding[] argTypes, |
| ReferenceBinding receiverType, |
| Scope scope, |
| ObjectVector methodsFound, |
| boolean onlyStaticMethods, |
| boolean exactMatch, |
| boolean isCompletingDeclaration, |
| InvocationSite invocationSite, |
| Scope invocationScope, |
| boolean implicitCall, |
| boolean superCall, |
| boolean canBePrefixed) { |
| if (selector == null) |
| return; |
| |
| 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]); |
| } |
| } |
| } |
| } |
| |
| ReferenceBinding currentType = receiverType; |
| if (receiverType.isInterface()) { |
| if(isCompletingDeclaration) { |
| findIntefacesMethods( |
| selector, |
| argTypes, |
| receiverType, |
| currentType.superInterfaces(), |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| isCompletingDeclaration, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| canBePrefixed); |
| } else { |
| findIntefacesMethods( |
| selector, |
| argTypes, |
| receiverType, |
| new ReferenceBinding[]{currentType}, |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| isCompletingDeclaration, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| canBePrefixed); |
| } |
| |
| currentType = scope.getJavaLangObject(); |
| } else { |
| if(isCompletingDeclaration){ |
| findIntefacesMethods( |
| selector, |
| argTypes, |
| receiverType, |
| currentType.superInterfaces(), |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| isCompletingDeclaration, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| canBePrefixed); |
| |
| currentType = receiverType.superclass(); |
| } |
| } |
| boolean hasPotentialDefaultAbstractMethods = true; |
| while (currentType != null) { |
| |
| MethodBinding[] methods = currentType.availableMethods(); |
| if(methods != null) { |
| if(isCompletingDeclaration){ |
| findLocalMethodDeclarations( |
| selector, |
| methods, |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| receiverType); |
| } else{ |
| findLocalMethods( |
| selector, |
| argTypes, |
| methods, |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| receiverType, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| canBePrefixed); |
| } |
| } |
| |
| if(hasPotentialDefaultAbstractMethods && currentType.isAbstract()){ |
| findIntefacesMethods( |
| selector, |
| argTypes, |
| receiverType, |
| currentType.superInterfaces(), |
| scope, |
| methodsFound, |
| onlyStaticMethods, |
| exactMatch, |
| isCompletingDeclaration, |
| invocationSite, |
| invocationScope, |
| implicitCall, |
| superCall, |
| canBePrefixed); |
| } else { |
| hasPotentialDefaultAbstractMethods = false; |
| } |
| currentType = currentType.superclass(); |
| } |
| } |
| private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){ |
| ReferenceBinding bindingType = method.declaringClass; |
| |
| 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 (bindingType instanceof SourceTypeBinding){ |
| SourceTypeBinding sourceType = (SourceTypeBinding) bindingType; |
| |
| if (sourceType.scope != null){ |
| TypeDeclaration parsedType; |
| |
| if ((parsedType = sourceType.scope.referenceContext) != null){ |
| AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method.original()); |
| |
| if (methodDecl != null){ |
| Argument[] arguments = methodDecl.arguments; |
| parameterNames = new char[length][]; |
| |
| for(int i = 0 ; i < length ; i++){ |
| parameterNames[i] = arguments[i].name; |
| } |
| } |
| } |
| } |
| } |
| // look into the model |
| if(parameterNames == null){ |
| char[] compoundName = CharOperation.concatWith(bindingType.compoundName, '.'); |
| Object type = this.typeCache.get(compoundName); |
| |
| ISourceType sourceType = null; |
| if(type != null) { |
| if(type instanceof ISourceType) { |
| sourceType = (ISourceType) type; |
| } |
| } else { |
| NameEnvironmentAnswer answer = this.nameEnvironment.findType(bindingType.compoundName); |
| if(answer != null && answer.isSourceType()) { |
| sourceType = answer.getSourceTypes()[0]; |
| this.typeCache.put(compoundName, sourceType); |
| } |
| } |
| |
| if(sourceType != null) { |
| SourceMethod[] sourceMethods = ((SourceTypeElementInfo) sourceType).getMethodHandles(); |
| int len = sourceMethods.length; |
| for(int i = 0; i < len ; i++){ |
| SourceMethod sourceMethod = sourceMethods[i]; |
| String[] argTypeSignatures = sourceMethod.getParameterTypes(); |
| |
| if(argTypeSignatures != null && |
| CharOperation.equals(method.selector,sourceMethod.getElementName().toCharArray()) && |
| equalSignatures(parameterTypeNames, argTypeSignatures)){ |
| try { |
| parameterNames = ((SourceMethodElementInfo) sourceMethod.getElementInfo()).getArgumentNames(); |
| break; |
| } catch (JavaModelException e) { |
| // method doesn't exist: ignore |
| } |
| } |
| } |
| } |
| } |
| return parameterNames; |
| } |
| |
| private boolean equalSignatures(char[][] typeNames, String[] typeSignatures) { |
| if (typeNames == null || typeSignatures == null) |
| return false; |
| if (typeNames.length != typeSignatures.length) |
| return false; |
| |
| for (int i = typeNames.length; --i >= 0;) |
| if (!CharOperation.equals(typeNames[i], Signature.toCharArray(typeSignatures[i].toCharArray()))) |
| return false; |
| return true; |
| } |
| |
| private void findNestedTypes( |
| char[] typeName, |
| SourceTypeBinding currentType, |
| Scope scope, |
| ObjectVector typesFound) { |
| if (typeName == null) |
| return; |
| |
| int typeLength = typeName.length; |
| |
| while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found |
| |
| switch (scope.kind) { |
| |
| case Scope.METHOD_SCOPE : |
| case Scope.BLOCK_SCOPE : |
| BlockScope blockScope = (BlockScope) scope; |
| |
| next : for (int i = 0, length = blockScope.subscopeCount; i < length; i++) { |
| |
| if (blockScope.subscopes[i] instanceof ClassScope) { |
| SourceTypeBinding localType = |
| ((ClassScope) blockScope.subscopes[i]).referenceContext.binding; |
| |
| if (!localType.isAnonymousType()) { |
| if (this.isForbidden(localType)) |
| continue next; |
| if (typeLength > localType.sourceName.length) |
| continue next; |
| if (!CharOperation.prefixEquals(typeName, localType.sourceName, false |
| /* ignore case */ |
| )) |
| continue next; |
| |
| int relevance = computeBaseRelevance(); |
| 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 |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(localType.qualifiedPackageName()); |
| proposal.setSignature(getSignature(localType)); |
| proposal.setPackageName(localType.qualifiedPackageName()); |
| proposal.setTypeName(localType.sourceName); |
| proposal.setCompletion(localType.sourceName); |
| proposal.setFlags(localType.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| } |
| break; |
| |
| case Scope.CLASS_SCOPE : |
| findMemberTypes(typeName, scope.enclosingSourceType(), scope, currentType, false, typesFound); |
| if (typeLength == 0) |
| return; // do not search outside the class scope if no prefix was provided |
| break; |
| |
| case Scope.COMPILATION_UNIT_SCOPE : |
| return; |
| } |
| scope = scope.parent; |
| } |
| } |
| |
| private void findPackages(CompletionOnPackageReference packageStatement) { |
| |
| this.completionToken = CharOperation.concatWith(packageStatement.tokens, '.'); |
| if (this.completionToken.length == 0) |
| return; |
| |
| setSourceRange(packageStatement.sourceStart, packageStatement.sourceEnd); |
| this.nameEnvironment.findPackages(CharOperation.toLowerCase(this.completionToken), this); |
| } |
| |
| private void findTypeParameters(char[] token, Scope scope) { |
| if (this.compilerOptions.sourceLevel < ClassFileConstants.JDK1_5) return; |
| |
| TypeParameter[] typeParameters = null; |
| while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found |
| typeParameters = null; |
| switch (scope.kind) { |
| case Scope.METHOD_SCOPE : |
| MethodScope methodScope = (MethodScope) scope; |
| if(methodScope.referenceContext instanceof MethodDeclaration) { |
| MethodDeclaration methodDeclaration = (MethodDeclaration) methodScope.referenceContext; |
| typeParameters = methodDeclaration.typeParameters; |
| } else if(methodScope.referenceContext instanceof ConstructorDeclaration) { |
| ConstructorDeclaration methodDeclaration = (ConstructorDeclaration) methodScope.referenceContext; |
| typeParameters = methodDeclaration.typeParameters; |
| } |
| break; |
| case Scope.CLASS_SCOPE : |
| ClassScope classScope = (ClassScope) scope; |
| typeParameters = classScope.referenceContext.typeParameters; |
| break; |
| case Scope.COMPILATION_UNIT_SCOPE : |
| return; |
| } |
| if(typeParameters != null) { |
| for (int i = 0; i < typeParameters.length; i++) { |
| int typeLength = token.length; |
| TypeParameter typeParameter = typeParameters[i]; |
| |
| if(typeParameter.binding == null) continue; |
| |
| if (typeLength > typeParameter.name.length) continue; |
| |
| if (!CharOperation.prefixEquals(token, typeParameter.name, false)) continue; |
| |
| int relevance = computeBaseRelevance(); |
| 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)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| //proposal.setDeclarationSignature(null); |
| proposal.setSignature(getSignature(typeParameter.binding)); |
| //proposal.setPackageName(null); |
| proposal.setTypeName(typeParameter.name); |
| proposal.setCompletion(typeParameter.name); |
| proposal.setFlags(typeParameter.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| scope = scope.parent; |
| } |
| } |
| |
| private void findTypesAndPackages(char[] token, Scope scope) { |
| |
| if (token == null) |
| return; |
| |
| boolean proposeType = !this.requestor.isIgnored(CompletionProposal.TYPE_REF); |
| |
| ObjectVector typesFound = new ObjectVector(); |
| |
| if (proposeType && scope.enclosingSourceType() != null) { |
| findNestedTypes(token, scope.enclosingSourceType(), scope, typesFound); |
| findTypeParameters(token, scope); |
| } |
| |
| if (proposeType && this.unitScope != null) { |
| int typeLength = token.length; |
| SourceTypeBinding[] types = this.unitScope.topLevelTypes; |
| |
| for (int i = 0, length = types.length; i < length; i++) { |
| SourceTypeBinding sourceType = types[i]; |
| |
| if (sourceType.sourceName == CompletionParser.FAKE_TYPE_NAME) continue; |
| if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME) continue; |
| |
| if (typeLength > sourceType.sourceName.length) continue; |
| |
| if (!CharOperation.prefixEquals(token, sourceType.sourceName, false)) continue; |
| |
| this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this); |
| |
| if(isForbidden(sourceType)) continue; |
| |
| int relevance = computeBaseRelevance(); |
| 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 |
| |
| if (sourceType.isAnnotationType()) { |
| relevance += computeRelevanceForAnnotation(); |
| } else if (sourceType.isInterface()) { |
| relevance += computeRelevanceForInterface(); |
| } else { |
| relevance += computeRelevanceForClass(); |
| relevance += computeRelevanceForException(sourceType.sourceName); |
| } |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(sourceType.qualifiedPackageName()); |
| proposal.setSignature(getSignature(sourceType)); |
| proposal.setPackageName(sourceType.qualifiedPackageName()); |
| proposal.setTypeName(sourceType.sourceName()); |
| proposal.setCompletion(sourceType.sourceName()); |
| proposal.setFlags(sourceType.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| if(proposeType) { |
| this.findTypesFromStaticImports(token, scope, typesFound); |
| } |
| |
| if (token.length == 0) { |
| 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]; |
| |
| int accessibility = IAccessRule.K_ACCESSIBLE; |
| if(refBinding.hasRestrictedAccess()) { |
| AccessRestriction accessRestriction = 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; |
| } |
| } |
| } |
| |
| boolean inSameUnit = this.unitScope.isDefinedInSameUnit(refBinding); |
| |
| // top level types of the current unit are already proposed. |
| if(!inSameUnit || (inSameUnit && refBinding.isMemberType())) { |
| char[] packageName = refBinding.qualifiedPackageName(); |
| char[] typeName = refBinding.sourceName(); |
| char[] completionName = typeName; |
| |
| boolean isQualified = false; |
| if (!this.insideQualifiedReference && !refBinding.isMemberType()) { |
| if (mustQualifyType(packageName, typeName)) { |
| 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; |
| } |
| } |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(token, typeName); |
| relevance += computeRelevanceForExpectingType(refBinding); |
| relevance += computeRelevanceForQualification(isQualified); |
| relevance += computeRelevanceForRestrictions(accessibility); |
| |
| if(refBinding.isClass()) { |
| relevance += computeRelevanceForClass(); |
| } else if(refBinding.isEnum()) { |
| relevance += computeRelevanceForEnum(); |
| } else if(refBinding.isInterface()) { |
| relevance += computeRelevanceForInterface(); |
| } |
| |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| proposal.setAccessibility(accessibility); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| } |
| } |
| } else { |
| if(!this.requestor.isIgnored(CompletionProposal.KEYWORD)) { |
| findKeywords(token, baseTypes); |
| } |
| if(proposeType) { |
| this.nameEnvironment.findTypes(token, this); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { |
| this.nameEnvironment.findPackages(token, this); |
| } |
| } |
| } |
| |
| private void findTypesAndSubpackages( |
| char[] token, |
| PackageBinding packageBinding) { |
| |
| boolean proposeType = !this.requestor.isIgnored(CompletionProposal.TYPE_REF); |
| |
| char[] qualifiedName = |
| CharOperation.concatWith(packageBinding.compoundName, token, '.'); |
| |
| if (token == null || token.length == 0) { |
| int length = qualifiedName.length; |
| System.arraycopy( |
| qualifiedName, |
| 0, |
| qualifiedName = new char[length + 1], |
| 0, |
| length); |
| qualifiedName[length] = '.'; |
| } |
| |
| this.qualifiedCompletionToken = qualifiedName; |
| |
| if (proposeType && this.unitScope != null) { |
| int typeLength = qualifiedName.length; |
| SourceTypeBinding[] types = this.unitScope.topLevelTypes; |
| |
| for (int i = 0, length = types.length; i < length; i++) { |
| SourceTypeBinding sourceType = types[i]; |
| |
| char[] qualifiedSourceTypeName = CharOperation.concatWith(sourceType.compoundName, '.'); |
| |
| if (sourceType.sourceName == CompletionParser.FAKE_TYPE_NAME) continue; |
| if (sourceType.sourceName == TypeConstants.PACKAGE_INFO_NAME) continue; |
| if (typeLength > qualifiedSourceTypeName.length) continue; |
| if (!(packageBinding == sourceType.getPackage())) continue; |
| if (!CharOperation.prefixEquals(qualifiedName, qualifiedSourceTypeName, false)) continue; |
| |
| int accessibility = IAccessRule.K_ACCESSIBLE; |
| if(sourceType.hasRestrictedAccess()) { |
| AccessRestriction accessRestriction = lookupEnvironment.getAccessRestriction(sourceType); |
| 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; |
| } |
| } |
| } |
| |
| this.knownTypes.put(CharOperation.concat(sourceType.qualifiedPackageName(), sourceType.sourceName(), '.'), this); |
| |
| int relevance = computeBaseRelevance(); |
| 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 { |
| relevance += computeRelevanceForClass(); |
| relevance += computeRelevanceForException(sourceType.sourceName); |
| } |
| this.noProposal = false; |
| if(!this.requestor.isIgnored(CompletionProposal.TYPE_REF)) { |
| CompletionProposal proposal = this.createProposal(CompletionProposal.TYPE_REF, this.actualCompletionPosition); |
| proposal.setDeclarationSignature(sourceType.qualifiedPackageName()); |
| proposal.setSignature(getSignature(sourceType)); |
| proposal.setPackageName(sourceType.qualifiedPackageName()); |
| proposal.setTypeName(sourceType.sourceName()); |
| proposal.setCompletion(sourceType.sourceName()); |
| proposal.setFlags(sourceType.modifiers); |
| proposal.setReplaceRange(this.startPosition - this.offset, this.endPosition - this.offset); |
| proposal.setRelevance(relevance); |
| proposal.setAccessibility(accessibility); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| |
| if(proposeType) { |
| this.nameEnvironment.findTypes(qualifiedName, this); |
| } |
| if(!this.requestor.isIgnored(CompletionProposal.PACKAGE_REF)) { |
| this.nameEnvironment.findPackages(qualifiedName, this); |
| } |
| } |
| |
| private void findTypesFromStaticImports(char[] token, Scope scope, 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, |
| typesFound); |
| } |
| } 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)) continue; |
| |
| if (typesFound.contains(typeBinding)) continue; |
| |
| typesFound.add(typeBinding); |
| |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(token, typeBinding.sourceName); |
| relevance += computeRelevanceForExpectingType(typeBinding); |
| 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)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| 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; |
| |
| 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 */ |
| )) |
| 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 += computeRelevanceForInterestingProposal(local); |
| relevance += computeRelevanceForCaseMatching(token, local.name); |
| relevance += computeRelevanceForExpectingType(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)) { |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| break; |
| |
| case Scope.COMPILATION_UNIT_SCOPE : |
| break done1; |
| } |
| currentScope = currentScope.parent; |
| } |
| } |
| |
| boolean proposeField = !this.requestor.isIgnored(CompletionProposal.FIELD_REF); |
| boolean proposeMethod = !this.requestor.isIgnored(CompletionProposal.METHOD_REF); |
| |
| staticsOnly = false; |
| currentScope = scope; |
| |
| if(proposeField || proposeMethod) { |
| done2 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found |
| |
| switch (currentScope.kind) { |
| case Scope.METHOD_SCOPE : |
| // handle the error case inside an explicit constructor call (see MethodScope>>findField) |
| MethodScope methodScope = (MethodScope) currentScope; |
| staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall; |
| break; |
| case Scope.CLASS_SCOPE : |
| ClassScope classScope = (ClassScope) currentScope; |
| SourceTypeBinding enclosingType = classScope.referenceContext.binding; |
| /* if (tokenLength == 0) { // only search inside the type itself if no prefix was provided |
| findFields(token, enclosingType.fields(), classScope, fieldsFound, staticsOnly); |
| findMethods(token, enclosingType.methods(), classScope, methodsFound, staticsOnly, false); |
| break done; |
| } else { */ |
| if(!insideTypeAnnotation) { |
| if(proposeField) { |
| findFields( |
| token, |
| enclosingType, |
| classScope, |
| fieldsFound, |
| localsFound, |
| staticsOnly, |
| invocationSite, |
| invocationScope, |
| true, |
| true); |
| } |
| if(proposeMethod && !insideAnnotationAttribute) { |
| findMethods( |
| token, |
| null, |
| enclosingType, |
| classScope, |
| methodsFound, |
| staticsOnly, |
| false, |
| false, |
| invocationSite, |
| invocationScope, |
| true, |
| false, |
| true); |
| } |
| } |
| staticsOnly |= enclosingType.isStatic(); |
| insideTypeAnnotation = false; |
| // } |
| break; |
| |
| case Scope.COMPILATION_UNIT_SCOPE : |
| break done2; |
| } |
| currentScope = currentScope.parent; |
| } |
| |
| 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); |
| } |
| if(proposeMethod && !insideAnnotationAttribute) { |
| findMethods( |
| token, |
| null, |
| (ReferenceBinding)binding, |
| scope, |
| methodsFound, |
| true, |
| false, |
| false, |
| invocationSite, |
| invocationScope, |
| true, |
| false, |
| false); |
| } |
| } |
| } 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); |
| } |
| } else if ((binding.kind() & Binding.METHOD) != 0) { |
| if(proposeMethod && !insideAnnotationAttribute) { |
| MethodBinding methodBinding = (MethodBinding)binding; |
| if(CharOperation.prefixEquals(token, methodBinding.selector)) |
| |
| findLocalMethodsOfStaticImports( |
| methodBinding.selector, |
| methodBinding.declaringClass.methods(), |
| scope, |
| methodBinding.declaringClass, |
| invocationSite); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| // 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[][] excludeNames, |
| int dim, |
| int kind, |
| int modifiers){ |
| |
| if(sourceName == null || sourceName.length == 0) |
| return; |
| |
| // compute variable name for non base type |
| final char[] displayName; |
| 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; |
| } |
| |
| final char[] t = token; |
| final char[] q = qualifiedPackageName; |
| INamingRequestor namingRequestor = new INamingRequestor() { |
| public void acceptNameWithPrefixAndSuffix(char[] name, boolean isFirstPrefix, boolean isFirstSuffix) { |
| accept( name, |
| (isFirstPrefix ? R_NAME_FIRST_PREFIX : R_NAME_PREFIX) + (isFirstSuffix ? R_NAME_FIRST_SUFFIX : R_NAME_SUFFIX)); |
| } |
| |
| public void acceptNameWithPrefix(char[] name, boolean isFirstPrefix) { |
| accept(name, isFirstPrefix ? R_NAME_FIRST_PREFIX : R_NAME_PREFIX); |
| } |
| |
| public void acceptNameWithSuffix(char[] name, boolean isFirstSuffix) { |
| accept(name, isFirstSuffix ? R_NAME_FIRST_SUFFIX : R_NAME_SUFFIX); |
| } |
| |
| public void acceptNameWithoutPrefixAndSuffix(char[] name) { |
| accept(name, 0); |
| } |
| void accept(char[] name, int prefixAndSuffixRelevance){ |
| if (CharOperation.prefixEquals(t, name, false)) { |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForCaseMatching(t, name); |
| relevance += prefixAndSuffixRelevance; |
| 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)) { |
| CompletionProposal 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.setRelevance(relevance); |
| CompletionEngine.this.requestor.accept(proposal); |
| if(DEBUG) { |
| CompletionEngine.this.printDebug(proposal); |
| } |
| } |
| } |
| } |
| }; |
| |
| switch (kind) { |
| case FIELD : |
| InternalNamingConventions.suggestFieldNames( |
| this.javaProject, |
| qualifiedPackageName, |
| qualifiedSourceName, |
| dim, |
| modifiers, |
| excludeNames, |
| namingRequestor); |
| break; |
| case LOCAL : |
| InternalNamingConventions.suggestLocalVariableNames( |
| this.javaProject, |
| qualifiedPackageName, |
| qualifiedSourceName, |
| dim, |
| excludeNames, |
| namingRequestor); |
| break; |
| case ARGUMENT : |
| InternalNamingConventions.suggestArgumentNames( |
| this.javaProject, |
| qualifiedPackageName, |
| qualifiedSourceName, |
| dim, |
| excludeNames, |
| namingRequestor); |
| break; |
| } |
| } |
| |
| private void findVariableNames(char[] name, TypeReference type , char[][] excludeNames, int kind, int modifiers){ |
| |
| if(type != null && |
| type.resolvedType != null && |
| type.resolvedType.problemId() == ProblemReasons.NoError){ |
| TypeBinding tb = type.resolvedType; |
| findVariableName( |
| name, |
| tb.leafComponentType().qualifiedPackageName(), |
| tb.leafComponentType().qualifiedSourceName(), |
| tb.leafComponentType().sourceName(), |
| tb, |
| excludeNames, |
| type.dimensions(), |
| kind, |
| modifiers); |
| }/* else { |
| char[][] typeName = type.getTypeName(); |
| findVariableName( |
| name, |
| NoChar, |
| CharOperation.concatWith(typeName, '.'), |
| typeName[typeName.length - 1], |
| excludeNames, |
| type.dimensions()); |
| }*/ |
| } |
| |
| public AssistParser getParser() { |
| |
| return this.parser; |
| } |
| |
| protected void reset() { |
| |
| super.reset(); |
| this.knownPkgs = new HashtableOfObject(10); |
| this.knownTypes = new HashtableOfObject(10); |
| } |
| |
| 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; |
| } |
| } |
| int computeBaseRelevance(){ |
| return R_DEFAULT; |
| } |
| private void computeExpectedTypes(ASTNode parent, ASTNode node, Scope scope){ |
| |
| // default filter |
| this.expectedTypesFilter = SUBTYPE; |
| |
| // 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); |
| } |
| } |
| } else if(parent instanceof Assignment) { |
| TypeBinding binding = ((Assignment)parent).resolvedType; |
| if(binding != null) { |
| addExpectedType(binding); |
| } |
| } 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); |
| } |
| } |
| } else if(parent instanceof CastExpression) { |
| Expression e = ((CastExpression)parent).type; |
| TypeBinding binding = e.resolvedType; |
| if(binding != null){ |
| addExpectedType(binding); |
| this.expectedTypesFilter = SUBTYPE | SUPERTYPE; |
| } |
| } else if(parent instanceof MessageSend) { |
| MessageSend messageSend = (MessageSend) parent; |
| |
| if(messageSend.actualReceiverType instanceof ReferenceBinding) { |
| ReferenceBinding binding = (ReferenceBinding)messageSend.actualReceiverType; |
| boolean isStatic = messageSend.receiver.isTypeReference(); |
| |
| while(binding != null) { |
| computeExpectedTypesForMessageSend( |
| binding, |
| messageSend.selector, |
| messageSend.arguments, |
| (ReferenceBinding)messageSend.actualReceiverType, |
| scope, |
| messageSend, |
| isStatic); |
| computeExpectedTypesForMessageSendForInterface( |
| binding, |
| messageSend.selector, |
| messageSend.arguments, |
| (ReferenceBinding)messageSend.actualReceiverType, |
| scope, |
| messageSend, |
| isStatic); |
| binding = binding.superclass(); |
| } |
| } |
| } else if(parent instanceof AllocationExpression) { |
| AllocationExpression allocationExpression = (AllocationExpression) parent; |
| |
| ReferenceBinding binding = (ReferenceBinding)allocationExpression.type.resolvedType; |
| |
| if(binding != null) { |
| computeExpectedTypesForAllocationExpression( |
| binding, |
| allocationExpression.arguments, |
| scope, |
| allocationExpression); |
| } |
| } else if(parent instanceof OperatorExpression) { |
| int operator = (parent.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT; |
| if(parent instanceof ConditionalExpression) { |
| // for future use |
| } else if(parent instanceof InstanceOfExpression) { |
| InstanceOfExpression e = (InstanceOfExpression) parent; |
| TypeBinding binding = e.expression.resolvedType; |
| if(binding != null){ |
| addExpectedType(binding); |
| this.expectedTypesFilter = SUBTYPE | SUPERTYPE; |
| } |
| } else if(parent instanceof BinaryExpression) { |
| switch(operator) { |
| case OperatorIds.PLUS : |
| addExpectedType(BaseTypes.ShortBinding); |
| addExpectedType(BaseTypes.IntBinding); |
| addExpectedType(BaseTypes.LongBinding); |
| addExpectedType(BaseTypes.FloatBinding); |
| addExpectedType(BaseTypes.DoubleBinding); |
| addExpectedType(BaseTypes.CharBinding); |
| addExpectedType(BaseTypes.ByteBinding); |
| addExpectedType(scope.getJavaLangString()); |
| break; |
| case OperatorIds.AND_AND : |
| case OperatorIds.OR_OR : |
| case OperatorIds.XOR : |
| addExpectedType(BaseTypes.BooleanBinding); |
| break; |
| default : |
| addExpectedType(BaseTypes.ShortBinding); |
| addExpectedType(BaseTypes.IntBinding); |
| addExpectedType(BaseTypes.LongBinding); |
| addExpectedType(BaseTypes.FloatBinding); |
| addExpectedType(BaseTypes.DoubleBinding); |
| addExpectedType(BaseTypes.CharBinding); |
| addExpectedType(BaseTypes.ByteBinding); |
| break; |
| } |
| BinaryExpression binaryExpression = (BinaryExpression) parent; |
| 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); |
| } |
| |
| } |
| } |
| } |
| } else if(parent instanceof UnaryExpression) { |
| switch(operator) { |
| case OperatorIds.NOT : |
| addExpectedType(BaseTypes.BooleanBinding); |
| break; |
| case OperatorIds.TWIDDLE : |
| addExpectedType(BaseTypes.ShortBinding); |
| addExpectedType(BaseTypes.IntBinding); |
| addExpectedType(BaseTypes.LongBinding); |
| addExpectedType(BaseTypes.CharBinding); |
| addExpectedType(BaseTypes.ByteBinding); |
| break; |
| case OperatorIds.PLUS : |
| case OperatorIds.MINUS : |
| case OperatorIds.PLUS_PLUS : |
| case OperatorIds.MINUS_MINUS : |
| addExpectedType(BaseTypes.ShortBinding); |
| addExpectedType(BaseTypes.IntBinding); |
| addExpectedType(BaseTypes.LongBinding); |
| addExpectedType(BaseTypes.FloatBinding); |
| addExpectedType(BaseTypes.DoubleBinding); |
| addExpectedType(BaseTypes.CharBinding); |
| addExpectedType(BaseTypes.ByteBinding); |
| break; |
| } |
| } |
| } else if(parent instanceof ArrayReference) { |
| addExpectedType(BaseTypes.ShortBinding); |
| addExpectedType(BaseTypes.IntBinding); |
| addExpectedType(BaseTypes.LongBinding); |
| } 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--; |
| addExpectedType(typeVariables[index].firstBound); |
| } |
| } 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) { |
| addExpectedType(typeVariables[j].firstBound); |
| break done; |
| } |
| } |
| } |
| } |
| } else if(parent instanceof MemberValuePair) { |
| MemberValuePair memberValuePair = (MemberValuePair) parent; |
| if(memberValuePair.binding != null) { |
| addExpectedType(memberValuePair.binding.returnType); |
| } |
| } 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 == 1 && |
| CharOperation.equals(methodBindings[0].selector, VALUE)) { |
| addExpectedType(methodBindings[0].returnType); |
| } |
| } |
| } |
| } |
| |
| if(this.expectedTypesPtr + 1 != this.expectedTypes.length) { |
| System.arraycopy(this.expectedTypes, 0, this.expectedTypes = new TypeBinding[this.expectedTypesPtr + 1], 0, this.expectedTypesPtr + 1); |
| } |
| } |
| |
| private void computeExpectedTypesForAllocationExpression( |
| ReferenceBinding binding, |
| Expression[] arguments, |
| Scope scope, |
| InvocationSite invocationSite) { |
| |
| MethodBinding[] methods = binding.availableMethods(); |
| nextMethod : for (int i = 0; i < methods.length; i++) { |
| MethodBinding method = methods[i]; |
| |
| if (!method.isConstructor()) continue nextMethod; |
| |
| if (method.isSynthetic()) continue nextMethod; |
| |
| if (this.options.checkVisibility && !method.canBeSeenBy(invocationSite, scope)) continue nextMethod; |
| |
| TypeBinding[] parameters = method.parameters; |
| if(parameters.length < arguments.length) |
| continue nextMethod; |
| |
| int length = arguments.length - 1; |
| |
| for (int j = 0; j < length; j++) { |
| Expression argument = arguments[j]; |
| TypeBinding argType = argument.resolvedType; |
| if(argType != null && !argType.isCompatibleWith(parameters[j])) |
| continue nextMethod; |
| } |
| |
| TypeBinding expectedType = method.parameters[arguments.length - 1]; |
| if(expectedType != null) { |
| addExpectedType(expectedType); |
| } |
| } |
| } |
| |
| private void computeExpectedTypesForMessageSendForInterface( |
| ReferenceBinding binding, |
| char[] selector, |
| Expression[] arguments, |
| ReferenceBinding receiverType, |
| Scope scope, |
| InvocationSite invocationSite, |
| boolean isStatic) { |
| |
| ReferenceBinding[] itsInterfaces = binding.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][]; |
| int lastPosition = 0; |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| |
| for (int j = 0, length = interfaces.length; j < length; j++) { |
| ReferenceBinding currentType = interfaces[j]; |
| |
| if ((currentType.tagBits & TagBits.InterfaceVisited) == 0) { |
| // if interface as not already been visited |
| currentType.tagBits |= TagBits.InterfaceVisited; |
| |
| computeExpectedTypesForMessageSend( |
| currentType, |
| selector, |
| arguments, |
| receiverType, |
| scope, |
| invocationSite, |
| isStatic); |
| |
| itsInterfaces = currentType.superInterfaces(); |
| if (itsInterfaces != NoSuperInterfaces) { |
| |
| if (++lastPosition == interfacesToVisit.length) |
| System.arraycopy( |
| interfacesToVisit, |
| 0, |
| interfacesToVisit = new ReferenceBinding[lastPosition * 2][], |
| 0, |
| lastPosition); |
| interfacesToVisit[lastPosition] = itsInterfaces; |
| } |
| } |
| } |
| } |
| |
| // bit reinitialization |
| for (int i = 0; i <= lastPosition; i++) { |
| ReferenceBinding[] interfaces = interfacesToVisit[i]; |
| |
| for (int j = 0, length = interfaces.length; j < length; j++){ |
| interfaces[j].tagBits &= ~TagBits.InterfaceVisited; |
| } |
| } |
| } |
| } |
| |
| private void computeExpectedTypesForMessageSend( |
| ReferenceBinding binding, |
| char[] selector, |
| Expression[] arguments, |
| ReferenceBinding receiverType, |
| Scope scope, |
| InvocationSite invocationSite, |
| boolean isStatic) { |
| |
| MethodBinding[] methods = binding.availableMethods(); |
| nextMethod : for (int i = 0; i < methods.length; i++) { |
| MethodBinding method = methods[i]; |
| |
| if (method.isSynthetic()) continue nextMethod; |
| |
| if (method.isDefaultAbstract()) continue nextMethod; |
| |
| if (method.isConstructor()) continue nextMethod; |
| |
| if (isStatic && !method.isStatic()) continue nextMethod; |
| |
| if (this.options.checkVisibility && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue nextMethod; |
| |
| if(!CharOperation.equals(method.selector, selector)) continue nextMethod; |
| |
| TypeBinding[] parameters = method.parameters; |
| if(parameters.length < arguments.length) |
| continue nextMethod; |
| |
| int length = arguments.length - 1; |
| |
| for (int j = 0; j < length; j++) { |
| Expression argument = arguments[j]; |
| TypeBinding argType = argument.resolvedType; |
| if(argType != null && !argType.isCompatibleWith(parameters[j])) |
| continue nextMethod; |
| } |
| |
| TypeBinding expectedType = method.parameters[arguments.length - 1]; |
| if(expectedType != null) { |
| addExpectedType(expectedType); |
| } |
| } |
| } |
| private void addExpectedType(TypeBinding type){ |
| if (type == null || !type.isValidBinding()) 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; |
| } |
| 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; |
| } |
| |
| private Scope computeForbiddenBindings(ASTNode astNode, ASTNode astNodeParent, Scope scope) { |
| if(scope instanceof ClassScope) { |
| TypeDeclaration typeDeclaration = ((ClassScope)scope).referenceContext; |
| if(typeDeclaration.superclass == astNode) { |
| this.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) { |
| this.addForbiddenBindings(typeDeclaration.binding); |
| return scope.parent; |
| } |
| } |
| } |
| // 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(); |
| } |
| |
| private void proposeNewMethod(char[] token, ReferenceBinding reference) { |
| if(!this.requestor.isIgnored(CompletionProposal.POTENTIAL_METHOD_DECLARATION)) { |
| int relevance = computeBaseRelevance(); |
| relevance += computeRelevanceForInterestingProposal(); |
| relevance += computeRelevanceForRestrictions(IAccessRule.K_ACCESSIBLE); // no access restriction for new method |
| |
| CompletionProposal proposal = this.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.setRelevance(relevance); |
| this.requestor.accept(proposal); |
| if(DEBUG) { |
| this.printDebug(proposal); |
| } |
| } |
| } |
| private boolean isForbidden(Binding binding) { |
| for (int i = 0; i <= this.forbbidenBindingsPtr; i++) { |
| if(this.forbbidenBindings[i] == binding) { |
| return true; |
| } |
| } |
| return false; |
| } |
| private boolean isValidParent(ASTNode parent, ASTNode node, Scope scope){ |
| |
| if(parent instanceof ParameterizedSingleTypeReference) { |
| ParameterizedSingleTypeReference ref = (ParameterizedSingleTypeReference) parent; |
| TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables(); |
| int length = ref.typeArguments == null ? 0 : ref.typeArguments.length; |
| int nodeIndex = -1; |
| for(int i = length - 1 ; i > -1 ; i--) { |
| if(node == ref.typeArguments[i]) { |
| nodeIndex = i; |
| break; |
| } |
| } |
| if(nodeIndex > -1 && (typeVariables == null || typeVariables.length < nodeIndex + 1)) { |
| TypeBinding[] typeBindings = new TypeBinding[nodeIndex + 1]; |
| for(int i = 0; i < nodeIndex; i++) { |
| typeBindings[i] = ref.typeArguments[i].resolvedType; |
| } |
| typeBindings[nodeIndex] = scope.getJavaLangObject(); |
| if(typeVariables == null || typeVariables.length == 0) { |
| scope.problemReporter().nonGenericTypeCannotBeParameterized(ref, ref.resolvedType, typeBindings); |
| } else { |
| scope.problemReporter().incorrectArityForParameterizedType(ref, ref.resolvedType, typeBindings); |
| } |
| return false; |
| } |
| } else if(parent instanceof ParameterizedQualifiedTypeReference) { |
| ParameterizedQualifiedTypeReference ref = (ParameterizedQualifiedTypeReference) parent; |
| TypeVariableBinding[] typeVariables = ((ReferenceBinding)ref.resolvedType).typeVariables(); |
| TypeReference[][] arguments = ref.typeArguments; |
| int iLength = arguments == null ? 0 : arguments.length; |
| 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 == null || typeVariables.length <= j)) { |
| TypeBinding[] typeBindings = new TypeBinding[j + 1]; |
| for(int k = 0; k < j; k++) { |
| typeBindings[k] = ref.typeArguments[i][k].resolvedType; |
| } |
| typeBindings[j] = scope.getJavaLangObject(); |
| if(typeVariables == null || typeVariables.length == 0) { |
| scope.problemReporter().nonGenericTypeCannotBeParameterized(ref, ref.resolvedType, typeBindings); |
| } else { |
| scope.problemReporter().incorrectArityForParameterizedType(ref, ref.resolvedType, typeBindings); |
| } |
| return false; |
| } |
| } |
| } |
| } |
| 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; |
| lastDotLookup: 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[][] 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); |
| } |
| |
| char[] returnTypeSignature = |
| returnTypeName == null || returnTypeName.length == 0 |
| ? Signature.createCharArrayTypeSignature(VOID, true) |
| : Signature.createCharArrayTypeSignature( |
| CharOperation.concat( |
| returnPackagename, |
| CharOperation.replaceOnCopy(returnTypeName, '.', '$'), '.'), true); |
| |
| return Signature.createMethodSignature( |
| parameterTypeSignature, |
| returnTypeSignature); |
| } |
| |
| protected CompletionProposal createProposal(int kind, int compteionOffset) { |
| CompletionProposal proposal = CompletionProposal.create(kind, compteionOffset); |
| proposal.nameLookup = this.nameEnvironment.nameLookup; |
| proposal.completionEngine = this; |
| return proposal; |
| } |
| |
| protected void printDebug(IProblem error) { |
| if(CompletionEngine.DEBUG) { |
| System.out.print("COMPLETION - completionFailure("); //$NON-NLS-1$ |
| System.out.print(error); |
| System.out.println(")"); //$NON-NLS-1$ |
| } |
| } |
| |
| protected void printDebug(CompletionProposal proposal){ |
| StringBuffer buffer = new StringBuffer(); |
| buffer.append("COMPLETION - "); //$NON-NLS-1$ |
| switch(proposal.getKind()) { |
| case CompletionProposal.ANONYMOUS_CLASS_DECLARATION : |
| buffer.append("ANONYMOUS_CLASS_DECLARATION"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.FIELD_REF : |
| buffer.append("FIELD_REF"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.KEYWORD : |
| buffer.append("KEYWORD"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.LABEL_REF : |
| buffer.append("LABEL_REF"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.LOCAL_VARIABLE_REF : |
| buffer.append("LOCAL_VARIABLE_REF"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.METHOD_DECLARATION : |
| buffer.append("METHOD_DECLARATION"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.METHOD_REF : |
| buffer.append("METHOD_REF"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.PACKAGE_REF : |
| buffer.append("PACKAGE_REF"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.TYPE_REF : |
| buffer.append("TYPE_REF"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.VARIABLE_DECLARATION : |
| buffer.append("VARIABLE_DECLARATION"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.POTENTIAL_METHOD_DECLARATION : |
| buffer.append("POTENTIAL_METHOD_DECLARATION"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.METHOD_NAME_REFERENCE : |
| buffer.append("METHOD_NAME_REFERENCE"); //$NON-NLS-1$ |
| break; |
| case CompletionProposal.ANNOTATION_ATTRIBUTE_REF : |
| buffer.append("ANNOTATION_ATTRIBUT_REF"); //$NON-NLS-1$ |
| break; |
| default : |
| buffer.append("PROPOSAL"); //$NON-NLS-1$ |
| break; |
| |
| } |
| |
| buffer.append("{\n");//$NON-NLS-1$ |
| buffer.append("\tCompletion[").append(proposal.getCompletion() == null ? "null".toCharArray() : proposal.getCompletion()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| buffer.append("\tDeclarationSignature[").append(proposal.getDeclarationSignature() == null ? "null".toCharArray() : proposal.getDeclarationSignature()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| buffer.append("\tDeclarationKey[").append(proposal.getDeclarationKey() == null ? "null".toCharArray() : proposal.getDeclarationKey()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| buffer.append("\tSignature[").append(proposal.getSignature() == null ? "null".toCharArray() : proposal.getSignature()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| buffer.append("\tKey[").append(proposal.getKey() == null ? "null".toCharArray() : proposal.getKey()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| // buffer.append("\tDeclarationPackage[").append(proposal.getDeclarationPackageName() == null ? "null".toCharArray() : proposal.getDeclarationPackageName()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| // buffer.append("\tDeclarationType[").append(proposal.getDeclarationTypeName() == null ? "null".toCharArray() : proposal.getDeclarationTypeName()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| // buffer.append("\tPackage[").append(proposal.getPackageName() == null ? "null".toCharArray() : proposal.getPackageName()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| // buffer.append("\tType[").append(proposal.getTypeName() == null ? "null".toCharArray() : proposal.getTypeName()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| buffer.append("\tName[").append(proposal.getName() == null ? "null".toCharArray() : proposal.getName()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| |
| buffer.append("\tFlags[");//$NON-NLS-1$ |
| int flags = proposal.getFlags(); |
| buffer.append(Flags.toString(flags)); |
| if((flags & Flags.AccInterface) != 0) buffer.append("interface ");//$NON-NLS-1$ |
| if((flags & Flags.AccEnum) != 0) buffer.append("enum ");//$NON-NLS-1$ |
| buffer.append("]\n"); //$NON-NLS-1$ |
| |
| buffer.append("\tCompletionLocation[").append(proposal.getCompletionLocation()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append("\tReplaceStart[").append(proposal.getReplaceStart()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append("-ReplaceEnd[").append(proposal.getReplaceEnd()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append("\tTokenStart[").append(proposal.getTokenStart()).append("]"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append("-TokenEnd[").append(proposal.getTokenEnd()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ |
| buffer.append("\tRelevance[").append(proposal.getRelevance()).append("]\n"); //$NON-NLS-1$ //$NON-NLS-2$ |
| |
| buffer.append("}\n");//$NON-NLS-1$ |
| System.out.println(buffer.toString()); |
| } |
| } |