1 /*******************************************************************************
2 * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v0.5
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v05.html
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.codeassist;
13 import java.util.Locale;
16 import net.sourceforge.phpdt.core.ICompletionRequestor;
17 import net.sourceforge.phpdt.core.compiler.IProblem;
18 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols;
19 import net.sourceforge.phpdt.core.compiler.InvalidInputException;
20 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionNodeFound;
21 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnArgumentName;
22 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnClassLiteralAccess;
23 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnClassReference;
24 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnExceptionReference;
25 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnExplicitConstructorCall;
26 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnFieldName;
27 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnFieldType;
28 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnImportReference;
29 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnInterfaceReference;
30 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnLocalName;
31 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnMemberAccess;
32 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnMessageSend;
33 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnMethodName;
34 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnMethodReturnType;
35 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnPackageReference;
36 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnQualifiedAllocationExpression;
37 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnQualifiedClassReference;
38 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnQualifiedExceptionReference;
39 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnQualifiedInterfaceReference;
40 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnQualifiedNameReference;
41 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnQualifiedTypeReference;
42 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnSingleNameReference;
43 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionOnSingleTypeReference;
44 import net.sourceforge.phpdt.internal.codeassist.complete.CompletionParser;
45 import net.sourceforge.phpdt.internal.codeassist.complete.InvalidCursorLocation;
46 import net.sourceforge.phpdt.internal.codeassist.impl.AssistParser;
47 import net.sourceforge.phpdt.internal.codeassist.impl.Engine;
48 import net.sourceforge.phpdt.internal.compiler.CompilationResult;
49 import net.sourceforge.phpdt.internal.compiler.DefaultErrorHandlingPolicies;
50 import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
51 import net.sourceforge.phpdt.internal.compiler.ast.AbstractVariableDeclaration;
52 import net.sourceforge.phpdt.internal.compiler.ast.Argument;
53 import net.sourceforge.phpdt.internal.compiler.ast.Assignment;
54 import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
55 import net.sourceforge.phpdt.internal.compiler.ast.CompilationUnitDeclaration;
56 import net.sourceforge.phpdt.internal.compiler.ast.Expression;
57 import net.sourceforge.phpdt.internal.compiler.ast.ImportReference;
58 import net.sourceforge.phpdt.internal.compiler.ast.LocalDeclaration;
59 import net.sourceforge.phpdt.internal.compiler.ast.ReturnStatement;
60 import net.sourceforge.phpdt.internal.compiler.ast.SingleTypeReference;
61 import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
62 import net.sourceforge.phpdt.internal.compiler.ast.TypeReference;
63 import net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit;
64 import net.sourceforge.phpdt.internal.compiler.env.IConstants;
65 import net.sourceforge.phpdt.internal.compiler.env.ISourceMethod;
66 import net.sourceforge.phpdt.internal.compiler.env.ISourceType;
67 import net.sourceforge.phpdt.internal.compiler.env.NameEnvironmentAnswer;
68 import net.sourceforge.phpdt.internal.compiler.impl.ReferenceContext;
69 import net.sourceforge.phpdt.internal.compiler.lookup.BaseTypes;
70 import net.sourceforge.phpdt.internal.compiler.lookup.Binding;
71 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
72 import net.sourceforge.phpdt.internal.compiler.lookup.ClassScope;
73 import net.sourceforge.phpdt.internal.compiler.lookup.CompilerModifiers;
74 import net.sourceforge.phpdt.internal.compiler.lookup.FieldBinding;
75 import net.sourceforge.phpdt.internal.compiler.lookup.InvocationSite;
76 import net.sourceforge.phpdt.internal.compiler.lookup.LocalVariableBinding;
77 import net.sourceforge.phpdt.internal.compiler.lookup.LookupEnvironment;
78 import net.sourceforge.phpdt.internal.compiler.lookup.MethodBinding;
79 import net.sourceforge.phpdt.internal.compiler.lookup.MethodScope;
80 import net.sourceforge.phpdt.internal.compiler.lookup.PackageBinding;
81 import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
82 import net.sourceforge.phpdt.internal.compiler.lookup.Scope;
83 import net.sourceforge.phpdt.internal.compiler.lookup.SourceTypeBinding;
84 import net.sourceforge.phpdt.internal.compiler.lookup.TagBits;
85 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
86 import net.sourceforge.phpdt.internal.compiler.lookup.TypeConstants;
87 import net.sourceforge.phpdt.internal.compiler.lookup.VariableBinding;
88 import net.sourceforge.phpdt.internal.compiler.parser.Scanner;
89 import net.sourceforge.phpdt.internal.compiler.problem.AbortCompilation;
90 import net.sourceforge.phpdt.internal.compiler.problem.DefaultProblemFactory;
91 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
92 import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
93 import net.sourceforge.phpdt.internal.compiler.util.HashtableOfObject;
94 import net.sourceforge.phpdt.internal.compiler.util.ObjectVector;
97 * This class is the entry point for source completions.
98 * It contains two public APIs used to call CodeAssist on a given source with
99 * a given environment, assisting position and storage (and possibly options).
101 public final class CompletionEngine
103 implements ISearchRequestor, TypeConstants , ITerminalSymbols , RelevanceConstants {
105 public static boolean DEBUG = false;
107 private final static char[] ERROR_PATTERN = "*error*".toCharArray(); //$NON-NLS-1$
108 private final static char[] EXCEPTION_PATTERN = "*exception*".toCharArray(); //$NON-NLS-1$
109 private final static char[] SEMICOLON = new char[] { ';' };
110 TypeBinding[] expectedTypes;
112 boolean assistNodeIsClass;
113 boolean assistNodeIsException;
114 boolean assistNodeIsInterface;
116 CompletionParser parser;
117 ICompletionRequestor requestor;
118 ProblemReporter problemReporter;
121 boolean resolvingImports = false;
122 boolean insideQualifiedReference = false;
123 int startPosition, actualCompletionPosition, endPosition, offset;
124 HashtableOfObject knownPkgs = new HashtableOfObject(10);
125 HashtableOfObject knownTypes = new HashtableOfObject(10);
129 static final char[][] mainDeclarations =
131 "package".toCharArray(),
132 "import".toCharArray(),
133 "abstract".toCharArray(),
134 "final".toCharArray(),
135 "public".toCharArray(),
136 "class".toCharArray(),
137 "interface".toCharArray()};
139 static final char[][] modifiers = // may want field, method, type & member type modifiers
141 "abstract".toCharArray(),
142 "final".toCharArray(),
143 "native".toCharArray(),
144 "public".toCharArray(),
145 "protected".toCharArray(),
146 "private".toCharArray(),
147 "static".toCharArray(),
148 "strictfp".toCharArray(),
149 "synchronized".toCharArray(),
150 "transient".toCharArray(),
151 "volatile".toCharArray()};
153 static final char[][] baseTypes = new char[][] {
154 "boolean".toCharArray(), //$NON-NLS-1$
155 "byte".toCharArray(), //$NON-NLS-1$
156 "char".toCharArray(), //$NON-NLS-1$
157 "double".toCharArray(), //$NON-NLS-1$
158 "float".toCharArray(), //$NON-NLS-1$
159 "int".toCharArray(), //$NON-NLS-1$
160 "long".toCharArray(), //$NON-NLS-1$
161 "short".toCharArray(), //$NON-NLS-1$
162 "void".toCharArray(), //$NON-NLS-1$
165 static final char[] classField = "class".toCharArray(); //$NON-NLS-1$
166 static final char[] lengthField = "length".toCharArray(); //$NON-NLS-1$
167 static final char[] THIS = "this".toCharArray(); //$NON-NLS-1$
168 static final char[] THROWS = "throws".toCharArray(); //$NON-NLS-1$
170 static InvocationSite FakeInvocationSite = new InvocationSite(){
171 public boolean isSuperAccess(){ return false; }
172 public boolean isTypeAccess(){ return false; }
173 public void setActualReceiverType(ReferenceBinding receiverType) {}
174 public void setDepth(int depth){}
175 public void setFieldIndex(int depth){}
179 * The CompletionEngine is responsible for computing source completions.
181 * It requires a searchable name environment, which supports some
182 * specific search APIs, and a requestor to feed back the results to a UI.
184 * @param nameEnvironment net.sourceforge.phpdt.internal.codeassist.ISearchableNameEnvironment
185 * used to resolve type/package references and search for types/packages
186 * based on partial names.
188 * @param requestor net.sourceforge.phpdt.internal.codeassist.ICompletionRequestor
189 * since the engine might produce answers of various forms, the engine
190 * is associated with a requestor able to accept all possible completions.
192 * @param settings java.util.Map
193 * set of options used to configure the code assist engine.
195 public CompletionEngine(
196 ISearchableNameEnvironment nameEnvironment,
197 ICompletionRequestor requestor,
201 this.requestor = requestor;
202 this.nameEnvironment = nameEnvironment;
204 problemReporter = new ProblemReporter(
205 DefaultErrorHandlingPolicies.proceedWithAllProblems(),
206 this.compilerOptions,
207 new DefaultProblemFactory(Locale.getDefault()) {
208 public void record(IProblem problem, CompilationResult unitResult, ReferenceContext referenceContext) {
209 if (problem.isError() && (problem.getID() & IProblem.Syntax) != 0) {
210 CompletionEngine.this.requestor.acceptError(problem);
215 new CompletionParser(problemReporter, this.compilerOptions.assertMode);
216 this.lookupEnvironment =
217 new LookupEnvironment(this, this.compilerOptions, problemReporter, nameEnvironment);
219 new Scanner(false, false, false, this.compilerOptions.assertMode);
223 * One result of the search consists of a new class.
225 * NOTE - All package and type names are presented in their readable form:
226 * Package names are in the form "a.b.c".
227 * Nested type names are in the qualified form "A.M".
228 * The default package is represented by an empty array.
230 public void acceptClass(char[] packageName, char[] className, int modifiers) {
232 char[] fullyQualifiedName = CharOperation.concat(packageName, className, '.');
233 char[] completionName = fullyQualifiedName;
235 if (this.knownTypes.containsKey(completionName)) return;
237 this.knownTypes.put(completionName, this);
239 int relevance = R_DEFAULT;
240 if (resolvingImports) {
241 completionName = CharOperation.concat(completionName, SEMICOLON);
242 relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName);
244 if (!insideQualifiedReference) {
245 if (mustQualifyType(packageName, className)) {
246 if (packageName == null || packageName.length == 0)
247 if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar)
248 return; // ignore types from the default package from outside it
250 completionName = className;
253 relevance += computeRelevanceForCaseMatching(token, className);
254 relevance += computeRelevanceForExpectingType(packageName, className);
255 relevance += computeRelevanceForClass();
256 relevance += computeRelevanceForException(className);
259 requestor.acceptClass(
264 startPosition - offset,
265 endPosition - offset,
270 * One result of the search consists of a new interface.
272 * NOTE - All package and type names are presented in their readable form:
273 * Package names are in the form "a.b.c".
274 * Nested type names are in the qualified form "A.I".
275 * The default package is represented by an empty array.
277 public void acceptInterface(
279 char[] interfaceName,
282 char[] fullyQualifiedName = CharOperation.concat(packageName, interfaceName, '.');
283 char[] completionName = fullyQualifiedName;
285 if (this.knownTypes.containsKey(completionName)) return;
287 this.knownTypes.put(completionName, this);
289 int relevance = R_DEFAULT;
290 if (resolvingImports) {
291 completionName = CharOperation.concat(completionName, new char[] { ';' });
292 relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName);
294 if (!insideQualifiedReference) {
295 if (mustQualifyType(packageName, interfaceName)) {
296 if (packageName == null || packageName.length == 0)
297 if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar)
298 return; // ignore types from the default package from outside it
300 completionName = interfaceName;
303 relevance += computeRelevanceForCaseMatching(token, interfaceName);
304 relevance += computeRelevanceForExpectingType(packageName, interfaceName);
305 relevance += computeRelevanceForInterface();
308 requestor.acceptInterface(
313 startPosition - offset,
314 endPosition - offset,
319 * One result of the search consists of a new package.
321 * NOTE - All package names are presented in their readable form:
322 * Package names are in the form "a.b.c".
323 * The default package is represented by an empty array.
325 public void acceptPackage(char[] packageName) {
327 if (this.knownPkgs.containsKey(packageName)) return;
329 this.knownPkgs.put(packageName, this);
331 int relevance = R_DEFAULT;
332 relevance += computeRelevanceForCaseMatching(token, packageName);
334 requestor.acceptPackage(
337 ? CharOperation.concat(packageName, new char[] { '.', '*', ';' })
339 startPosition - offset,
340 endPosition - offset,
345 * One result of the search consists of a new type.
347 * NOTE - All package and type names are presented in their readable form:
348 * Package names are in the form "a.b.c".
349 * Nested type names are in the qualified form "A.M".
350 * The default package is represented by an empty array.
352 public void acceptType(char[] packageName, char[] typeName) {
354 char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');
355 char[] completionName = fullyQualifiedName;
357 if (this.knownTypes.containsKey(completionName)) return;
359 this.knownTypes.put(completionName, this);
361 int relevance = R_DEFAULT;
362 if (resolvingImports) {
363 completionName = CharOperation.concat(completionName, new char[] { ';' });
364 relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName);
366 if (!insideQualifiedReference) {
367 if (mustQualifyType(packageName, typeName)) {
368 if (packageName == null || packageName.length == 0)
369 if (unitScope != null && unitScope.fPackage.compoundName != NoCharChar)
370 return; // ignore types from the default package from outside it
372 completionName = typeName;
375 relevance += computeRelevanceForCaseMatching(token, typeName);
376 relevance += computeRelevanceForExpectingType(packageName, typeName);
379 requestor.acceptType(
383 startPosition - offset,
384 endPosition - offset,
388 private void complete(AstNode astNode, Binding qualifiedBinding, Scope scope) {
390 setSourceRange(astNode.sourceStart, astNode.sourceEnd);
392 if(parser.assistNodeParent != null) {
393 computeExpectedTypes(parser.assistNodeParent, scope);
396 // defaults... some nodes will change these
397 if (astNode instanceof CompletionOnFieldType) {
399 CompletionOnFieldType field = (CompletionOnFieldType) astNode;
400 CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) field.type;
402 setSourceRange(type.sourceStart, type.sourceEnd);
403 // findKeywords(token, modifiers, scope); // could be the start of a field, method or member type
404 findTypesAndPackages(token, scope);
406 if(!field.isLocalVariable && field.modifiers == CompilerModifiers.AccDefault) {
407 findMethods(token,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false);
410 if(astNode instanceof CompletionOnMethodReturnType) {
412 CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode;
413 SingleTypeReference type = (CompletionOnSingleTypeReference) method.returnType;
415 setSourceRange(type.sourceStart, type.sourceEnd);
416 findTypesAndPackages(token, scope);
418 if(method.modifiers == CompilerModifiers.AccDefault) {
419 findMethods(token,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false);
423 if (astNode instanceof CompletionOnSingleNameReference) {
425 token = ((CompletionOnSingleNameReference) astNode).token;
426 findVariablesAndMethods(
429 (CompletionOnSingleNameReference) astNode,
431 // can be the start of a qualified type name
432 findTypesAndPackages(token, scope);
436 if (astNode instanceof CompletionOnSingleTypeReference) {
438 token = ((CompletionOnSingleTypeReference) astNode).token;
440 assistNodeIsClass = astNode instanceof CompletionOnClassReference;
441 assistNodeIsException = astNode instanceof CompletionOnExceptionReference;
442 assistNodeIsInterface = astNode instanceof CompletionOnInterfaceReference;
444 // can be the start of a qualified type name
445 if (qualifiedBinding == null) {
446 findTypesAndPackages(token, scope);
450 (ReferenceBinding) qualifiedBinding,
452 scope.enclosingSourceType());
456 if (astNode instanceof CompletionOnQualifiedNameReference) {
458 insideQualifiedReference = true;
459 CompletionOnQualifiedNameReference ref =
460 (CompletionOnQualifiedNameReference) astNode;
461 token = ref.completionIdentifier;
462 long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1];
464 if (qualifiedBinding instanceof VariableBinding) {
466 setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
467 TypeBinding receiverType = ((VariableBinding) qualifiedBinding).type;
468 if (receiverType != null) {
469 findFieldsAndMethods(token, receiverType, scope, ref, scope,false);
474 if (qualifiedBinding instanceof ReferenceBinding) {
476 ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
477 setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
479 findMemberTypes(token, receiverType, scope, scope.enclosingSourceType());
481 findClassField(token, (TypeBinding) qualifiedBinding, scope);
509 if (qualifiedBinding instanceof PackageBinding) {
511 setSourceRange(astNode.sourceStart, (int) completionPosition);
512 // replace to the end of the completion identifier
513 findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding);
520 if (astNode instanceof CompletionOnQualifiedTypeReference) {
522 insideQualifiedReference = true;
524 assistNodeIsClass = astNode instanceof CompletionOnQualifiedClassReference;
525 assistNodeIsException = astNode instanceof CompletionOnQualifiedExceptionReference;
526 assistNodeIsInterface = astNode instanceof CompletionOnQualifiedInterfaceReference;
528 CompletionOnQualifiedTypeReference ref =
529 (CompletionOnQualifiedTypeReference) astNode;
530 token = ref.completionIdentifier;
531 long completionPosition = ref.sourcePositions[ref.tokens.length];
533 // get the source positions of the completion identifier
534 if (qualifiedBinding instanceof ReferenceBinding) {
536 setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
539 (ReferenceBinding) qualifiedBinding,
541 scope.enclosingSourceType());
545 if (qualifiedBinding instanceof PackageBinding) {
547 setSourceRange(astNode.sourceStart, (int) completionPosition);
548 // replace to the end of the completion identifier
549 findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding);
555 if (astNode instanceof CompletionOnMemberAccess) {
557 CompletionOnMemberAccess access = (CompletionOnMemberAccess) astNode;
558 long completionPosition = access.nameSourcePosition;
559 setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
561 token = access.token;
563 findFieldsAndMethods(
565 (TypeBinding) qualifiedBinding,
573 if (astNode instanceof CompletionOnMessageSend) {
575 CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode;
576 TypeBinding[] argTypes =
577 computeTypes(messageSend.arguments, (BlockScope) scope);
578 token = messageSend.selector;
579 if (qualifiedBinding == null) {
581 findImplicitMessageSends(token, argTypes, scope, messageSend, scope);
587 (ReferenceBinding) qualifiedBinding,
600 if (astNode instanceof CompletionOnExplicitConstructorCall) {
602 CompletionOnExplicitConstructorCall constructorCall =
603 (CompletionOnExplicitConstructorCall) astNode;
604 TypeBinding[] argTypes =
605 computeTypes(constructorCall.arguments, (BlockScope) scope);
607 (ReferenceBinding) qualifiedBinding,
615 if (astNode instanceof CompletionOnQualifiedAllocationExpression) {
617 CompletionOnQualifiedAllocationExpression allocExpression =
618 (CompletionOnQualifiedAllocationExpression) astNode;
619 TypeBinding[] argTypes =
620 computeTypes(allocExpression.arguments, (BlockScope) scope);
622 ReferenceBinding ref = (ReferenceBinding) qualifiedBinding;
624 if(!ref.isAbstract()) {
643 if (astNode instanceof CompletionOnClassLiteralAccess) {
644 CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode;
645 setSourceRange(access.classStart, access.sourceEnd);
647 token = access.completionIdentifier;
649 findClassField(token, (TypeBinding) qualifiedBinding, scope);
651 if(astNode instanceof CompletionOnMethodName) {
652 CompletionOnMethodName method = (CompletionOnMethodName) astNode;
654 setSourceRange(method.sourceStart, method.selectorEnd);
656 FieldBinding[] fields = scope.enclosingSourceType().fields();
657 char[][] excludeNames = new char[fields.length][];
658 for(int i = 0 ; i < fields.length ; i++){
659 excludeNames[i] = fields[i].name;
662 token = method.selector;
664 findVariableNames(token, method.returnType, excludeNames);
666 if (astNode instanceof CompletionOnFieldName) {
667 CompletionOnFieldName field = (CompletionOnFieldName) astNode;
669 FieldBinding[] fields = scope.enclosingSourceType().fields();
670 char[][] excludeNames = new char[fields.length][];
671 for(int i = 0 ; i < fields.length ; i++){
672 excludeNames[i] = fields[i].name;
675 token = field.realName;
677 findVariableNames(field.realName, field.type, excludeNames);
679 if (astNode instanceof CompletionOnLocalName ||
680 astNode instanceof CompletionOnArgumentName){
681 LocalDeclaration variable = (LocalDeclaration) astNode;
683 LocalVariableBinding[] locals = ((BlockScope)scope).locals;
684 char[][] excludeNames = new char[locals.length][];
686 for(int i = 0 ; i < locals.length ; i++){
687 if(locals[i] != null) {
688 excludeNames[localCount++] = locals[i].name;
691 System.arraycopy(excludeNames, 0, excludeNames = new char[localCount][], 0, localCount);
693 if(variable instanceof CompletionOnLocalName){
694 token = ((CompletionOnLocalName) variable).realName;
696 token = ((CompletionOnArgumentName) variable).realName;
698 findVariableNames(token, variable.type, excludeNames);
715 // public void complete(IType type, char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){
716 // TypeConverter converter = new TypeConverter();
718 // IType topLevelType = type;
719 // while(topLevelType.getDeclaringType() != null) {
720 // topLevelType = topLevelType.getDeclaringType();
723 // CompilationResult compilationResult = new CompilationResult((topLevelType.getElementName() + ".java").toCharArray(), 1, 1, this.compilerOptions.maxProblemsPerUnit); //$NON-NLS-1$
725 // CompilationUnitDeclaration compilationUnit = new CompilationUnitDeclaration(problemReporter, compilationResult, 0);
728 // TypeDeclaration typeDeclaration = converter.buildTypeDeclaration(type, compilationUnit, compilationResult, problemReporter);
730 // if(typeDeclaration != null) {
731 // // build AST from snippet
732 // Initializer fakeInitializer = parseSnippeInitializer(snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);
735 // FieldDeclaration[] oldFields = typeDeclaration.fields;
736 // FieldDeclaration[] newFields = new FieldDeclaration[oldFields.length + 1];
737 // System.arraycopy(oldFields, 0, newFields, 0, oldFields.length);
738 // newFields[oldFields.length] = fakeInitializer;
739 // typeDeclaration.fields = newFields;
742 // System.out.println("SNIPPET COMPLETION AST :"); //$NON-NLS-1$
743 // System.out.println(compilationUnit.toString());
746 // if (compilationUnit.types != null) {
748 // lookupEnvironment.buildTypeBindings(compilationUnit);
750 // if ((unitScope = compilationUnit.scope) != null) {
751 // lookupEnvironment.completeTypeBindings(compilationUnit, true);
752 // compilationUnit.scope.faultInTypes();
753 // compilationUnit.resolve();
755 // } catch (CompletionNodeFound e) {
756 // // completionNodeFound = true;
757 // if (e.astNode != null) {
758 // // if null then we found a problem in the completion node
759 // complete(e.astNode, e.qualifiedBinding, e.scope);
764 // } catch(JavaModelException e) {
769 // private Initializer parseSnippeInitializer(char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){
770 // StringBuffer prefix = new StringBuffer();
771 // prefix.append("public class FakeType {\n "); //$NON-NLS-1$
773 // prefix.append("static "); //$NON-NLS-1$
775 // prefix.append("{\n"); //$NON-NLS-1$
776 // for (int i = 0; i < localVariableTypeNames.length; i++) {
777 // prefix.append(AstNode.modifiersString(localVariableModifiers[i]));
778 // prefix.append(' ');
779 // prefix.append(localVariableTypeNames[i]);
780 // prefix.append(' ');
781 // prefix.append(localVariableNames[i]);
782 // prefix.append(';');
785 // char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$
786 // offset = prefix.length();
788 // String encoding = JavaCore.getOption(JavaCore.CORE_ENCODING);
789 // BasicCompilationUnit fakeUnit = new BasicCompilationUnit(
792 // "FakeType.java", //$NON-NLS-1$
795 // actualCompletionPosition = prefix.length() + position - 1;
797 // CompilationResult fakeResult = new CompilationResult(fakeUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
798 // CompilationUnitDeclaration fakeAST = parser.dietParse(fakeUnit, fakeResult, actualCompletionPosition);
800 // parseMethod(fakeAST, actualCompletionPosition);
802 // return (Initializer)fakeAST.types[0].fields[0];
806 * Ask the engine to compute a completion at the specified position
807 * of the given compilation unit.
810 * completion results are answered through a requestor.
812 * @param sourceUnit net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit
813 * the source of the current compilation unit.
815 * @param completionPosition int
816 * a position in the source where the completion is taking place.
817 * This position is relative to the source provided.
819 public void complete(ICompilationUnit sourceUnit, int completionPosition, int offset) {
822 System.out.print("COMPLETION IN "); //$NON-NLS-1$
823 System.out.print(sourceUnit.getFileName());
824 System.out.print(" AT POSITION "); //$NON-NLS-1$
825 System.out.println(completionPosition);
826 System.out.println("COMPLETION - Source :"); //$NON-NLS-1$
827 System.out.println(sourceUnit.getContents());
830 actualCompletionPosition = completionPosition - 1;
831 this.offset = offset;
832 // for now until we can change the UI.
833 CompilationResult result = new CompilationResult(sourceUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
834 CompilationUnitDeclaration parsedUnit = parser.dietParse(sourceUnit, result, actualCompletionPosition);
836 // boolean completionNodeFound = false;
837 if (parsedUnit != null) {
839 System.out.println("COMPLETION - Diet AST :"); //$NON-NLS-1$
840 System.out.println(parsedUnit.toString());
843 // scan the package & import statements first
844 if (parsedUnit.currentPackage instanceof CompletionOnPackageReference) {
845 findPackages((CompletionOnPackageReference) parsedUnit.currentPackage);
849 ImportReference[] imports = parsedUnit.imports;
850 if (imports != null) {
851 for (int i = 0, length = imports.length; i < length; i++) {
852 ImportReference importReference = imports[i];
853 if (importReference instanceof CompletionOnImportReference) {
854 findImports((CompletionOnImportReference) importReference);
860 if (parsedUnit.types != null) {
862 lookupEnvironment.buildTypeBindings(parsedUnit);
864 if ((unitScope = parsedUnit.scope) != null) {
865 source = sourceUnit.getContents();
866 lookupEnvironment.completeTypeBindings(parsedUnit, true);
867 parsedUnit.scope.faultInTypes();
868 parseMethod(parsedUnit, actualCompletionPosition);
870 System.out.println("COMPLETION - AST :"); //$NON-NLS-1$
871 System.out.println(parsedUnit.toString());
873 parsedUnit.resolve();
875 } catch (CompletionNodeFound e) {
876 // completionNodeFound = true;
877 if (e.astNode != null) {
879 System.out.print("COMPLETION - Completion node : "); //$NON-NLS-1$
880 System.out.println(e.astNode.toString());
882 // if null then we found a problem in the completion node
883 complete(e.astNode, e.qualifiedBinding, e.scope);
889 /* Ignore package, import, class & interface keywords for now...
890 if (!completionNodeFound) {
891 if (parsedUnit == null || parsedUnit.types == null) {
892 // this is not good enough... can still be trying to define a second type
893 CompletionScanner scanner = (CompletionScanner) parser.scanner;
894 setSourceRange(scanner.completedIdentifierStart, scanner.completedIdentifierEnd);
895 findKeywords(scanner.completionIdentifier, mainDeclarations, null);
897 // currently have no way to know if extends/implements are possible keywords
900 } catch (IndexOutOfBoundsException e) { // work-around internal failure - 1GEMF6D
901 } catch (InvalidCursorLocation e) { // may eventually report a usefull error
902 } catch (AbortCompilation e) { // ignore this exception for now since it typically means we cannot find java.lang.Object
903 } catch (CompletionNodeFound e){ // internal failure - bugs 5618
909 private TypeBinding[] computeTypes(Expression[] arguments, BlockScope scope) {
911 if (arguments == null)
914 int argsLength = arguments.length;
915 TypeBinding[] argTypes = new TypeBinding[argsLength];
916 for (int a = argsLength; --a >= 0;)
917 argTypes[a] = arguments[a].resolveType(scope);
921 private void findAnonymousType(
922 ReferenceBinding currentType,
923 TypeBinding[] argTypes,
925 InvocationSite invocationSite) {
927 if (currentType.isInterface()) {
928 char[] completion = TypeConstants.NoChar;
929 // nothing to insert - do not want to replace the existing selector & arguments
931 || source.length <= endPosition
932 || source[endPosition] != ')')
933 completion = new char[] { ')' };
935 requestor.acceptAnonymousType(
936 currentType.qualifiedPackageName(),
937 currentType.qualifiedSourceName(),
938 TypeConstants.NoCharChar,
939 TypeConstants.NoCharChar,
940 TypeConstants.NoCharChar,
942 IConstants.AccPublic,
943 endPosition - offset,
944 endPosition - offset,
956 private void findClassField(char[] token, TypeBinding receiverType, Scope scope) {
961 if (token.length <= classField.length
962 && CharOperation.prefixEquals(token, classField, false /* ignore case */
964 int relevance = R_DEFAULT;
965 relevance += computeRelevanceForCaseMatching(token, classField);
966 relevance += computeRelevanceForExpectingType(scope.getJavaLangClass());
968 requestor.acceptField(
975 CompilerModifiers.AccStatic | CompilerModifiers.AccPublic,
976 startPosition - offset,
977 endPosition - offset,
982 private void findConstructors(
983 ReferenceBinding currentType,
984 TypeBinding[] argTypes,
986 InvocationSite invocationSite,
987 boolean forAnonymousType) {
989 // No visibility checks can be performed without the scope & invocationSite
990 MethodBinding[] methods = currentType.availableMethods();
991 if(methods != null) {
992 int minArgLength = argTypes == null ? 0 : argTypes.length;
993 next : for (int f = methods.length; --f >= 0;) {
994 MethodBinding constructor = methods[f];
995 if (constructor.isConstructor()) {
997 if (constructor.isSynthetic()) continue next;
999 if (options.checkVisibility
1000 && !constructor.canBeSeenBy(invocationSite, scope)) continue next;
1002 TypeBinding[] parameters = constructor.parameters;
1003 int paramLength = parameters.length;
1004 if (minArgLength > paramLength)
1006 for (int a = minArgLength; --a >= 0;)
1007 if (argTypes[a] != null) // can be null if it could not be resolved properly
1008 if (!Scope.areTypesCompatible(argTypes[a], constructor.parameters[a]))
1011 char[][] parameterPackageNames = new char[paramLength][];
1012 char[][] parameterTypeNames = new char[paramLength][];
1013 for (int i = 0; i < paramLength; i++) {
1014 TypeBinding type = parameters[i];
1015 parameterPackageNames[i] = type.qualifiedPackageName();
1016 parameterTypeNames[i] = type.qualifiedSourceName();
1018 char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames);
1020 char[] completion = TypeConstants.NoChar;
1021 // nothing to insert - do not want to replace the existing selector & arguments
1023 || source.length <= endPosition
1024 || source[endPosition] != ')')
1025 completion = new char[] { ')' };
1027 if(forAnonymousType){
1028 requestor.acceptAnonymousType(
1029 currentType.qualifiedPackageName(),
1030 currentType.qualifiedSourceName(),
1031 parameterPackageNames,
1035 constructor.modifiers,
1036 endPosition - offset,
1037 endPosition - offset,
1040 requestor.acceptMethod(
1041 currentType.qualifiedPackageName(),
1042 currentType.qualifiedSourceName(),
1043 currentType.sourceName(),
1044 parameterPackageNames,
1047 TypeConstants.NoChar,
1048 TypeConstants.NoChar,
1050 constructor.modifiers,
1051 endPosition - offset,
1052 endPosition - offset,
1060 // Helper method for findFields(char[], ReferenceBinding, Scope, ObjectVector, boolean)
1061 private void findFields(
1063 FieldBinding[] fields,
1065 ObjectVector fieldsFound,
1066 ObjectVector localsFound,
1067 boolean onlyStaticFields,
1068 ReferenceBinding receiverType,
1069 InvocationSite invocationSite,
1070 Scope invocationScope,
1071 boolean implicitCall) {
1073 // Inherited fields which are hidden by subclasses are filtered out
1074 // No visibility checks can be performed without the scope & invocationSite
1076 int fieldLength = fieldName.length;
1077 next : for (int f = fields.length; --f >= 0;) {
1078 FieldBinding field = fields[f];
1080 if (field.isSynthetic()) continue next;
1082 if (onlyStaticFields && !field.isStatic()) continue next;
1084 if (fieldLength > field.name.length) continue next;
1086 if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */)) continue next;
1088 if (options.checkVisibility
1089 && !field.canBeSeenBy(receiverType, invocationSite, scope)) continue next;
1091 boolean prefixRequired = false;
1093 for (int i = fieldsFound.size; --i >= 0;) {
1094 Object[] other = (Object[])fieldsFound.elementAt(i);
1095 FieldBinding otherField = (FieldBinding) other[0];
1096 ReferenceBinding otherReceiverType = (ReferenceBinding) other[1];
1097 if (field == otherField && receiverType == otherReceiverType)
1099 if (CharOperation.equals(field.name, otherField.name, true)) {
1100 if (field.declaringClass.isSuperclassOf(otherField.declaringClass))
1102 if (otherField.declaringClass.isInterface())
1103 if (field.declaringClass.implementsInterface(otherField.declaringClass, true))
1105 if (field.declaringClass.isInterface())
1106 if (otherField.declaringClass.implementsInterface(field.declaringClass, true))
1108 prefixRequired = true;
1112 for (int l = localsFound.size; --l >= 0;) {
1113 LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l);
1115 if (CharOperation.equals(field.name, local.name, true)) {
1116 SourceTypeBinding declarationType = scope.enclosingSourceType();
1117 if (declarationType.isAnonymousType() && declarationType != invocationScope.enclosingSourceType()) {
1120 prefixRequired = true;
1125 fieldsFound.add(new Object[]{field, receiverType});
1127 char[] completion = field.name;
1129 if(prefixRequired || options.forceImplicitQualification){
1130 char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), field.isStatic());
1131 completion = CharOperation.concat(prefix,completion,'.');
1134 int relevance = R_DEFAULT;
1135 relevance += computeRelevanceForCaseMatching(fieldName, field.name);
1136 relevance += computeRelevanceForExpectingType(field.type);
1140 field.declaringClass.qualifiedPackageName(),
1141 field.declaringClass.qualifiedSourceName(),
1143 field.type.qualifiedPackageName(),
1144 field.type.qualifiedSourceName(),
1146 // may include some qualification to resolve ambiguities
1147 field.modifiers, startPosition - offset, endPosition - offset,
1152 private void findFields(
1154 ReferenceBinding receiverType,
1156 ObjectVector fieldsFound,
1157 ObjectVector localsFound,
1158 boolean onlyStaticFields,
1159 InvocationSite invocationSite,
1160 Scope invocationScope,
1161 boolean implicitCall) {
1163 if (fieldName == null)
1166 ReferenceBinding currentType = receiverType;
1167 ReferenceBinding[][] interfacesToVisit = null;
1168 int lastPosition = -1;
1171 ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
1172 if (itsInterfaces != NoSuperInterfaces) {
1174 if (interfacesToVisit == null)
1175 interfacesToVisit = new ReferenceBinding[5][];
1177 if (++lastPosition == interfacesToVisit.length)
1181 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1184 interfacesToVisit[lastPosition] = itsInterfaces;
1187 FieldBinding[] fields = currentType.availableFields();
1188 if(fields != null) {
1201 currentType = currentType.superclass();
1202 } while (currentType != null);
1204 if (interfacesToVisit != null) {
1205 for (int i = 0; i <= lastPosition; i++) {
1206 ReferenceBinding[] interfaces = interfacesToVisit[i];
1207 for (int j = 0, length = interfaces.length; j < length; j++) {
1209 ReferenceBinding anInterface = interfaces[j];
1210 if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) {
1211 // if interface as not already been visited
1212 anInterface.tagBits |= TagBits.InterfaceVisited;
1214 FieldBinding[] fields = anInterface.availableFields();
1215 if(fields != null) {
1229 ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
1230 if (itsInterfaces != NoSuperInterfaces) {
1231 if (++lastPosition == interfacesToVisit.length)
1235 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1238 interfacesToVisit[lastPosition] = itsInterfaces;
1244 // bit reinitialization
1245 for (int i = 0; i <= lastPosition; i++) {
1246 ReferenceBinding[] interfaces = interfacesToVisit[i];
1247 for (int j = 0, length = interfaces.length; j < length; j++)
1248 interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
1253 private void findFieldsAndMethods(
1255 TypeBinding receiverType,
1257 InvocationSite invocationSite,
1258 Scope invocationScope,
1259 boolean implicitCall) {
1264 if (receiverType.isBaseType())
1265 return; // nothing else is possible with base types
1267 if (receiverType.isArrayType()) {
1268 if (token.length <= lengthField.length
1269 && CharOperation.prefixEquals(token, lengthField, false /* ignore case */
1272 int relevance = R_DEFAULT;
1273 relevance += computeRelevanceForCaseMatching(token,lengthField);
1274 relevance += computeRelevanceForExpectingType(BaseTypes.IntBinding);
1276 requestor.acceptField(
1283 CompilerModifiers.AccPublic,
1284 startPosition - offset,
1285 endPosition - offset,
1288 receiverType = scope.getJavaLangObject();
1293 (ReferenceBinding) receiverType,
1305 (ReferenceBinding) receiverType,
1316 private void findImports(CompletionOnImportReference importReference) {
1317 char[][] tokens = importReference.tokens;
1319 char[] importName = CharOperation.concatWith(tokens, '.');
1321 if (importName.length == 0)
1324 char[] lastToken = tokens[tokens.length - 1];
1325 if(lastToken != null && lastToken.length == 0)
1326 importName = CharOperation.concat(importName, new char[]{'.'});
1328 resolvingImports = true;
1330 importReference.sourceStart,
1331 importReference.declarationSourceEnd);
1334 // want to replace the existing .*;
1335 nameEnvironment.findPackages(importName, this);
1336 nameEnvironment.findTypes(importName, this);
1339 // what about onDemand types? Ignore them since it does not happen!
1340 // import p1.p2.A.*;
1341 private void findKeywords(char[] keyword, char[][] choices, Scope scope) {
1343 int length = keyword.length;
1345 for (int i = 0; i < choices.length; i++)
1346 if (length <= choices[i].length
1347 && CharOperation.prefixEquals(keyword, choices[i], false /* ignore case */
1349 int relevance = R_DEFAULT;
1350 relevance += computeRelevanceForCaseMatching(keyword, choices[i]);
1352 requestor.acceptKeyword(choices[i], startPosition - offset, endPosition - offset,relevance);
1356 // Helper method for findMemberTypes(char[], ReferenceBinding, Scope)
1357 private void findMemberTypes(
1359 ReferenceBinding[] memberTypes,
1360 ObjectVector typesFound,
1361 ReferenceBinding receiverType,
1362 SourceTypeBinding invocationType) {
1364 // Inherited member types which are hidden by subclasses are filtered out
1365 // No visibility checks can be performed without the scope & invocationSite
1366 int typeLength = typeName.length;
1367 next : for (int m = memberTypes.length; --m >= 0;) {
1368 ReferenceBinding memberType = memberTypes[m];
1369 // if (!wantClasses && memberType.isClass()) continue next;
1370 // if (!wantInterfaces && memberType.isInterface()) continue next;
1371 if (typeLength > memberType.sourceName.length)
1374 if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false
1379 if (options.checkVisibility
1380 && !memberType.canBeSeenBy(receiverType, invocationType))
1383 for (int i = typesFound.size; --i >= 0;) {
1384 ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i);
1386 if (memberType == otherType)
1389 if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) {
1391 if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType()))
1394 if (otherType.enclosingType().isInterface())
1395 if (memberType.enclosingType()
1396 .implementsInterface(otherType.enclosingType(), true))
1399 if (memberType.enclosingType().isInterface())
1400 if (otherType.enclosingType()
1401 .implementsInterface(memberType.enclosingType(), true))
1406 typesFound.add(memberType);
1408 int relevance = R_DEFAULT;
1409 relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName);
1410 relevance += computeRelevanceForExpectingType(memberType);
1412 if (memberType.isClass()) {
1413 relevance += computeRelevanceForClass();
1414 requestor.acceptClass(
1415 memberType.qualifiedPackageName(),
1416 memberType.qualifiedSourceName(),
1417 memberType.sourceName(),
1418 memberType.modifiers,
1419 startPosition - offset,
1420 endPosition - offset,
1424 relevance += computeRelevanceForInterface();
1425 requestor.acceptInterface(
1426 memberType.qualifiedPackageName(),
1427 memberType.qualifiedSourceName(),
1428 memberType.sourceName(),
1429 memberType.modifiers,
1430 startPosition - offset,
1431 endPosition - offset,
1437 private void findMemberTypes(
1439 ReferenceBinding receiverType,
1441 SourceTypeBinding typeInvocation) {
1443 ReferenceBinding currentType = receiverType;
1444 if (typeName == null)
1447 if (currentType.superInterfaces() == null)
1448 return; // we're trying to find a supertype
1450 ObjectVector typesFound = new ObjectVector();
1451 if (insideQualifiedReference
1452 || typeName.length == 0) { // do not search up the hierarchy
1456 currentType.memberTypes(),
1463 ReferenceBinding[][] interfacesToVisit = null;
1464 int lastPosition = -1;
1468 ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
1469 if (itsInterfaces != NoSuperInterfaces) {
1471 if (interfacesToVisit == null)
1472 interfacesToVisit = new ReferenceBinding[5][];
1474 if (++lastPosition == interfacesToVisit.length)
1478 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1481 interfacesToVisit[lastPosition] = itsInterfaces;
1486 currentType.memberTypes(),
1490 currentType = currentType.superclass();
1492 } while (currentType != null);
1494 if (interfacesToVisit != null) {
1495 for (int i = 0; i <= lastPosition; i++) {
1496 ReferenceBinding[] interfaces = interfacesToVisit[i];
1497 for (int j = 0, length = interfaces.length; j < length; j++) {
1499 ReferenceBinding anInterface = interfaces[j];
1500 if ((anInterface.tagBits & TagBits.InterfaceVisited) == 0) {
1501 // if interface as not already been visited
1502 anInterface.tagBits |= TagBits.InterfaceVisited;
1506 anInterface.memberTypes(),
1511 ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
1512 if (itsInterfaces != NoSuperInterfaces) {
1514 if (++lastPosition == interfacesToVisit.length)
1518 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1521 interfacesToVisit[lastPosition] = itsInterfaces;
1527 // bit reinitialization
1528 for (int i = 0; i <= lastPosition; i++) {
1529 ReferenceBinding[] interfaces = interfacesToVisit[i];
1530 for (int j = 0, length = interfaces.length; j < length; j++)
1531 interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
1536 private void findIntefacesMethods(
1538 TypeBinding[] argTypes,
1539 ReferenceBinding receiverType,
1540 ReferenceBinding[] itsInterfaces,
1542 ObjectVector methodsFound,
1543 boolean onlyStaticMethods,
1545 boolean isCompletingDeclaration,
1546 InvocationSite invocationSite,
1547 Scope invocationScope,
1548 boolean implicitCall) {
1550 if (selector == null)
1553 if (itsInterfaces != NoSuperInterfaces) {
1554 ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
1555 int lastPosition = 0;
1556 interfacesToVisit[lastPosition] = itsInterfaces;
1558 for (int i = 0; i <= lastPosition; i++) {
1559 ReferenceBinding[] interfaces = interfacesToVisit[i];
1561 for (int j = 0, length = interfaces.length; j < length; j++) {
1562 ReferenceBinding currentType = interfaces[j];
1564 if ((currentType.tagBits & TagBits.InterfaceVisited) == 0) {
1565 // if interface as not already been visited
1566 currentType.tagBits |= TagBits.InterfaceVisited;
1568 MethodBinding[] methods = currentType.availableMethods();
1569 if(methods != null) {
1570 if(isCompletingDeclaration){
1572 findLocalMethodDeclarations(
1598 itsInterfaces = currentType.superInterfaces();
1599 if (itsInterfaces != NoSuperInterfaces) {
1601 if (++lastPosition == interfacesToVisit.length)
1605 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1608 interfacesToVisit[lastPosition] = itsInterfaces;
1614 // bit reinitialization
1615 for (int i = 0; i <= lastPosition; i++) {
1616 ReferenceBinding[] interfaces = interfacesToVisit[i];
1618 for (int j = 0, length = interfaces.length; j < length; j++){
1619 interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
1625 private void findImplicitMessageSends(
1627 TypeBinding[] argTypes,
1629 InvocationSite invocationSite,
1630 Scope invocationScope) {
1635 boolean staticsOnly = false;
1636 // need to know if we're in a static context (or inside a constructor)
1637 ObjectVector methodsFound = new ObjectVector();
1639 done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
1641 switch (scope.kind) {
1643 case Scope.METHOD_SCOPE :
1644 // handle the error case inside an explicit constructor call (see MethodScope>>findField)
1645 MethodScope methodScope = (MethodScope) scope;
1646 staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;
1649 case Scope.CLASS_SCOPE :
1650 ClassScope classScope = (ClassScope) scope;
1651 SourceTypeBinding enclosingType = classScope.referenceContext.binding;
1664 staticsOnly |= enclosingType.isStatic();
1667 case Scope.COMPILATION_UNIT_SCOPE :
1670 scope = scope.parent;
1674 // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean)
1675 private void findLocalMethods(
1677 TypeBinding[] argTypes,
1678 MethodBinding[] methods,
1680 ObjectVector methodsFound,
1681 boolean onlyStaticMethods,
1683 ReferenceBinding receiverType,
1684 InvocationSite invocationSite,
1685 Scope invocationScope,
1686 boolean implicitCall) {
1688 // Inherited methods which are hidden by subclasses are filtered out
1689 // No visibility checks can be performed without the scope & invocationSite
1691 int methodLength = methodName.length;
1692 int minArgLength = argTypes == null ? 0 : argTypes.length;
1694 next : for (int f = methods.length; --f >= 0;) {
1695 MethodBinding method = methods[f];
1697 if (method.isSynthetic()) continue next;
1699 if (method.isDefaultAbstract()) continue next;
1701 if (method.isConstructor()) continue next;
1703 // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
1704 if (onlyStaticMethods && !method.isStatic()) continue next;
1706 if (options.checkVisibility
1707 && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next;
1710 if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
1716 if (methodLength > method.selector.length)
1719 if (!CharOperation.prefixEquals(methodName, method.selector, false
1724 if (minArgLength > method.parameters.length)
1727 for (int a = minArgLength; --a >= 0;){
1728 if (argTypes[a] != null){ // can be null if it could not be resolved properly
1729 if (!Scope.areTypesCompatible(argTypes[a], method.parameters[a])) {
1735 boolean prefixRequired = false;
1737 for (int i = methodsFound.size; --i >= 0;) {
1738 Object[] other = (Object[]) methodsFound.elementAt(i);
1739 MethodBinding otherMethod = (MethodBinding) other[0];
1740 ReferenceBinding otherReceiverType = (ReferenceBinding) other[1];
1741 if (method == otherMethod && receiverType == otherReceiverType)
1744 if (CharOperation.equals(method.selector, otherMethod.selector, true)
1745 && method.areParametersEqual(otherMethod)) {
1747 if (method.declaringClass.isSuperclassOf(otherMethod.declaringClass))
1750 if (otherMethod.declaringClass.isInterface())
1753 .implementsInterface(otherMethod.declaringClass, true))
1756 if (method.declaringClass.isInterface())
1759 .implementsInterface(method.declaringClass,true))
1761 prefixRequired = true;
1765 methodsFound.add(new Object[]{method, receiverType});
1766 int length = method.parameters.length;
1767 char[][] parameterPackageNames = new char[length][];
1768 char[][] parameterTypeNames = new char[length][];
1770 for (int i = 0; i < length; i++) {
1771 TypeBinding type = method.parameters[i];
1772 parameterPackageNames[i] = type.qualifiedPackageName();
1773 parameterTypeNames[i] = type.qualifiedSourceName();
1775 char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
1777 char[] completion = TypeConstants.NoChar;
1779 int previousStartPosition = startPosition;
1781 // nothing to insert - do not want to replace the existing selector & arguments
1784 && source.length > endPosition
1785 && source[endPosition] == '(')
1786 completion = method.selector;
1788 completion = CharOperation.concat(method.selector, new char[] { '(', ')' });
1790 if(prefixRequired && (source != null)) {
1791 completion = CharOperation.subarray(source, startPosition, endPosition);
1793 startPosition = endPosition;
1797 if(prefixRequired || options.forceImplicitQualification){
1798 char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), method.isStatic());
1799 completion = CharOperation.concat(prefix,completion,'.');
1802 int relevance = R_DEFAULT;
1803 relevance += computeRelevanceForCaseMatching(methodName, method.selector);
1804 relevance += computeRelevanceForExpectingType(method.returnType);
1806 requestor.acceptMethod(
1807 method.declaringClass.qualifiedPackageName(),
1808 method.declaringClass.qualifiedSourceName(),
1810 parameterPackageNames,
1813 method.returnType.qualifiedPackageName(),
1814 method.returnType.qualifiedSourceName(),
1817 startPosition - offset,
1818 endPosition - offset,
1820 startPosition = previousStartPosition;
1824 private int computeRelevanceForCaseMatching(char[] token, char[] proposalName){
1825 if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) {
1831 private int computeRelevanceForClass(){
1832 if(assistNodeIsClass) {
1837 private int computeRelevanceForInterface(){
1838 if(assistNodeIsInterface) {
1843 private int computeRelevanceForException(char[] proposalName){
1845 if(assistNodeIsException &&
1846 (CharOperation.match(EXCEPTION_PATTERN, proposalName, false) ||
1847 CharOperation.match(ERROR_PATTERN, proposalName, false))) {
1852 private int computeRelevanceForExpectingType(TypeBinding proposalType){
1853 if(expectedTypes != null && proposalType != null) {
1854 for (int i = 0; i < expectedTypes.length; i++) {
1855 if(Scope.areTypesCompatible(proposalType, expectedTypes[i])) {
1856 return R_EXPECTED_TYPE;
1862 private int computeRelevanceForExpectingType(char[] packageName, char[] typeName){
1863 if(expectedTypes != null) {
1864 for (int i = 0; i < expectedTypes.length; i++) {
1865 if(CharOperation.equals(expectedTypes[i].qualifiedPackageName(), packageName) &&
1866 CharOperation.equals(expectedTypes[i].qualifiedSourceName(), typeName)) {
1867 return R_EXPECTED_TYPE;
1874 // Helper method for findMethods(char[], MethodBinding[], Scope, ObjectVector, boolean, boolean, boolean, TypeBinding)
1875 private void findLocalMethodDeclarations(
1877 MethodBinding[] methods,
1879 ObjectVector methodsFound,
1880 // boolean noVoidReturnType, how do you know?
1881 boolean onlyStaticMethods,
1883 ReferenceBinding receiverType) {
1885 // Inherited methods which are hidden by subclasses are filtered out
1886 // No visibility checks can be performed without the scope & invocationSite
1887 int methodLength = methodName.length;
1888 next : for (int f = methods.length; --f >= 0;) {
1890 MethodBinding method = methods[f];
1891 if (method.isSynthetic()) continue next;
1893 if (method.isDefaultAbstract()) continue next;
1895 if (method.isConstructor()) continue next;
1897 if (method.isFinal()) continue next;
1899 // if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
1900 if (onlyStaticMethods && !method.isStatic()) continue next;
1902 if (options.checkVisibility
1903 && !method.canBeSeenBy(receiverType, FakeInvocationSite , scope)) continue next;
1906 if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
1912 if (methodLength > method.selector.length)
1915 if (!CharOperation.prefixEquals(methodName, method.selector, false
1921 for (int i = methodsFound.size; --i >= 0;) {
1922 MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i);
1923 if (method == otherMethod)
1926 if (CharOperation.equals(method.selector, otherMethod.selector, true)
1927 && method.areParametersEqual(otherMethod)) {
1932 methodsFound.add(method);
1934 int length = method.parameters.length;
1935 char[][] parameterPackageNames = new char[length][];
1936 char[][] parameterTypeNames = new char[length][];
1938 for (int i = 0; i < length; i++) {
1939 TypeBinding type = method.parameters[i];
1940 parameterPackageNames[i] = type.qualifiedPackageName();
1941 parameterTypeNames[i] = type.qualifiedSourceName();
1944 char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
1946 StringBuffer completion = new StringBuffer(10);
1947 // flush uninteresting modifiers
1948 int insertedModifiers = method.modifiers & ~(CompilerModifiers.AccNative | CompilerModifiers.AccAbstract);
1951 if(insertedModifiers != CompilerModifiers.AccDefault){
1952 completion.append(AstNode.modifiersString(insertedModifiers));
1954 char[] returnPackageName = method.returnType.qualifiedPackageName();
1955 char[] returnTypeName = method.returnType.qualifiedSourceName();
1956 if(mustQualifyType(returnPackageName, returnTypeName)) {
1957 completion.append(CharOperation.concat(returnPackageName, returnTypeName,'.'));
1959 completion.append(method.returnType.sourceName());
1961 completion.append(' ');
1962 completion.append(method.selector);
1963 completion.append('(');
1965 for(int i = 0; i < length ; i++){
1966 if(mustQualifyType(parameterPackageNames[i], parameterTypeNames[i])){
1967 completion.append(CharOperation.concat(parameterPackageNames[i], parameterTypeNames[i], '.'));
1969 completion.append(parameterTypeNames[i]);
1971 completion.append(' ');
1972 if(parameterNames != null){
1973 completion.append(parameterNames[i]);
1975 completion.append('%');
1977 if(i != (length - 1))
1978 completion.append(',');
1980 completion.append(')');
1982 ReferenceBinding[] exceptions = method.thrownExceptions;
1984 if (exceptions != null && exceptions.length > 0){
1985 completion.append(' ');
1986 completion.append(THROWS);
1987 completion.append(' ');
1988 for(int i = 0; i < exceptions.length ; i++){
1989 ReferenceBinding exception = exceptions[i];
1991 char[] exceptionPackageName = exception.qualifiedPackageName();
1992 char[] exceptionTypeName = exception.qualifiedSourceName();
1995 completion.append(',');
1996 completion.append(' ');
1999 if(mustQualifyType(exceptionPackageName, exceptionTypeName)){
2000 completion.append(CharOperation.concat(exceptionPackageName, exceptionTypeName, '.'));
2002 completion.append(exception.sourceName());
2008 int relevance = R_DEFAULT;
2009 relevance += computeRelevanceForCaseMatching(methodName, method.selector);
2011 requestor.acceptMethodDeclaration(
2012 method.declaringClass.qualifiedPackageName(),
2013 method.declaringClass.qualifiedSourceName(),
2015 parameterPackageNames,
2018 method.returnType.qualifiedPackageName(),
2019 method.returnType.qualifiedSourceName(),
2020 completion.toString().toCharArray(),
2022 startPosition - offset,
2023 endPosition - offset,
2027 private void findMethods(
2029 TypeBinding[] argTypes,
2030 ReferenceBinding receiverType,
2032 ObjectVector methodsFound,
2033 boolean onlyStaticMethods,
2035 boolean isCompletingDeclaration,
2036 InvocationSite invocationSite,
2037 Scope invocationScope,
2038 boolean implicitCall) {
2039 if (selector == null)
2042 if(isCompletingDeclaration) {
2043 MethodBinding[] methods = receiverType.availableMethods();
2044 if (methods != null){
2045 for (int i = 0; i < methods.length; i++) {
2046 if(!methods[i].isDefaultAbstract()) {
2047 methodsFound.add(methods[i]);
2053 ReferenceBinding currentType = receiverType;
2054 if (receiverType.isInterface()) {
2055 if(isCompletingDeclaration) {
2056 findIntefacesMethods(
2060 currentType.superInterfaces(),
2065 isCompletingDeclaration,
2070 findIntefacesMethods(
2074 new ReferenceBinding[]{currentType},
2079 isCompletingDeclaration,
2085 currentType = scope.getJavaLangObject();
2087 if(isCompletingDeclaration){
2088 findIntefacesMethods(
2092 currentType.superInterfaces(),
2097 isCompletingDeclaration,
2102 currentType = receiverType.superclass();
2105 boolean hasPotentialDefaultAbstractMethods = true;
2106 while (currentType != null) {
2108 MethodBinding[] methods = currentType.availableMethods();
2109 if(methods != null) {
2110 if(isCompletingDeclaration){
2111 findLocalMethodDeclarations(
2135 if(hasPotentialDefaultAbstractMethods && currentType.isAbstract()){
2136 findIntefacesMethods(
2140 currentType.superInterfaces(),
2145 isCompletingDeclaration,
2150 hasPotentialDefaultAbstractMethods = false;
2152 currentType = currentType.superclass();
2155 private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){
2156 ReferenceBinding bindingType = method.declaringClass;
2158 char[][] parameterNames = null;
2160 int length = parameterTypeNames.length;
2163 return TypeConstants.NoCharChar;
2165 // look into the corresponding unit if it is available
2166 if (bindingType instanceof SourceTypeBinding){
2167 SourceTypeBinding sourceType = (SourceTypeBinding) bindingType;
2169 if (sourceType.scope != null){
2170 TypeDeclaration parsedType;
2172 if ((parsedType = sourceType.scope.referenceContext) != null){
2173 AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method);
2175 if (methodDecl != null){
2176 Argument[] arguments = methodDecl.arguments;
2177 parameterNames = new char[length][];
2179 for(int i = 0 ; i < length ; i++){
2180 parameterNames[i] = arguments[i].name;
2186 // look into the model
2187 if(parameterNames == null){
2188 NameEnvironmentAnswer answer = nameEnvironment.findType(bindingType.compoundName);
2191 if(answer.isSourceType()) {
2192 ISourceType sourceType = answer.getSourceTypes()[0];
2193 ISourceMethod[] sourceMethods = sourceType.getMethods();
2194 int len = sourceMethods == null ? 0 : sourceMethods.length;
2195 for(int i = 0; i < len ; i++){
2196 ISourceMethod sourceMethod = sourceMethods[i];
2197 char[][] argTypeNames = sourceMethod.getArgumentTypeNames();
2199 if(argTypeNames != null &&
2200 CharOperation.equals(method.selector,sourceMethod.getSelector()) &&
2201 CharOperation.equals(argTypeNames,parameterTypeNames)){
2202 parameterNames = sourceMethod.getArgumentNames();
2209 return parameterNames;
2212 private void findNestedTypes(
2214 SourceTypeBinding currentType,
2216 if (typeName == null)
2219 int typeLength = typeName.length;
2221 while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found
2223 switch (scope.kind) {
2225 case Scope.METHOD_SCOPE :
2226 case Scope.BLOCK_SCOPE :
2227 BlockScope blockScope = (BlockScope) scope;
2229 next : for (int i = 0, length = blockScope.scopeIndex; i < length; i++) {
2231 if (blockScope.subscopes[i] instanceof ClassScope) {
2232 SourceTypeBinding localType =
2233 ((ClassScope) blockScope.subscopes[i]).referenceContext.binding;
2235 if (!localType.isAnonymousType()) {
2236 if (typeLength > localType.sourceName.length)
2238 if (!CharOperation.prefixEquals(typeName, localType.sourceName, false
2243 int relevance = R_DEFAULT;
2244 relevance += computeRelevanceForCaseMatching(typeName, localType.sourceName);
2245 relevance += computeRelevanceForExpectingType(localType);
2246 relevance += computeRelevanceForClass();
2248 requestor.acceptClass(
2249 localType.qualifiedPackageName(),
2250 localType.sourceName,
2251 localType.sourceName,
2252 localType.modifiers,
2253 startPosition - offset,
2254 endPosition - offset,
2261 case Scope.CLASS_SCOPE :
2262 findMemberTypes(typeName, scope.enclosingSourceType(), scope, currentType);
2263 if (typeLength == 0)
2264 return; // do not search outside the class scope if no prefix was provided
2267 case Scope.COMPILATION_UNIT_SCOPE :
2270 scope = scope.parent;
2274 private void findPackages(CompletionOnPackageReference packageStatement) {
2276 token = CharOperation.concatWith(packageStatement.tokens, '.');
2277 if (token.length == 0)
2280 setSourceRange(packageStatement.sourceStart, packageStatement.sourceEnd);
2281 nameEnvironment.findPackages(CharOperation.toLowerCase(token), this);
2284 private void findTypesAndPackages(char[] token, Scope scope) {
2289 if (scope.enclosingSourceType() != null)
2290 findNestedTypes(token, scope.enclosingSourceType(), scope);
2292 if (unitScope != null) {
2293 int typeLength = token.length;
2294 SourceTypeBinding[] types = unitScope.topLevelTypes;
2296 for (int i = 0, length = types.length; i < length; i++) {
2297 SourceTypeBinding sourceType = types[i];
2299 if (typeLength > sourceType.sourceName.length) continue;
2301 if (!CharOperation.prefixEquals(token, sourceType.sourceName, false)) continue;
2303 int relevance = R_DEFAULT;
2304 relevance += computeRelevanceForCaseMatching(token, sourceType.sourceName);
2305 relevance += computeRelevanceForExpectingType(sourceType);
2307 if (sourceType.isClass()){
2308 relevance += computeRelevanceForClass();
2309 requestor.acceptClass(
2310 sourceType.qualifiedPackageName(),
2311 sourceType.sourceName(),
2312 sourceType.sourceName(),
2313 sourceType.modifiers,
2314 startPosition - offset,
2315 endPosition - offset,
2318 relevance += computeRelevanceForInterface();
2319 requestor.acceptInterface(
2320 sourceType.qualifiedPackageName(),
2321 sourceType.sourceName(),
2322 sourceType.sourceName(),
2323 sourceType.modifiers,
2324 startPosition - offset,
2325 endPosition - offset,
2331 if (token.length == 0)
2334 findKeywords(token, baseTypes, scope);
2335 nameEnvironment.findTypes(token, this);
2336 nameEnvironment.findPackages(token, this);
2339 private void findTypesAndSubpackages(
2341 PackageBinding packageBinding) {
2343 char[] qualifiedName =
2344 CharOperation.concatWith(packageBinding.compoundName, token, '.');
2346 if (token == null || token.length == 0) {
2347 int length = qualifiedName.length;
2351 qualifiedName = new char[length + 1],
2354 qualifiedName[length] = '.';
2356 nameEnvironment.findTypes(qualifiedName, this);
2357 nameEnvironment.findPackages(qualifiedName, this);
2360 private void findVariablesAndMethods(
2363 InvocationSite invocationSite,
2364 Scope invocationScope) {
2369 // Should local variables hide fields from the receiver type or any of its enclosing types?
2370 // we know its an implicit field/method access... see BlockScope getBinding/getImplicitMethod
2372 boolean staticsOnly = false;
2373 // need to know if we're in a static context (or inside a constructor)
2374 int tokenLength = token.length;
2376 ObjectVector localsFound = new ObjectVector();
2377 ObjectVector fieldsFound = new ObjectVector();
2378 ObjectVector methodsFound = new ObjectVector();
2380 Scope currentScope = scope;
2382 done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
2384 switch (currentScope.kind) {
2386 case Scope.METHOD_SCOPE :
2387 // handle the error case inside an explicit constructor call (see MethodScope>>findField)
2388 MethodScope methodScope = (MethodScope) currentScope;
2389 staticsOnly |= methodScope.isStatic | methodScope.isConstructorCall;
2391 case Scope.BLOCK_SCOPE :
2392 BlockScope blockScope = (BlockScope) currentScope;
2394 next : for (int i = 0, length = blockScope.locals.length; i < length; i++) {
2395 LocalVariableBinding local = blockScope.locals[i];
2400 if (tokenLength > local.name.length)
2403 if (!CharOperation.prefixEquals(token, local.name, false /* ignore case */
2407 if (local.isSecret())
2410 for (int f = 0; f < localsFound.size; f++) {
2411 LocalVariableBinding otherLocal =
2412 (LocalVariableBinding) localsFound.elementAt(f);
2413 if (CharOperation.equals(otherLocal.name, local.name, true))
2416 localsFound.add(local);
2418 int relevance = R_DEFAULT;
2419 relevance += computeRelevanceForCaseMatching(token, local.name);
2420 relevance += computeRelevanceForExpectingType(local.type);
2422 requestor.acceptLocalVariable(
2426 : local.type.qualifiedPackageName(),
2428 ? local.declaration.type.toString().toCharArray()
2429 : local.type.qualifiedSourceName(),
2431 startPosition - offset,
2432 endPosition - offset,
2437 case Scope.COMPILATION_UNIT_SCOPE :
2440 currentScope = currentScope.parent;
2443 currentScope = scope;
2445 done2 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
2447 switch (currentScope.kind) {
2449 case Scope.CLASS_SCOPE :
2450 ClassScope classScope = (ClassScope) currentScope;
2451 SourceTypeBinding enclosingType = classScope.referenceContext.binding;
2452 /* if (tokenLength == 0) { // only search inside the type itself if no prefix was provided
2453 findFields(token, enclosingType.fields(), classScope, fieldsFound, staticsOnly);
2454 findMethods(token, enclosingType.methods(), classScope, methodsFound, staticsOnly, false);
2480 staticsOnly |= enclosingType.isStatic();
2484 case Scope.COMPILATION_UNIT_SCOPE :
2487 currentScope = currentScope.parent;
2491 // Helper method for private void findVariableNames(char[] name, TypeReference type )
2492 private void findVariableName(char[] token, char[] qualifiedPackageName, char[] qualifiedSourceName, char[] sourceName, char[][] excludeNames, int dim){
2493 if(sourceName == null || sourceName.length == 0)
2498 // compute variable name for base type
2500 nameScanner.setSource(sourceName);
2501 nameScanner.getNextToken(); // switch (nameScanner.getNextToken()) {
2502 // case TokenNameint :
2503 // case TokenNamebyte :
2504 // case TokenNameshort :
2505 // case TokenNamechar :
2506 // case TokenNamelong :
2507 // case TokenNamefloat :
2508 // case TokenNamedouble :
2509 // case TokenNameboolean :
2510 // if(token != null && token.length != 0)
2512 // name = computeBaseNames(sourceName[0], excludeNames);
2516 int relevance = R_DEFAULT;
2517 relevance += computeRelevanceForCaseMatching(token, name);
2520 requestor.acceptVariableName(
2521 qualifiedPackageName,
2522 qualifiedSourceName,
2525 startPosition - offset,
2526 endPosition - offset,
2530 } catch(InvalidInputException e){
2533 // compute variable name for non base type
2534 char[][] names = computeNames(sourceName, dim > 0);
2537 int l = qualifiedSourceName.length;
2538 displayName = new char[l+(2*dim)];
2539 System.arraycopy(qualifiedSourceName, 0, displayName, 0, l);
2540 for(int i = 0; i < dim; i++){
2541 displayName[l+(i*2)] = '[';
2542 displayName[l+(i*2)+1] = ']';
2545 displayName = qualifiedSourceName;
2547 next : for(int i = 0 ; i < names.length ; i++){
2550 if (!CharOperation.prefixEquals(token, name, false))
2553 // completion must be an identifier (not a keyword, ...).
2555 nameScanner.setSource(name);
2556 if(nameScanner.getNextToken() != TokenNameIdentifier)
2558 } catch(InvalidInputException e){
2563 char[] originalName = name;
2564 for(int j = 0 ; j < excludeNames.length ; j++){
2565 if(CharOperation.equals(name, excludeNames[j], false)) {
2566 name = CharOperation.concat(originalName, String.valueOf(count++).toCharArray());
2571 int relevance = R_DEFAULT;
2572 relevance += computeRelevanceForCaseMatching(token, name);
2575 requestor.acceptVariableName(
2576 qualifiedPackageName,
2580 startPosition - offset,
2581 endPosition - offset,
2586 private void findVariableNames(char[] name, TypeReference type , char[][] excludeNames){
2589 type.binding != null &&
2590 type.binding.problemId() == Binding.NoError){
2591 TypeBinding tb = type.binding;
2594 tb.leafComponentType().qualifiedPackageName(),
2595 tb.leafComponentType().qualifiedSourceName(),
2596 tb.leafComponentType().sourceName(),
2600 char[][] typeName = type.getTypeName();
2604 CharOperation.concatWith(typeName, '.'),
2605 typeName[typeName.length - 1],
2611 public AssistParser getParser() {
2616 protected void reset() {
2619 this.knownPkgs = new HashtableOfObject(10);
2620 this.knownTypes = new HashtableOfObject(10);
2623 private void setSourceRange(int start, int end) {
2625 this.startPosition = start;
2626 this.endPosition = end + 1;
2629 private char[] computeBaseNames(char firstName, char[][] excludeNames){
2630 char[] name = new char[]{firstName};
2632 for(int i = 0 ; i < excludeNames.length ; i++){
2633 if(CharOperation.equals(name, excludeNames[i], false)) {
2637 if(name[0] == firstName)
2645 private void computeExpectedTypes(AstNode parent, Scope scope){
2646 int expectedTypeCount = 0;
2647 expectedTypes = new TypeBinding[1];
2649 if(parent instanceof AbstractVariableDeclaration) {
2650 TypeBinding binding = ((AbstractVariableDeclaration)parent).type.binding;
2651 if(binding != null) {
2652 expectedTypes[expectedTypeCount++] = binding;
2654 } else if(parent instanceof Assignment) {
2655 TypeBinding binding = ((Assignment)parent).lhsType;
2656 if(binding != null) {
2657 expectedTypes[expectedTypeCount++] = binding;
2659 } else if(parent instanceof ReturnStatement) {
2660 MethodBinding methodBinding = ((AbstractMethodDeclaration) scope.methodScope().referenceContext).binding;
2661 TypeBinding binding = methodBinding == null ? null : methodBinding.returnType;
2662 if(binding != null) {
2663 expectedTypes[expectedTypeCount++] = binding;
2667 System.arraycopy(expectedTypes, 0, expectedTypes = new TypeBinding[expectedTypeCount], 0, expectedTypeCount);
2669 private char[][] computeNames(char[] sourceName, boolean forArray){
2670 char[][] names = new char[5][];
2672 boolean previousIsUpperCase = false;
2673 for(int i = sourceName.length - 1 ; i >= 0 ; i--){
2674 boolean isUpperCase = Character.isUpperCase(sourceName[i]);
2675 if(isUpperCase && !previousIsUpperCase){
2676 char[] name = CharOperation.subarray(sourceName,i,sourceName.length);
2677 if(name.length > 1){
2678 if(nameCount == names.length) {
2679 System.arraycopy(names, 0, names = new char[nameCount * 2][], 0, nameCount);
2681 name[0] = Character.toLowerCase(name[0]);
2684 int length = name.length;
2685 if (name[length-1] == 's'){
2686 System.arraycopy(name, 0, name = new char[length + 2], 0, length);
2688 name[length+1] = 's';
2690 System.arraycopy(name, 0, name = new char[length + 1], 0, length);
2694 names[nameCount++] = name;
2697 previousIsUpperCase = isUpperCase;
2700 char[] name = CharOperation.toLowerCase(sourceName);
2702 int length = name.length;
2703 if (name[length-1] == 's'){
2704 System.arraycopy(name, 0, name = new char[length + 2], 0, length);
2706 name[length+1] = 's';
2708 System.arraycopy(name, 0, name = new char[length + 1], 0, length);
2712 names[nameCount++] = name;
2715 System.arraycopy(names, 0, names = new char[nameCount][], 0, nameCount);
2719 private char[] computePrefix(SourceTypeBinding declarationType, SourceTypeBinding invocationType, boolean isStatic){
2721 StringBuffer completion = new StringBuffer(10);
2724 completion.append(declarationType.sourceName());
2726 } else if (declarationType == invocationType) {
2727 completion.append(THIS);
2731 if (!declarationType.isNestedType()) {
2733 completion.append(declarationType.sourceName());
2734 completion.append('.');
2735 completion.append(THIS);
2737 } else if (!declarationType.isAnonymousType()) {
2739 completion.append(declarationType.sourceName());
2740 completion.append('.');
2741 completion.append(THIS);
2746 return completion.toString().toCharArray();
2749 private boolean isEnclosed(ReferenceBinding possibleEnclosingType, ReferenceBinding type){
2750 if(type.isNestedType()){
2751 ReferenceBinding enclosing = type.enclosingType();
2752 while(enclosing != null ){
2753 if(possibleEnclosingType == enclosing)
2755 enclosing = enclosing.enclosingType();