made PHPParser tokens more compatible with JDT Scanner tokens
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / codeassist / CompletionEngine.java
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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.codeassist;
12
13 import java.util.Locale;
14 import java.util.Map;
15
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;
95
96 /**
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).
100  */
101 public final class CompletionEngine
102         extends Engine
103         implements ISearchRequestor, TypeConstants , ITerminalSymbols , RelevanceConstants {
104         
105         public static boolean DEBUG = false;
106
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;
111         
112         boolean assistNodeIsClass;
113         boolean assistNodeIsException;
114         boolean assistNodeIsInterface;
115         
116         CompletionParser parser;
117         ICompletionRequestor requestor;
118         ProblemReporter problemReporter;
119         char[] source;
120         char[] token;
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);
126         Scanner nameScanner;
127
128         /*
129                 static final char[][] mainDeclarations =
130                         new char[][] {
131                                 "package".toCharArray(),
132                                 "import".toCharArray(),
133                                 "abstract".toCharArray(),
134                                 "final".toCharArray(),
135                                 "public".toCharArray(),
136                                 "class".toCharArray(),
137                                 "interface".toCharArray()};
138         
139                 static final char[][] modifiers = // may want field, method, type & member type modifiers
140                         new char[][] {
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()};
152         */
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$
163         };
164                 
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$
169         
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){}
176         };
177
178         /**
179          * The CompletionEngine is responsible for computing source completions.
180          *
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.
183          *
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.
187          *
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.
191          *
192          *  @param settings java.util.Map
193          *              set of options used to configure the code assist engine.
194          */
195         public CompletionEngine(
196                 ISearchableNameEnvironment nameEnvironment,
197                 ICompletionRequestor requestor,
198                 Map settings) {
199
200                 super(settings);
201                 this.requestor = requestor;
202                 this.nameEnvironment = nameEnvironment;
203
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);
211                                                 }
212                                         }
213                                 });
214                 this.parser =
215                         new CompletionParser(problemReporter, this.compilerOptions.assertMode);
216                 this.lookupEnvironment =
217                         new LookupEnvironment(this, this.compilerOptions, problemReporter, nameEnvironment);
218                 this.nameScanner =
219                         new Scanner(false, false, false, this.compilerOptions.assertMode);
220         }
221
222         /**
223          * One result of the search consists of a new class.
224          *
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.
229          */
230         public void acceptClass(char[] packageName, char[] className, int modifiers) {
231
232                 char[] fullyQualifiedName = CharOperation.concat(packageName, className, '.');
233                 char[] completionName = fullyQualifiedName;
234                 
235                 if (this.knownTypes.containsKey(completionName)) return;
236
237                 this.knownTypes.put(completionName, this);
238                 
239                 int relevance = R_DEFAULT;
240                 if (resolvingImports) {
241                         completionName = CharOperation.concat(completionName, SEMICOLON);
242                         relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName);
243                 } else {
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
249                                 } else {
250                                         completionName = className;
251                                 }
252                         }
253                         relevance += computeRelevanceForCaseMatching(token, className);
254                         relevance += computeRelevanceForExpectingType(packageName, className);
255                         relevance += computeRelevanceForClass();
256                         relevance += computeRelevanceForException(className);
257                 }
258
259                 requestor.acceptClass(
260                         packageName,
261                         className,
262                         completionName,
263                         modifiers,
264                         startPosition - offset,
265                         endPosition - offset,
266                         relevance);
267         }
268         
269         /**
270          * One result of the search consists of a new interface.
271          *
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.
276          */
277         public void acceptInterface(
278                 char[] packageName,
279                 char[] interfaceName,
280                 int modifiers) {
281
282                 char[] fullyQualifiedName = CharOperation.concat(packageName, interfaceName, '.');
283                 char[] completionName = fullyQualifiedName;
284
285                 if (this.knownTypes.containsKey(completionName)) return;
286
287                 this.knownTypes.put(completionName, this);
288
289                 int relevance = R_DEFAULT;
290                 if (resolvingImports) {
291                         completionName = CharOperation.concat(completionName, new char[] { ';' });
292                         relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName);
293                 } else {
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
299                                 } else {
300                                         completionName = interfaceName;
301                                 }
302                         }
303                         relevance += computeRelevanceForCaseMatching(token, interfaceName);
304                         relevance += computeRelevanceForExpectingType(packageName, interfaceName);
305                         relevance += computeRelevanceForInterface();
306                 }
307                 
308                 requestor.acceptInterface(
309                         packageName,
310                         interfaceName,
311                         completionName,
312                         modifiers,
313                         startPosition - offset,
314                         endPosition - offset,
315                         relevance);
316         }
317
318         /**
319          * One result of the search consists of a new package.
320          *
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.
324          */
325         public void acceptPackage(char[] packageName) {
326
327                 if (this.knownPkgs.containsKey(packageName)) return;
328
329                 this.knownPkgs.put(packageName, this);
330                 
331                 int relevance = R_DEFAULT;
332                 relevance += computeRelevanceForCaseMatching(token, packageName);
333
334                 requestor.acceptPackage(
335                         packageName,
336                         resolvingImports
337                                 ? CharOperation.concat(packageName, new char[] { '.', '*', ';' })
338                                 : packageName,
339                         startPosition - offset,
340                         endPosition - offset,
341                         relevance);
342         }
343
344         /**
345          * One result of the search consists of a new type.
346          *
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.
351          */
352         public void acceptType(char[] packageName, char[] typeName) {
353
354                 char[] fullyQualifiedName = CharOperation.concat(packageName, typeName, '.');
355                 char[] completionName = fullyQualifiedName;
356                 
357                 if (this.knownTypes.containsKey(completionName)) return;
358
359                 this.knownTypes.put(completionName, this);
360
361                 int relevance = R_DEFAULT;
362                 if (resolvingImports) {
363                         completionName = CharOperation.concat(completionName, new char[] { ';' });
364                         relevance += computeRelevanceForCaseMatching(token, fullyQualifiedName);
365                 } else {
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
371                                 } else {
372                                         completionName = typeName;
373                                 }
374                         }
375                         relevance += computeRelevanceForCaseMatching(token, typeName);
376                         relevance += computeRelevanceForExpectingType(packageName, typeName);
377                 }
378                 
379                 requestor.acceptType(
380                         packageName,
381                         typeName,
382                         completionName,
383                         startPosition - offset,
384                         endPosition - offset,
385                         relevance);
386         }
387
388         private void complete(AstNode astNode, Binding qualifiedBinding, Scope scope) {
389
390                 setSourceRange(astNode.sourceStart, astNode.sourceEnd);
391                 
392                 if(parser.assistNodeParent != null) {
393                         computeExpectedTypes(parser.assistNodeParent, scope);
394                 }
395
396                 // defaults... some nodes will change these
397                 if (astNode instanceof CompletionOnFieldType) {
398
399                         CompletionOnFieldType field = (CompletionOnFieldType) astNode;
400                         CompletionOnSingleTypeReference type = (CompletionOnSingleTypeReference) field.type;
401                         token = type.token;
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);
405                         
406                         if(!field.isLocalVariable && field.modifiers == CompilerModifiers.AccDefault) {
407                                 findMethods(token,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false);
408                         }
409                 } else {
410                         if(astNode instanceof CompletionOnMethodReturnType) {
411                                 
412                                 CompletionOnMethodReturnType method = (CompletionOnMethodReturnType) astNode;
413                                 SingleTypeReference type = (CompletionOnSingleTypeReference) method.returnType;
414                                 token = type.token;
415                                 setSourceRange(type.sourceStart, type.sourceEnd);
416                                 findTypesAndPackages(token, scope);
417                                 
418                                 if(method.modifiers == CompilerModifiers.AccDefault) {
419                                         findMethods(token,null,scope.enclosingSourceType(),scope,new ObjectVector(),false,false,true,null,null,false);
420                                 }
421                         } else {
422                                 
423                                 if (astNode instanceof CompletionOnSingleNameReference) {
424         
425                                         token = ((CompletionOnSingleNameReference) astNode).token;
426                                         findVariablesAndMethods(
427                                                 token,
428                                                 scope,
429                                                 (CompletionOnSingleNameReference) astNode,
430                                                 scope);
431                                         // can be the start of a qualified type name
432                                         findTypesAndPackages(token, scope);
433         
434                                 } else {
435         
436                                         if (astNode instanceof CompletionOnSingleTypeReference) {
437         
438                                                 token = ((CompletionOnSingleTypeReference) astNode).token;
439                                                 
440                                                 assistNodeIsClass = astNode instanceof CompletionOnClassReference;
441                                                 assistNodeIsException = astNode instanceof CompletionOnExceptionReference;
442                                                 assistNodeIsInterface = astNode instanceof CompletionOnInterfaceReference;
443         
444                                                 // can be the start of a qualified type name
445                                                 if (qualifiedBinding == null) {
446                                                         findTypesAndPackages(token, scope);
447                                                         } else {
448                                                                 findMemberTypes(
449                                                                 token,
450                                                                 (ReferenceBinding) qualifiedBinding,
451                                                                 scope,
452                                                                 scope.enclosingSourceType());
453                                                 }
454                                         } else {
455                                                 
456                                                 if (astNode instanceof CompletionOnQualifiedNameReference) {
457         
458                                                         insideQualifiedReference = true;
459                                                         CompletionOnQualifiedNameReference ref =
460                                                                 (CompletionOnQualifiedNameReference) astNode;
461                                                         token = ref.completionIdentifier;
462                                                         long completionPosition = ref.sourcePositions[ref.sourcePositions.length - 1];
463         
464                                                         if (qualifiedBinding instanceof VariableBinding) {
465         
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);
470                                                                 }
471         
472                                                         } else {
473         
474                                                                 if (qualifiedBinding instanceof ReferenceBinding) {
475         
476                                                                         ReferenceBinding receiverType = (ReferenceBinding) qualifiedBinding;
477                                                                         setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
478         
479                                                                         findMemberTypes(token, receiverType, scope, scope.enclosingSourceType());
480         
481                                                                         findClassField(token, (TypeBinding) qualifiedBinding, scope);
482         
483                                                                         findFields(
484                                                                                 token,
485                                                                                 receiverType,
486                                                                                 scope,
487                                                                                 new ObjectVector(),
488                                                                                 new ObjectVector(),
489                                                                                 true,
490                                                                                 ref,
491                                                                                 scope,
492                                                                                 false);
493         
494                                                                         findMethods(
495                                                                                 token,
496                                                                                 null,
497                                                                                 receiverType,
498                                                                                 scope,
499                                                                                 new ObjectVector(),
500                                                                                 true,
501                                                                                 false,
502                                                                                 false,
503                                                                                 ref,
504                                                                                 scope,
505                                                                                 false);
506         
507                                                                 } else {
508         
509                                                                         if (qualifiedBinding instanceof PackageBinding) {
510         
511                                                                                 setSourceRange(astNode.sourceStart, (int) completionPosition);
512                                                                                 // replace to the end of the completion identifier
513                                                                                 findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding);
514                                                                         }
515                                                                 }
516                                                         }
517         
518                                                 } else {
519         
520                                                                 if (astNode instanceof CompletionOnQualifiedTypeReference) {
521         
522                                                                 insideQualifiedReference = true;
523                                                                 
524                                                                 assistNodeIsClass = astNode instanceof CompletionOnQualifiedClassReference;
525                                                                 assistNodeIsException = astNode instanceof CompletionOnQualifiedExceptionReference;
526                                                                 assistNodeIsInterface = astNode instanceof CompletionOnQualifiedInterfaceReference;
527                                                                 
528                                                                 CompletionOnQualifiedTypeReference ref =
529                                                                         (CompletionOnQualifiedTypeReference) astNode;
530                                                                 token = ref.completionIdentifier;
531                                                                 long completionPosition = ref.sourcePositions[ref.tokens.length];
532         
533                                                                 // get the source positions of the completion identifier
534                                                                 if (qualifiedBinding instanceof ReferenceBinding) {
535         
536                                                                         setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
537                                                                         findMemberTypes(
538                                                                                 token,
539                                                                                 (ReferenceBinding) qualifiedBinding,
540                                                                                 scope,
541                                                                                 scope.enclosingSourceType());
542         
543                                                                 } else {
544         
545                                                                         if (qualifiedBinding instanceof PackageBinding) {
546         
547                                                                                 setSourceRange(astNode.sourceStart, (int) completionPosition);
548                                                                                 // replace to the end of the completion identifier
549                                                                                 findTypesAndSubpackages(token, (PackageBinding) qualifiedBinding);
550                                                                         }
551                                                                 }
552         
553                                                         } else {
554         
555                                                                 if (astNode instanceof CompletionOnMemberAccess) {
556         
557                                                                         CompletionOnMemberAccess access = (CompletionOnMemberAccess) astNode;
558                                                                         long completionPosition = access.nameSourcePosition;
559                                                                         setSourceRange((int) (completionPosition >>> 32), (int) completionPosition);
560                                         
561                                                                         token = access.token;
562         
563                                                                         findFieldsAndMethods(
564                                                                                 token,
565                                                                                 (TypeBinding) qualifiedBinding,
566                                                                                 scope,
567                                                                                 access,
568                                                                                 scope,
569                                                                                 false);
570         
571                                                                 } else {
572         
573                                                                         if (astNode instanceof CompletionOnMessageSend) {
574         
575                                                                                 CompletionOnMessageSend messageSend = (CompletionOnMessageSend) astNode;
576                                                                                 TypeBinding[] argTypes =
577                                                                                         computeTypes(messageSend.arguments, (BlockScope) scope);
578                                                                                 token = messageSend.selector;
579                                                                                 if (qualifiedBinding == null) {
580                                                                                         
581                                                                                         findImplicitMessageSends(token, argTypes, scope, messageSend, scope);
582                                                                                 } else {
583         
584                                                                                         findMethods(
585                                                                                                 token,
586                                                                                                 argTypes,
587                                                                                                 (ReferenceBinding) qualifiedBinding,
588                                                                                                 scope,
589                                                                                                 new ObjectVector(),
590                                                                                                 false,
591                                                                                                 true,
592                                                                                                 false,
593                                                                                                 messageSend,
594                                                                                                 scope,
595                                                                                                 false);
596                                                                                 }
597         
598                                                                         } else {
599         
600                                                                                 if (astNode instanceof CompletionOnExplicitConstructorCall) {
601         
602                                                                                         CompletionOnExplicitConstructorCall constructorCall =
603                                                                                                 (CompletionOnExplicitConstructorCall) astNode;
604                                                                                         TypeBinding[] argTypes =
605                                                                                                 computeTypes(constructorCall.arguments, (BlockScope) scope);
606                                                                                         findConstructors(
607                                                                                                 (ReferenceBinding) qualifiedBinding,
608                                                                                                 argTypes,
609                                                                                                 scope,
610                                                                                                 constructorCall,
611                                                                                                 false);
612         
613                                                                                 } else {
614         
615                                                                                         if (astNode instanceof CompletionOnQualifiedAllocationExpression) {
616         
617                                                                                                 CompletionOnQualifiedAllocationExpression allocExpression =
618                                                                                                         (CompletionOnQualifiedAllocationExpression) astNode;
619                                                                                                 TypeBinding[] argTypes =
620                                                                                                         computeTypes(allocExpression.arguments, (BlockScope) scope);
621                                                                                                 
622                                                                                                 ReferenceBinding ref = (ReferenceBinding) qualifiedBinding;
623                                                                                                 if(ref.isClass()) {
624                                                                                                         if(!ref.isAbstract()) {
625                                                                                                                 findConstructors(
626                                                                                                                         ref,
627                                                                                                                         argTypes,
628                                                                                                                         scope,
629                                                                                                                         allocExpression,
630                                                                                                                         false);
631                                                                                                         }
632                                                                                                 }
633                                                                                                 if(!ref.isFinal()){
634                                                                                                         findAnonymousType(
635                                                                                                                 ref,
636                                                                                                                 argTypes,
637                                                                                                                 scope,
638                                                                                                                 allocExpression);
639                                                                                                 }
640         
641                                                                                         } else {
642         
643                                                                                                 if (astNode instanceof CompletionOnClassLiteralAccess) {
644                                                                                                         CompletionOnClassLiteralAccess access = (CompletionOnClassLiteralAccess) astNode;
645                                                                                                         setSourceRange(access.classStart, access.sourceEnd);
646                                                                         
647                                                                                                         token = access.completionIdentifier;
648                                                                         
649                                                                                                         findClassField(token, (TypeBinding) qualifiedBinding, scope);
650                                                                                                 } else {
651                                                                                                         if(astNode instanceof CompletionOnMethodName) {
652                                                                                                                 CompletionOnMethodName method = (CompletionOnMethodName) astNode;
653                                                                                                                         
654                                                                                                                 setSourceRange(method.sourceStart, method.selectorEnd);
655                                                                                                                         
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;
660                                                                                                                 }
661                                                                                                                 
662                                                                                                                 token = method.selector;
663                                                                                                                 
664                                                                                                                 findVariableNames(token, method.returnType, excludeNames);
665                                                                                                         } else {
666                                                                                                                 if (astNode instanceof CompletionOnFieldName) {
667                                                                                                                         CompletionOnFieldName field = (CompletionOnFieldName) astNode;
668                                                                                                                         
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;
673                                                                                                                         }
674                                                                                                                         
675                                                                                                                         token = field.realName;
676                                                                                                                         
677                                                                                                                         findVariableNames(field.realName, field.type, excludeNames);
678                                                                                                                 } else {
679                                                                                                                         if (astNode instanceof CompletionOnLocalName ||
680                                                                                                                                 astNode instanceof CompletionOnArgumentName){
681                                                                                                                                 LocalDeclaration variable = (LocalDeclaration) astNode;
682                                                                                                                                 
683                                                                                                                                 LocalVariableBinding[] locals = ((BlockScope)scope).locals;
684                                                                                                                                 char[][] excludeNames = new char[locals.length][];
685                                                                                                                                 int localCount = 0;
686                                                                                                                                 for(int i = 0 ; i < locals.length ; i++){
687                                                                                                                                         if(locals[i] != null) {
688                                                                                                                                                 excludeNames[localCount++] = locals[i].name;
689                                                                                                                                         }
690                                                                                                                                 }
691                                                                                                                                 System.arraycopy(excludeNames, 0, excludeNames = new char[localCount][], 0, localCount);
692                                                                                                                                 
693                                                                                                                                 if(variable instanceof CompletionOnLocalName){
694                                                                                                                                         token = ((CompletionOnLocalName) variable).realName;
695                                                                                                                                 } else {
696                                                                                                                                         token = ((CompletionOnArgumentName) variable).realName;
697                                                                                                                                 }
698                                                                                                                                 findVariableNames(token, variable.type, excludeNames);
699                                                                                                                         }
700                                                                                                                 }
701                                                                                                         }
702                                                                                                 }
703                                                                                         }
704                                                                                 }
705                                                                         }
706                                                                 }
707                                                         }
708                                                 }
709                                         }
710                                 }
711                         }
712                 }
713         }
714         
715 //      public void complete(IType type, char[] snippet, int position, char[][] localVariableTypeNames, char[][] localVariableNames, int[] localVariableModifiers, boolean isStatic){   
716 //              TypeConverter converter = new TypeConverter();
717 //              
718 //              IType topLevelType = type;
719 //              while(topLevelType.getDeclaringType() != null) {
720 //                      topLevelType = topLevelType.getDeclaringType();
721 //              }
722 //              
723 //              CompilationResult compilationResult = new CompilationResult((topLevelType.getElementName() + ".java").toCharArray(), 1, 1, this.compilerOptions.maxProblemsPerUnit); //$NON-NLS-1$
724 //      
725 //              CompilationUnitDeclaration compilationUnit = new CompilationUnitDeclaration(problemReporter, compilationResult, 0);
726 //      
727 //              try {
728 //                      TypeDeclaration typeDeclaration = converter.buildTypeDeclaration(type, compilationUnit, compilationResult, problemReporter);
729 //              
730 //                      if(typeDeclaration != null) {   
731 //                              // build AST from snippet
732 //                              Initializer fakeInitializer = parseSnippeInitializer(snippet, position, localVariableTypeNames, localVariableNames, localVariableModifiers, isStatic);
733 //                              
734 //                              // merge AST
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;
740 //              
741 //                              if(DEBUG) {
742 //                                      System.out.println("SNIPPET COMPLETION AST :"); //$NON-NLS-1$
743 //                                      System.out.println(compilationUnit.toString());
744 //                              }
745 //                              
746 //                              if (compilationUnit.types != null) {
747 //                                      try {
748 //                                              lookupEnvironment.buildTypeBindings(compilationUnit);
749 //                              
750 //                                              if ((unitScope = compilationUnit.scope) != null) {
751 //                                                      lookupEnvironment.completeTypeBindings(compilationUnit, true);
752 //                                                      compilationUnit.scope.faultInTypes();
753 //                                                      compilationUnit.resolve();
754 //                                              }
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);
760 //                                              }
761 //                                      }
762 //                              }
763 //                      }
764 //              } catch(JavaModelException e) {
765 //                      // Do nothing
766 //              }
767 //      }
768         
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$
772 //              if(isStatic) {
773 //                      prefix.append("static "); //$NON-NLS-1$
774 //              }
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(';');
783 //              }
784 //              
785 //              char[] fakeSource = CharOperation.concat(prefix.toString().toCharArray(), snippet, "}}".toCharArray());//$NON-NLS-1$ 
786 //              offset = prefix.length();
787 //              
788 //              String encoding = JavaCore.getOption(JavaCore.CORE_ENCODING);
789 //              BasicCompilationUnit fakeUnit = new BasicCompilationUnit(
790 //                      fakeSource, 
791 //                      null,
792 //                      "FakeType.java", //$NON-NLS-1$
793 //                      encoding); 
794 //                      
795 //              actualCompletionPosition = prefix.length() + position - 1;
796 //                      
797 //              CompilationResult fakeResult = new CompilationResult(fakeUnit, 1, 1, this.compilerOptions.maxProblemsPerUnit);
798 //              CompilationUnitDeclaration fakeAST = parser.dietParse(fakeUnit, fakeResult, actualCompletionPosition);
799 //              
800 //              parseMethod(fakeAST, actualCompletionPosition);
801 //              
802 //              return (Initializer)fakeAST.types[0].fields[0];
803 //      }
804
805         /**
806          * Ask the engine to compute a completion at the specified position
807          * of the given compilation unit.
808          *
809          *  @return void
810          *      completion results are answered through a requestor.
811          *
812          *  @param sourceUnit net.sourceforge.phpdt.internal.compiler.env.ICompilationUnit
813          *      the source of the current compilation unit.
814          *
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.
818          */
819         public void complete(ICompilationUnit sourceUnit, int completionPosition, int offset) {
820
821                 if(DEBUG) {
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());
828                 }
829                 try {
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);
835
836                         //              boolean completionNodeFound = false;
837                         if (parsedUnit != null) {
838                                 if(DEBUG) {
839                                         System.out.println("COMPLETION - Diet AST :"); //$NON-NLS-1$
840                                         System.out.println(parsedUnit.toString());
841                                 }
842
843                                 // scan the package & import statements first
844                                 if (parsedUnit.currentPackage instanceof CompletionOnPackageReference) {
845                                         findPackages((CompletionOnPackageReference) parsedUnit.currentPackage);
846                                         return;
847                                 }
848
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);
855                                                         return;
856                                                 }
857                                         }
858                                 }
859
860                                 if (parsedUnit.types != null) {
861                                         try {
862                                                 lookupEnvironment.buildTypeBindings(parsedUnit);
863
864                                                 if ((unitScope = parsedUnit.scope) != null) {
865                                                         source = sourceUnit.getContents();
866                                                         lookupEnvironment.completeTypeBindings(parsedUnit, true);
867                                                         parsedUnit.scope.faultInTypes();
868                                                         parseMethod(parsedUnit, actualCompletionPosition);
869                                                         if(DEBUG) {
870                                                                 System.out.println("COMPLETION - AST :"); //$NON-NLS-1$
871                                                                 System.out.println(parsedUnit.toString());
872                                                         }
873                                                         parsedUnit.resolve();
874                                                 }
875                                         } catch (CompletionNodeFound e) {
876                                                 //                                      completionNodeFound = true;
877                                                 if (e.astNode != null) {
878                                                         if(DEBUG) {
879                                                                 System.out.print("COMPLETION - Completion node : "); //$NON-NLS-1$
880                                                                 System.out.println(e.astNode.toString());
881                                                         }
882                                                         // if null then we found a problem in the completion node
883                                                         complete(e.astNode, e.qualifiedBinding, e.scope);
884                                                 }
885                                         }
886                                 }
887                         }
888
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);
896                                                 }
897                                                 // currently have no way to know if extends/implements are possible keywords
898                                         }
899                         */
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
904                 } finally {
905                         reset();
906                 }
907         }
908
909         private TypeBinding[] computeTypes(Expression[] arguments, BlockScope scope) {
910
911                 if (arguments == null)
912                         return null;
913
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);
918                 return argTypes;
919         }
920         
921         private void findAnonymousType(
922                 ReferenceBinding currentType,
923                 TypeBinding[] argTypes,
924                 Scope scope,
925                 InvocationSite invocationSite) {
926
927                 if (currentType.isInterface()) {
928                         char[] completion = TypeConstants.NoChar;
929                         // nothing to insert - do not want to replace the existing selector & arguments
930                         if (source == null
931                                 || source.length <= endPosition
932                                 || source[endPosition] != ')')
933                                 completion = new char[] { ')' };
934                         
935                         requestor.acceptAnonymousType(
936                                 currentType.qualifiedPackageName(),
937                                 currentType.qualifiedSourceName(),
938                                 TypeConstants.NoCharChar,
939                                 TypeConstants.NoCharChar,
940                                 TypeConstants.NoCharChar,
941                                 completion,
942                                 IConstants.AccPublic,
943                                 endPosition - offset,
944                                 endPosition - offset,
945                                 R_DEFAULT);
946                 } else {
947                         findConstructors(
948                                 currentType,
949                                 argTypes,
950                                 scope,
951                                 invocationSite,
952                                 true);
953                 }
954         }
955
956         private void findClassField(char[] token, TypeBinding receiverType, Scope scope) {
957
958                 if (token == null)
959                         return;
960
961                 if (token.length <= classField.length
962                         && CharOperation.prefixEquals(token, classField, false /* ignore case */
963                 )) {
964                         int relevance = R_DEFAULT;
965                         relevance += computeRelevanceForCaseMatching(token, classField);
966                         relevance += computeRelevanceForExpectingType(scope.getJavaLangClass());
967                                 
968                         requestor.acceptField(
969                                 NoChar,
970                                 NoChar,
971                                 classField,
972                                 NoChar,
973                                 NoChar,
974                                 classField,
975                                 CompilerModifiers.AccStatic | CompilerModifiers.AccPublic,
976                                 startPosition - offset,
977                                 endPosition - offset,
978                                 relevance);
979                 }
980         }
981
982         private void findConstructors(
983                 ReferenceBinding currentType,
984                 TypeBinding[] argTypes,
985                 Scope scope,
986                 InvocationSite invocationSite,
987                 boolean forAnonymousType) {
988
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()) {
996                                         
997                                         if (constructor.isSynthetic()) continue next;
998                                                 
999                                         if (options.checkVisibility
1000                                                 && !constructor.canBeSeenBy(invocationSite, scope)) continue next;
1001         
1002                                         TypeBinding[] parameters = constructor.parameters;
1003                                         int paramLength = parameters.length;
1004                                         if (minArgLength > paramLength)
1005                                                 continue next;
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]))
1009                                                                 continue next;
1010         
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();
1017                                         }
1018                                         char[][] parameterNames = findMethodParameterNames(constructor,parameterTypeNames);
1019                                         
1020                                         char[] completion = TypeConstants.NoChar;
1021                                         // nothing to insert - do not want to replace the existing selector & arguments
1022                                         if (source == null
1023                                                 || source.length <= endPosition
1024                                                 || source[endPosition] != ')')
1025                                                 completion = new char[] { ')' };
1026                                         
1027                                         if(forAnonymousType){
1028                                                 requestor.acceptAnonymousType(
1029                                                         currentType.qualifiedPackageName(),
1030                                                         currentType.qualifiedSourceName(),
1031                                                         parameterPackageNames,
1032                                                         parameterTypeNames,
1033                                                         parameterNames,
1034                                                         completion,
1035                                                         constructor.modifiers,
1036                                                         endPosition - offset,
1037                                                         endPosition - offset,
1038                                                         R_DEFAULT);
1039                                         } else {
1040                                                 requestor.acceptMethod(
1041                                                         currentType.qualifiedPackageName(),
1042                                                         currentType.qualifiedSourceName(),
1043                                                         currentType.sourceName(),
1044                                                         parameterPackageNames,
1045                                                         parameterTypeNames,
1046                                                         parameterNames,
1047                                                         TypeConstants.NoChar,
1048                                                         TypeConstants.NoChar,
1049                                                         completion,
1050                                                         constructor.modifiers,
1051                                                         endPosition - offset,
1052                                                         endPosition - offset,
1053                                                         R_DEFAULT);
1054                                         }
1055                                 }
1056                         }
1057                 }
1058         }
1059         
1060         // Helper method for findFields(char[], ReferenceBinding, Scope, ObjectVector, boolean)
1061         private void findFields(
1062                 char[] fieldName,
1063                 FieldBinding[] fields,
1064                 Scope scope,
1065                 ObjectVector fieldsFound,
1066                 ObjectVector localsFound,
1067                 boolean onlyStaticFields,
1068                 ReferenceBinding receiverType,
1069                 InvocationSite invocationSite,
1070                 Scope invocationScope,
1071                 boolean implicitCall) {
1072
1073                 // Inherited fields which are hidden by subclasses are filtered out
1074                 // No visibility checks can be performed without the scope & invocationSite
1075                 
1076                 int fieldLength = fieldName.length;
1077                 next : for (int f = fields.length; --f >= 0;) {                 
1078                         FieldBinding field = fields[f];
1079
1080                         if (field.isSynthetic())        continue next;
1081
1082                         if (onlyStaticFields && !field.isStatic()) continue next;
1083
1084                         if (fieldLength > field.name.length) continue next;
1085
1086                         if (!CharOperation.prefixEquals(fieldName, field.name, false /* ignore case */))        continue next;
1087
1088                         if (options.checkVisibility
1089                                 && !field.canBeSeenBy(receiverType, invocationSite, scope))     continue next;
1090
1091                         boolean prefixRequired = false;
1092
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)
1098                                         continue next;
1099                                 if (CharOperation.equals(field.name, otherField.name, true)) {
1100                                         if (field.declaringClass.isSuperclassOf(otherField.declaringClass))
1101                                                 continue next;
1102                                         if (otherField.declaringClass.isInterface())
1103                                                 if (field.declaringClass.implementsInterface(otherField.declaringClass, true))
1104                                                         continue next;
1105                                         if (field.declaringClass.isInterface())
1106                                                 if (otherField.declaringClass.implementsInterface(field.declaringClass, true))
1107                                                         continue next;
1108                                         prefixRequired = true;
1109                                 }
1110                         }
1111
1112                         for (int l = localsFound.size; --l >= 0;) {
1113                                 LocalVariableBinding local = (LocalVariableBinding) localsFound.elementAt(l);   
1114
1115                                 if (CharOperation.equals(field.name, local.name, true)) {
1116                                         SourceTypeBinding declarationType = scope.enclosingSourceType();
1117                                         if (declarationType.isAnonymousType() && declarationType != invocationScope.enclosingSourceType()) {
1118                                                 continue next;
1119                                         }
1120                                         prefixRequired = true;
1121                                         break;
1122                                 }
1123                         }
1124                         
1125                         fieldsFound.add(new Object[]{field, receiverType});
1126                         
1127                         char[] completion = field.name;
1128                         
1129                         if(prefixRequired || options.forceImplicitQualification){
1130                                 char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), field.isStatic());
1131                                 completion = CharOperation.concat(prefix,completion,'.');
1132                         }
1133
1134                         int relevance = R_DEFAULT;
1135                         relevance += computeRelevanceForCaseMatching(fieldName, field.name);
1136                         relevance += computeRelevanceForExpectingType(field.type);
1137
1138                         requestor
1139                                 .acceptField(
1140                                         field.declaringClass.qualifiedPackageName(),
1141                                         field.declaringClass.qualifiedSourceName(),
1142                                         field.name,
1143                                         field.type.qualifiedPackageName(),
1144                                         field.type.qualifiedSourceName(),
1145                                         completion,
1146                         // may include some qualification to resolve ambiguities
1147                         field.modifiers, startPosition - offset, endPosition - offset,
1148                         relevance);
1149                 }
1150         }
1151
1152         private void findFields(
1153                 char[] fieldName,
1154                 ReferenceBinding receiverType,
1155                 Scope scope,
1156                 ObjectVector fieldsFound,
1157                 ObjectVector localsFound,
1158                 boolean onlyStaticFields,
1159                 InvocationSite invocationSite,
1160                 Scope invocationScope,
1161                 boolean implicitCall) {
1162
1163                 if (fieldName == null)
1164                         return;
1165
1166                 ReferenceBinding currentType = receiverType;
1167                 ReferenceBinding[][] interfacesToVisit = null;
1168                 int lastPosition = -1;
1169                 do {
1170
1171                         ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
1172                         if (itsInterfaces != NoSuperInterfaces) {
1173
1174                                 if (interfacesToVisit == null)
1175                                         interfacesToVisit = new ReferenceBinding[5][];
1176
1177                                 if (++lastPosition == interfacesToVisit.length)
1178                                         System.arraycopy(
1179                                                 interfacesToVisit,
1180                                                 0,
1181                                                 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1182                                                 0,
1183                                                 lastPosition);
1184                                 interfacesToVisit[lastPosition] = itsInterfaces;
1185                         }
1186
1187                         FieldBinding[] fields = currentType.availableFields();
1188                         if(fields != null) {
1189                                 findFields(
1190                                         fieldName,
1191                                         fields,
1192                                         scope,
1193                                         fieldsFound,
1194                                         localsFound,
1195                                         onlyStaticFields,
1196                                         receiverType,
1197                                         invocationSite,
1198                                         invocationScope,
1199                                         implicitCall);
1200                         }
1201                         currentType = currentType.superclass();
1202                 } while (currentType != null);
1203
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++) {
1208
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;
1213
1214                                                 FieldBinding[] fields = anInterface.availableFields();
1215                                                 if(fields !=  null) {
1216                                                         findFields(
1217                                                                 fieldName,
1218                                                                 fields,
1219                                                                 scope,
1220                                                                 fieldsFound,
1221                                                                 localsFound,
1222                                                                 onlyStaticFields,
1223                                                                 receiverType,
1224                                                                 invocationSite,
1225                                                                 invocationScope,
1226                                                                 implicitCall);
1227                                                 }
1228
1229                                                 ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
1230                                                 if (itsInterfaces != NoSuperInterfaces) {
1231                                                         if (++lastPosition == interfacesToVisit.length)
1232                                                                 System.arraycopy(
1233                                                                         interfacesToVisit,
1234                                                                         0,
1235                                                                         interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1236                                                                         0,
1237                                                                         lastPosition);
1238                                                         interfacesToVisit[lastPosition] = itsInterfaces;
1239                                                 }
1240                                         }
1241                                 }
1242                         }
1243
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;
1249                         }
1250                 }
1251         }
1252
1253         private void findFieldsAndMethods(
1254                 char[] token,
1255                 TypeBinding receiverType,
1256                 Scope scope,
1257                 InvocationSite invocationSite,
1258                 Scope invocationScope,
1259                 boolean implicitCall) {
1260
1261                 if (token == null)
1262                         return;
1263
1264                 if (receiverType.isBaseType())
1265                         return; // nothing else is possible with base types
1266
1267                 if (receiverType.isArrayType()) {
1268                         if (token.length <= lengthField.length
1269                                 && CharOperation.prefixEquals(token, lengthField, false /* ignore case */
1270                         )) {
1271                                 
1272                                 int relevance = R_DEFAULT;
1273                                 relevance += computeRelevanceForCaseMatching(token,lengthField);
1274                                 relevance += computeRelevanceForExpectingType(BaseTypes.IntBinding);
1275                                 
1276                                 requestor.acceptField(
1277                                         NoChar,
1278                                         NoChar,
1279                                         lengthField,
1280                                         NoChar,
1281                                         NoChar,
1282                                         lengthField,
1283                                         CompilerModifiers.AccPublic,
1284                                         startPosition - offset,
1285                                         endPosition - offset,
1286                                         relevance);
1287                         }
1288                         receiverType = scope.getJavaLangObject();
1289                 }
1290
1291                 findFields(
1292                         token,
1293                         (ReferenceBinding) receiverType,
1294                         scope,
1295                         new ObjectVector(),
1296                         new ObjectVector(),
1297                         false,
1298                         invocationSite,
1299                         invocationScope,
1300                         implicitCall);
1301
1302                 findMethods(
1303                         token,
1304                         null,
1305                         (ReferenceBinding) receiverType,
1306                         scope,
1307                         new ObjectVector(),
1308                         false,
1309                         false,
1310                         false,
1311                         invocationSite,
1312                         invocationScope,
1313                         implicitCall);
1314         }
1315
1316         private void findImports(CompletionOnImportReference importReference) {
1317                 char[][] tokens = importReference.tokens;
1318                         
1319                 char[] importName = CharOperation.concatWith(tokens, '.');
1320                 
1321                 if (importName.length == 0)
1322                         return;
1323                         
1324                 char[] lastToken = tokens[tokens.length - 1];
1325                 if(lastToken != null && lastToken.length == 0)
1326                         importName = CharOperation.concat(importName, new char[]{'.'});
1327
1328                 resolvingImports = true;
1329                 setSourceRange(
1330                         importReference.sourceStart,
1331                         importReference.declarationSourceEnd);
1332                         
1333                 token =  importName;
1334                 // want to replace the existing .*;
1335                 nameEnvironment.findPackages(importName, this);
1336                 nameEnvironment.findTypes(importName, this);
1337         }
1338
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) {
1342
1343                 int length = keyword.length;
1344                 if (length > 0)
1345                         for (int i = 0; i < choices.length; i++)
1346                                 if (length <= choices[i].length
1347                                         && CharOperation.prefixEquals(keyword, choices[i], false /* ignore case */
1348                                 )){
1349                                         int relevance = R_DEFAULT;
1350                                         relevance += computeRelevanceForCaseMatching(keyword, choices[i]);
1351                                         
1352                                         requestor.acceptKeyword(choices[i], startPosition - offset, endPosition - offset,relevance);
1353                                 }
1354         }
1355
1356         // Helper method for findMemberTypes(char[], ReferenceBinding, Scope)
1357         private void findMemberTypes(
1358                 char[] typeName,
1359                 ReferenceBinding[] memberTypes,
1360                 ObjectVector typesFound,
1361                 ReferenceBinding receiverType,
1362                 SourceTypeBinding invocationType) {
1363
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)
1372                                 continue next;
1373
1374                         if (!CharOperation.prefixEquals(typeName, memberType.sourceName, false
1375                                 /* ignore case */
1376                                 ))
1377                                 continue next;
1378
1379                         if (options.checkVisibility
1380                                 && !memberType.canBeSeenBy(receiverType, invocationType))
1381                                 continue next;
1382
1383                         for (int i = typesFound.size; --i >= 0;) {
1384                                 ReferenceBinding otherType = (ReferenceBinding) typesFound.elementAt(i);
1385
1386                                 if (memberType == otherType)
1387                                         continue next;
1388
1389                                 if (CharOperation.equals(memberType.sourceName, otherType.sourceName, true)) {
1390
1391                                         if (memberType.enclosingType().isSuperclassOf(otherType.enclosingType()))
1392                                                 continue next;
1393
1394                                         if (otherType.enclosingType().isInterface())
1395                                                 if (memberType.enclosingType()
1396                                                         .implementsInterface(otherType.enclosingType(), true))
1397                                                         continue next;
1398
1399                                         if (memberType.enclosingType().isInterface())
1400                                                 if (otherType.enclosingType()
1401                                                         .implementsInterface(memberType.enclosingType(), true))
1402                                                         continue next;
1403                                 }
1404                         }
1405
1406                         typesFound.add(memberType);
1407
1408                         int relevance = R_DEFAULT;
1409                         relevance += computeRelevanceForCaseMatching(typeName, memberType.sourceName);
1410                         relevance += computeRelevanceForExpectingType(memberType);
1411
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,
1421                                         relevance);
1422
1423                         } else {
1424                                 relevance += computeRelevanceForInterface();
1425                                 requestor.acceptInterface(
1426                                         memberType.qualifiedPackageName(),
1427                                         memberType.qualifiedSourceName(),
1428                                         memberType.sourceName(),
1429                                         memberType.modifiers,
1430                                         startPosition - offset,
1431                                         endPosition - offset,
1432                                         relevance);
1433                         }
1434                 }
1435         }
1436
1437         private void findMemberTypes(
1438                 char[] typeName,
1439                 ReferenceBinding receiverType,
1440                 Scope scope,
1441                 SourceTypeBinding typeInvocation) {
1442
1443                 ReferenceBinding currentType = receiverType;
1444                 if (typeName == null)
1445                         return;
1446
1447                 if (currentType.superInterfaces() == null)
1448                         return; // we're trying to find a supertype
1449
1450                 ObjectVector typesFound = new ObjectVector();
1451                 if (insideQualifiedReference
1452                         || typeName.length == 0) { // do not search up the hierarchy
1453
1454                         findMemberTypes(
1455                                 typeName,
1456                                 currentType.memberTypes(),
1457                                 typesFound,
1458                                 receiverType,
1459                                 typeInvocation);
1460                         return;
1461                 }
1462
1463                 ReferenceBinding[][] interfacesToVisit = null;
1464                 int lastPosition = -1;
1465
1466                 do {
1467
1468                         ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
1469                         if (itsInterfaces != NoSuperInterfaces) {
1470
1471                                 if (interfacesToVisit == null)
1472                                         interfacesToVisit = new ReferenceBinding[5][];
1473
1474                                 if (++lastPosition == interfacesToVisit.length)
1475                                         System.arraycopy(
1476                                                 interfacesToVisit,
1477                                                 0,
1478                                                 interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1479                                                 0,
1480                                                 lastPosition);
1481                                 interfacesToVisit[lastPosition] = itsInterfaces;
1482                         }
1483
1484                         findMemberTypes(
1485                                 typeName,
1486                                 currentType.memberTypes(),
1487                                 typesFound,
1488                                 receiverType,
1489                                 typeInvocation);
1490                         currentType = currentType.superclass();
1491
1492                 } while (currentType != null);
1493
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++) {
1498
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;
1503
1504                                                 findMemberTypes(
1505                                                         typeName,
1506                                                         anInterface.memberTypes(),
1507                                                         typesFound,
1508                                                         receiverType,
1509                                                         typeInvocation);
1510
1511                                                 ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
1512                                                 if (itsInterfaces != NoSuperInterfaces) {
1513
1514                                                         if (++lastPosition == interfacesToVisit.length)
1515                                                                 System.arraycopy(
1516                                                                         interfacesToVisit,
1517                                                                         0,
1518                                                                         interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1519                                                                         0,
1520                                                                         lastPosition);
1521                                                         interfacesToVisit[lastPosition] = itsInterfaces;
1522                                                 }
1523                                         }
1524                                 }
1525                         }
1526
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;
1532                         }
1533                 }
1534         }
1535
1536         private void findIntefacesMethods(
1537                 char[] selector,
1538                 TypeBinding[] argTypes,
1539                 ReferenceBinding receiverType,
1540                 ReferenceBinding[] itsInterfaces,
1541                 Scope scope,
1542                 ObjectVector methodsFound,
1543                 boolean onlyStaticMethods,
1544                 boolean exactMatch,
1545                 boolean isCompletingDeclaration,
1546                 InvocationSite invocationSite,
1547                 Scope invocationScope,
1548                 boolean implicitCall) {
1549
1550                 if (selector == null)
1551                         return;
1552
1553                 if (itsInterfaces != NoSuperInterfaces) {
1554                         ReferenceBinding[][] interfacesToVisit = new ReferenceBinding[5][];
1555                         int lastPosition = 0;
1556                         interfacesToVisit[lastPosition] = itsInterfaces;
1557                         
1558                         for (int i = 0; i <= lastPosition; i++) {
1559                                 ReferenceBinding[] interfaces = interfacesToVisit[i];
1560
1561                                 for (int j = 0, length = interfaces.length; j < length; j++) {
1562                                         ReferenceBinding currentType = interfaces[j];
1563
1564                                         if ((currentType.tagBits & TagBits.InterfaceVisited) == 0) {
1565                                                 // if interface as not already been visited
1566                                                 currentType.tagBits |= TagBits.InterfaceVisited;
1567
1568                                                 MethodBinding[] methods = currentType.availableMethods();
1569                                                 if(methods != null) {
1570                                                         if(isCompletingDeclaration){
1571         
1572                                                                 findLocalMethodDeclarations(
1573                                                                         selector,
1574                                                                         methods,
1575                                                                         scope,
1576                                                                         methodsFound,
1577                                                                         onlyStaticMethods,
1578                                                                         exactMatch,
1579                                                                         receiverType);
1580         
1581                                                         } else {
1582         
1583                                                                 findLocalMethods(
1584                                                                         selector,
1585                                                                         argTypes,
1586                                                                         methods,
1587                                                                         scope,
1588                                                                         methodsFound,
1589                                                                         onlyStaticMethods,
1590                                                                         exactMatch,
1591                                                                         receiverType,
1592                                                                         invocationSite,
1593                                                                         invocationScope,
1594                                                                         implicitCall);
1595                                                         }
1596                                                 }
1597
1598                                                 itsInterfaces = currentType.superInterfaces();
1599                                                 if (itsInterfaces != NoSuperInterfaces) {
1600
1601                                                         if (++lastPosition == interfacesToVisit.length)
1602                                                                 System.arraycopy(
1603                                                                         interfacesToVisit,
1604                                                                         0,
1605                                                                         interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
1606                                                                         0,
1607                                                                         lastPosition);
1608                                                         interfacesToVisit[lastPosition] = itsInterfaces;
1609                                                 }
1610                                         }
1611                                 }
1612                         }
1613
1614                         // bit reinitialization
1615                         for (int i = 0; i <= lastPosition; i++) {
1616                                 ReferenceBinding[] interfaces = interfacesToVisit[i];
1617
1618                                 for (int j = 0, length = interfaces.length; j < length; j++){
1619                                         interfaces[j].tagBits &= ~TagBits.InterfaceVisited;
1620                                 }
1621                         }
1622                 }
1623         }
1624         
1625         private void findImplicitMessageSends(
1626                 char[] token,
1627                 TypeBinding[] argTypes,
1628                 Scope scope,
1629                 InvocationSite invocationSite,
1630                 Scope invocationScope) {
1631
1632                 if (token == null)
1633                         return;
1634
1635                 boolean staticsOnly = false;
1636                 // need to know if we're in a static context (or inside a constructor)
1637                 ObjectVector methodsFound = new ObjectVector();
1638
1639                 done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
1640
1641                         switch (scope.kind) {
1642
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;
1647                                         break;
1648
1649                                 case Scope.CLASS_SCOPE :
1650                                         ClassScope classScope = (ClassScope) scope;
1651                                         SourceTypeBinding enclosingType = classScope.referenceContext.binding;
1652                                         findMethods(
1653                                                 token,
1654                                                 argTypes,
1655                                                 enclosingType,
1656                                                 classScope,
1657                                                 methodsFound,
1658                                                 staticsOnly,
1659                                                 true,
1660                                                 false,
1661                                                 invocationSite,
1662                                                 invocationScope,
1663                                                 true);
1664                                         staticsOnly |= enclosingType.isStatic();
1665                                         break;
1666
1667                                 case Scope.COMPILATION_UNIT_SCOPE :
1668                                         break done;
1669                         }
1670                         scope = scope.parent;
1671                 }
1672         }
1673
1674         // Helper method for findMethods(char[], TypeBinding[], ReferenceBinding, Scope, ObjectVector, boolean, boolean, boolean)
1675         private void findLocalMethods(
1676                 char[] methodName,
1677                 TypeBinding[] argTypes,
1678                 MethodBinding[] methods,
1679                 Scope scope,
1680                 ObjectVector methodsFound,
1681                 boolean onlyStaticMethods,
1682                 boolean exactMatch,
1683                 ReferenceBinding receiverType,
1684                 InvocationSite invocationSite,
1685                 Scope invocationScope,
1686                 boolean implicitCall) {
1687
1688                 // Inherited methods which are hidden by subclasses are filtered out
1689                 // No visibility checks can be performed without the scope & invocationSite
1690
1691                 int methodLength = methodName.length;
1692                 int minArgLength = argTypes == null ? 0 : argTypes.length;
1693
1694                 next : for (int f = methods.length; --f >= 0;) {
1695                         MethodBinding method = methods[f];
1696
1697                         if (method.isSynthetic()) continue next;
1698
1699                         if (method.isDefaultAbstract()) continue next;
1700
1701                         if (method.isConstructor()) continue next;
1702
1703                         //              if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
1704                         if (onlyStaticMethods && !method.isStatic()) continue next;
1705
1706                         if (options.checkVisibility
1707                                 && !method.canBeSeenBy(receiverType, invocationSite, scope)) continue next;
1708
1709                         if (exactMatch) {
1710                                 if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
1711                                         ))
1712                                         continue next;
1713
1714                         } else {
1715
1716                                 if (methodLength > method.selector.length)
1717                                         continue next;
1718
1719                                 if (!CharOperation.prefixEquals(methodName, method.selector, false
1720                                         /* ignore case */
1721                                         ))
1722                                         continue next;
1723                         }
1724                         if (minArgLength > method.parameters.length)
1725                                 continue next;
1726
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])) {
1730                                                 continue next;
1731                                         }
1732                                 }
1733                         }
1734                         
1735                         boolean prefixRequired = false;
1736                         
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)
1742                                         continue next;
1743
1744                                 if (CharOperation.equals(method.selector, otherMethod.selector, true)
1745                                         && method.areParametersEqual(otherMethod)) {
1746
1747                                         if (method.declaringClass.isSuperclassOf(otherMethod.declaringClass))
1748                                                 continue next;
1749
1750                                         if (otherMethod.declaringClass.isInterface())
1751                                                 if (method
1752                                                         .declaringClass
1753                                                         .implementsInterface(otherMethod.declaringClass, true))
1754                                                         continue next;
1755
1756                                         if (method.declaringClass.isInterface())
1757                                                 if(otherMethod
1758                                                         .declaringClass
1759                                                         .implementsInterface(method.declaringClass,true))
1760                                                         continue next;
1761                                         prefixRequired = true;
1762                                 }
1763                         }
1764
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][];
1769
1770                         for (int i = 0; i < length; i++) {
1771                                 TypeBinding type = method.parameters[i];
1772                                 parameterPackageNames[i] = type.qualifiedPackageName();
1773                                 parameterTypeNames[i] = type.qualifiedSourceName();
1774                         }
1775                         char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
1776
1777                         char[] completion = TypeConstants.NoChar;
1778                         
1779                         int previousStartPosition = startPosition;
1780                         
1781                         // nothing to insert - do not want to replace the existing selector & arguments
1782                         if (!exactMatch) {
1783                                 if (source != null
1784                                         && source.length > endPosition
1785                                         && source[endPosition] == '(')
1786                                         completion = method.selector;
1787                                 else
1788                                         completion = CharOperation.concat(method.selector, new char[] { '(', ')' });
1789                         } else {
1790                                 if(prefixRequired && (source != null)) {
1791                                         completion = CharOperation.subarray(source, startPosition, endPosition);
1792                                 } else {
1793                                         startPosition = endPosition;
1794                                 }
1795                         }
1796                         
1797                         if(prefixRequired || options.forceImplicitQualification){
1798                                 char[] prefix = computePrefix(scope.enclosingSourceType(), invocationScope.enclosingSourceType(), method.isStatic());
1799                                 completion = CharOperation.concat(prefix,completion,'.');
1800                         }
1801
1802                         int relevance = R_DEFAULT;
1803                         relevance += computeRelevanceForCaseMatching(methodName, method.selector);
1804                         relevance += computeRelevanceForExpectingType(method.returnType);
1805
1806                         requestor.acceptMethod(
1807                                 method.declaringClass.qualifiedPackageName(),
1808                                 method.declaringClass.qualifiedSourceName(),
1809                                 method.selector,
1810                                 parameterPackageNames,
1811                                 parameterTypeNames,
1812                                 parameterNames,
1813                                 method.returnType.qualifiedPackageName(),
1814                                 method.returnType.qualifiedSourceName(),
1815                                 completion,
1816                                 method.modifiers,
1817                                 startPosition - offset,
1818                                 endPosition - offset,
1819                                 relevance);
1820                         startPosition = previousStartPosition;
1821                 }
1822         }
1823         
1824         private int computeRelevanceForCaseMatching(char[] token, char[] proposalName){
1825                 if (CharOperation.prefixEquals(token, proposalName, true /* do not ignore case */)) {
1826                         return  R_CASE;
1827                 } else {
1828                         return R_DEFAULT;
1829                 }
1830         }
1831         private int computeRelevanceForClass(){
1832                 if(assistNodeIsClass) {
1833                         return R_CLASS;
1834                 }
1835                 return 0;
1836         }
1837         private int computeRelevanceForInterface(){
1838                 if(assistNodeIsInterface) {
1839                         return R_INTERFACE;
1840                 }
1841                 return R_DEFAULT;
1842         }
1843         private int computeRelevanceForException(char[] proposalName){
1844                 
1845                 if(assistNodeIsException &&
1846                         (CharOperation.match(EXCEPTION_PATTERN, proposalName, false) ||
1847                         CharOperation.match(ERROR_PATTERN, proposalName, false))) { 
1848                         return R_EXCEPTION;
1849                 }
1850                 return R_DEFAULT;
1851         }
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;
1857                                 }
1858                         }
1859                 } 
1860                 return R_DEFAULT;
1861         }
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;
1868                                 }
1869                         }
1870                 } 
1871                 return R_DEFAULT;
1872         }
1873
1874         // Helper method for findMethods(char[], MethodBinding[], Scope, ObjectVector, boolean, boolean, boolean, TypeBinding)
1875         private void findLocalMethodDeclarations(
1876                 char[] methodName,
1877                 MethodBinding[] methods,
1878                 Scope scope,
1879                 ObjectVector methodsFound,
1880                 //      boolean noVoidReturnType, how do you know?
1881                 boolean onlyStaticMethods,
1882                 boolean exactMatch,
1883                 ReferenceBinding receiverType) {
1884
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;) {
1889
1890                         MethodBinding method = methods[f];
1891                         if (method.isSynthetic())       continue next;
1892                                 
1893                         if (method.isDefaultAbstract()) continue next;
1894                         
1895                         if (method.isConstructor()) continue next;
1896                                 
1897                         if (method.isFinal()) continue next;
1898
1899                         //              if (noVoidReturnType && method.returnType == BaseTypes.VoidBinding) continue next;
1900                         if (onlyStaticMethods && !method.isStatic()) continue next;
1901
1902                         if (options.checkVisibility
1903                                 && !method.canBeSeenBy(receiverType, FakeInvocationSite , scope)) continue next;
1904
1905                         if (exactMatch) {
1906                                 if (!CharOperation.equals(methodName, method.selector, false /* ignore case */
1907                                         ))
1908                                         continue next;
1909
1910                         } else {
1911
1912                                 if (methodLength > method.selector.length)
1913                                         continue next;
1914
1915                                 if (!CharOperation.prefixEquals(methodName, method.selector, false
1916                                         /* ignore case */
1917                                         ))
1918                                         continue next;
1919                         }
1920
1921                         for (int i = methodsFound.size; --i >= 0;) {
1922                                 MethodBinding otherMethod = (MethodBinding) methodsFound.elementAt(i);
1923                                 if (method == otherMethod)
1924                                         continue next;
1925
1926                                 if (CharOperation.equals(method.selector, otherMethod.selector, true)
1927                                         && method.areParametersEqual(otherMethod)) {
1928                                         continue next;
1929                                 }
1930                         }
1931
1932                         methodsFound.add(method);
1933                         
1934                         int length = method.parameters.length;
1935                         char[][] parameterPackageNames = new char[length][];
1936                         char[][] parameterTypeNames = new char[length][];
1937                         
1938                         for (int i = 0; i < length; i++) {
1939                                 TypeBinding type = method.parameters[i];
1940                                 parameterPackageNames[i] = type.qualifiedPackageName();
1941                                 parameterTypeNames[i] = type.qualifiedSourceName();
1942                         }
1943
1944                         char[][] parameterNames = findMethodParameterNames(method,parameterTypeNames);
1945                         
1946                         StringBuffer completion = new StringBuffer(10);
1947                         // flush uninteresting modifiers
1948                         int insertedModifiers = method.modifiers & ~(CompilerModifiers.AccNative | CompilerModifiers.AccAbstract);
1949
1950                         if (!exactMatch) {
1951                                 if(insertedModifiers != CompilerModifiers.AccDefault){
1952                                         completion.append(AstNode.modifiersString(insertedModifiers));
1953                                 }
1954                                 char[] returnPackageName = method.returnType.qualifiedPackageName();
1955                                 char[] returnTypeName = method.returnType.qualifiedSourceName();
1956                                 if(mustQualifyType(returnPackageName, returnTypeName)) {
1957                                         completion.append(CharOperation.concat(returnPackageName, returnTypeName,'.'));
1958                                 } else {
1959                                         completion.append(method.returnType.sourceName());
1960                                 }
1961                                 completion.append(' ');
1962                                 completion.append(method.selector);
1963                                 completion.append('(');
1964
1965                                 for(int i = 0; i < length ; i++){
1966                                         if(mustQualifyType(parameterPackageNames[i], parameterTypeNames[i])){
1967                                                 completion.append(CharOperation.concat(parameterPackageNames[i], parameterTypeNames[i], '.'));
1968                                         } else {
1969                                                 completion.append(parameterTypeNames[i]);
1970                                         }
1971                                         completion.append(' ');
1972                                         if(parameterNames != null){
1973                                                 completion.append(parameterNames[i]);
1974                                         } else {
1975                                                 completion.append('%');
1976                                         }
1977                                         if(i != (length - 1))
1978                                                 completion.append(','); 
1979                                 }
1980                                 completion.append(')');
1981                                 
1982                                 ReferenceBinding[] exceptions = method.thrownExceptions;
1983                                 
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];
1990
1991                                                 char[] exceptionPackageName = exception.qualifiedPackageName();
1992                                                 char[] exceptionTypeName = exception.qualifiedSourceName();
1993                                                 
1994                                                 if(i != 0){
1995                                                         completion.append(',');
1996                                                         completion.append(' ');
1997                                                 }
1998                                                 
1999                                                 if(mustQualifyType(exceptionPackageName, exceptionTypeName)){
2000                                                         completion.append(CharOperation.concat(exceptionPackageName, exceptionTypeName, '.'));
2001                                                 } else {
2002                                                         completion.append(exception.sourceName());
2003                                                 }
2004                                         }
2005                                 }
2006                         }
2007
2008                         int relevance = R_DEFAULT;
2009                         relevance += computeRelevanceForCaseMatching(methodName, method.selector);
2010
2011                         requestor.acceptMethodDeclaration(
2012                                 method.declaringClass.qualifiedPackageName(),
2013                                 method.declaringClass.qualifiedSourceName(),
2014                                 method.selector,
2015                                 parameterPackageNames,
2016                                 parameterTypeNames,
2017                                 parameterNames,
2018                                 method.returnType.qualifiedPackageName(),
2019                                 method.returnType.qualifiedSourceName(),
2020                                 completion.toString().toCharArray(),
2021                                 method.modifiers,
2022                                 startPosition - offset,
2023                                 endPosition - offset,
2024                                 relevance);
2025                 }
2026         }
2027         private void findMethods(
2028                 char[] selector,
2029                 TypeBinding[] argTypes,
2030                 ReferenceBinding receiverType,
2031                 Scope scope,
2032                 ObjectVector methodsFound,
2033                 boolean onlyStaticMethods,
2034                 boolean exactMatch,
2035                 boolean isCompletingDeclaration,
2036                 InvocationSite invocationSite,
2037                 Scope invocationScope,
2038                 boolean implicitCall) {
2039                 if (selector == null)
2040                         return;
2041                 
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]);
2048                                         }
2049                                 }
2050                         }
2051                 }
2052                 
2053                 ReferenceBinding currentType = receiverType;
2054                 if (receiverType.isInterface()) {
2055                         if(isCompletingDeclaration) {
2056                                 findIntefacesMethods(
2057                                         selector,
2058                                         argTypes,
2059                                         receiverType,
2060                                         currentType.superInterfaces(),
2061                                         scope,
2062                                         methodsFound,
2063                                         onlyStaticMethods,
2064                                         exactMatch,
2065                                         isCompletingDeclaration,
2066                                         invocationSite,
2067                                         invocationScope,
2068                                         implicitCall);
2069                         } else {
2070                                 findIntefacesMethods(
2071                                         selector,
2072                                         argTypes,
2073                                         receiverType,
2074                                         new ReferenceBinding[]{currentType},
2075                                         scope,
2076                                         methodsFound,
2077                                         onlyStaticMethods,
2078                                         exactMatch,
2079                                         isCompletingDeclaration,
2080                                         invocationSite,
2081                                         invocationScope,
2082                                         implicitCall);
2083                         }
2084                         
2085                         currentType = scope.getJavaLangObject();
2086                 } else {
2087                         if(isCompletingDeclaration){
2088                                 findIntefacesMethods(
2089                                         selector,
2090                                         argTypes,
2091                                         receiverType,
2092                                         currentType.superInterfaces(),
2093                                         scope,
2094                                         methodsFound,
2095                                         onlyStaticMethods,
2096                                         exactMatch,
2097                                         isCompletingDeclaration,
2098                                         invocationSite,
2099                                         invocationScope,
2100                                         implicitCall);
2101                                 
2102                                 currentType = receiverType.superclass();
2103                         }
2104                 }
2105                 boolean hasPotentialDefaultAbstractMethods = true;
2106                 while (currentType != null) {
2107                         
2108                         MethodBinding[] methods = currentType.availableMethods();
2109                         if(methods != null) {
2110                                 if(isCompletingDeclaration){
2111                                         findLocalMethodDeclarations(
2112                                                 selector,
2113                                                 methods,
2114                                                 scope,
2115                                                 methodsFound,
2116                                                 onlyStaticMethods,
2117                                                 exactMatch,
2118                                                 receiverType);
2119                                 } else{
2120                                         findLocalMethods(
2121                                                 selector,
2122                                                 argTypes,
2123                                                 methods,
2124                                                 scope,
2125                                                 methodsFound,
2126                                                 onlyStaticMethods,
2127                                                 exactMatch,
2128                                                 receiverType,
2129                                                 invocationSite,
2130                                                 invocationScope,
2131                                                 implicitCall);
2132                                 }
2133                         }
2134                         
2135                         if(hasPotentialDefaultAbstractMethods && currentType.isAbstract()){
2136                                 findIntefacesMethods(
2137                                         selector,
2138                                         argTypes,
2139                                         receiverType,
2140                                         currentType.superInterfaces(),
2141                                         scope,
2142                                         methodsFound,
2143                                         onlyStaticMethods,
2144                                         exactMatch,
2145                                         isCompletingDeclaration,
2146                                         invocationSite,
2147                                         invocationScope,
2148                                         implicitCall);
2149                         } else {
2150                                 hasPotentialDefaultAbstractMethods = false;
2151                         }
2152                         currentType = currentType.superclass();
2153                 }
2154         }
2155         private char[][] findMethodParameterNames(MethodBinding method, char[][] parameterTypeNames){
2156                 ReferenceBinding bindingType = method.declaringClass;
2157
2158                 char[][] parameterNames = null;
2159                 
2160                 int length = parameterTypeNames.length;
2161
2162                 if (length == 0){
2163                         return TypeConstants.NoCharChar;
2164                 }
2165                 // look into the corresponding unit if it is available
2166                 if (bindingType instanceof SourceTypeBinding){
2167                         SourceTypeBinding sourceType = (SourceTypeBinding) bindingType;
2168
2169                         if (sourceType.scope != null){
2170                                 TypeDeclaration parsedType;
2171
2172                                 if ((parsedType = sourceType.scope.referenceContext) != null){
2173                                         AbstractMethodDeclaration methodDecl = parsedType.declarationOf(method);
2174
2175                                         if (methodDecl != null){
2176                                                 Argument[] arguments = methodDecl.arguments;
2177                                                 parameterNames = new char[length][];
2178
2179                                                 for(int i = 0 ; i < length ; i++){
2180                                                         parameterNames[i] = arguments[i].name;
2181                                                 }
2182                                         }
2183                                 }
2184                         }
2185                 }
2186                 // look into the model          
2187                 if(parameterNames == null){
2188                         NameEnvironmentAnswer answer = nameEnvironment.findType(bindingType.compoundName);
2189
2190                         if(answer != null){
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();
2198
2199                                                 if(argTypeNames != null &&
2200                                                         CharOperation.equals(method.selector,sourceMethod.getSelector()) &&
2201                                                         CharOperation.equals(argTypeNames,parameterTypeNames)){
2202                                                         parameterNames = sourceMethod.getArgumentNames();
2203                                                         break;
2204                                                 }
2205                                         }
2206                                 } 
2207                         }
2208                 }
2209                 return parameterNames;
2210         }
2211         
2212         private void findNestedTypes(
2213                 char[] typeName,
2214                 SourceTypeBinding currentType,
2215                 Scope scope) {
2216                 if (typeName == null)
2217                         return;
2218
2219                 int typeLength = typeName.length;
2220
2221                 while (scope != null) { // done when a COMPILATION_UNIT_SCOPE is found
2222
2223                         switch (scope.kind) {
2224
2225                                 case Scope.METHOD_SCOPE :
2226                                 case Scope.BLOCK_SCOPE :
2227                                         BlockScope blockScope = (BlockScope) scope;
2228
2229                                         next : for (int i = 0, length = blockScope.scopeIndex; i < length; i++) {
2230
2231                                                 if (blockScope.subscopes[i] instanceof ClassScope) {
2232                                                         SourceTypeBinding localType =
2233                                                                 ((ClassScope) blockScope.subscopes[i]).referenceContext.binding;
2234
2235                                                         if (!localType.isAnonymousType()) {
2236                                                                 if (typeLength > localType.sourceName.length)
2237                                                                         continue next;
2238                                                                 if (!CharOperation.prefixEquals(typeName, localType.sourceName, false
2239                                                                         /* ignore case */
2240                                                                         ))
2241                                                                         continue next;
2242
2243                                                                 int relevance = R_DEFAULT;
2244                                                                 relevance += computeRelevanceForCaseMatching(typeName, localType.sourceName);
2245                                                                 relevance += computeRelevanceForExpectingType(localType);
2246                                                                 relevance += computeRelevanceForClass();
2247                                                                 
2248                                                                 requestor.acceptClass(
2249                                                                         localType.qualifiedPackageName(),
2250                                                                         localType.sourceName,
2251                                                                         localType.sourceName,
2252                                                                         localType.modifiers,
2253                                                                         startPosition - offset,
2254                                                                         endPosition - offset,
2255                                                                         relevance);
2256                                                         }
2257                                                 }
2258                                         }
2259                                         break;
2260
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
2265                                         break;
2266
2267                                 case Scope.COMPILATION_UNIT_SCOPE :
2268                                         return;
2269                         }
2270                         scope = scope.parent;
2271                 }
2272         }
2273
2274         private void findPackages(CompletionOnPackageReference packageStatement) {
2275
2276                 token = CharOperation.concatWith(packageStatement.tokens, '.');
2277                 if (token.length == 0)
2278                         return;
2279
2280                 setSourceRange(packageStatement.sourceStart, packageStatement.sourceEnd);
2281                 nameEnvironment.findPackages(CharOperation.toLowerCase(token), this);
2282         }
2283
2284         private void findTypesAndPackages(char[] token, Scope scope) {
2285
2286                 if (token == null)
2287                         return;
2288
2289                 if (scope.enclosingSourceType() != null)
2290                         findNestedTypes(token, scope.enclosingSourceType(), scope);
2291
2292                 if (unitScope != null) {
2293                         int typeLength = token.length;
2294                         SourceTypeBinding[] types = unitScope.topLevelTypes;
2295
2296                         for (int i = 0, length = types.length; i < length; i++) {
2297                                 SourceTypeBinding sourceType = types[i]; 
2298
2299                                 if (typeLength > sourceType.sourceName.length)  continue;
2300                                 
2301                                 if (!CharOperation.prefixEquals(token, sourceType.sourceName, false))   continue;
2302
2303                                 int relevance = R_DEFAULT;
2304                                 relevance += computeRelevanceForCaseMatching(token, sourceType.sourceName);
2305                                 relevance += computeRelevanceForExpectingType(sourceType);
2306
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,
2316                                                 relevance);
2317                                 } else {
2318                                         relevance += computeRelevanceForInterface();
2319                                         requestor.acceptInterface(
2320                                                 sourceType.qualifiedPackageName(),
2321                                                 sourceType.sourceName(),
2322                                                 sourceType.sourceName(),
2323                                                 sourceType.modifiers,
2324                                                 startPosition - offset,
2325                                                 endPosition - offset,
2326                                                 relevance);
2327                                 }
2328                         }
2329                 }
2330
2331                 if (token.length == 0)
2332                         return;
2333
2334                 findKeywords(token, baseTypes, scope);
2335                 nameEnvironment.findTypes(token, this);
2336                 nameEnvironment.findPackages(token, this);
2337         }
2338
2339         private void findTypesAndSubpackages(
2340                 char[] token,
2341                 PackageBinding packageBinding) {
2342
2343                 char[] qualifiedName =
2344                         CharOperation.concatWith(packageBinding.compoundName, token, '.');
2345
2346                 if (token == null || token.length == 0) {
2347                         int length = qualifiedName.length;
2348                         System.arraycopy(
2349                                 qualifiedName,
2350                                 0,
2351                                 qualifiedName = new char[length + 1],
2352                                 0,
2353                                 length);
2354                         qualifiedName[length] = '.';
2355                 }
2356                 nameEnvironment.findTypes(qualifiedName, this);
2357                 nameEnvironment.findPackages(qualifiedName, this);
2358         }
2359
2360         private void findVariablesAndMethods(
2361                 char[] token,
2362                 Scope scope,
2363                 InvocationSite invocationSite,
2364                 Scope invocationScope) {
2365
2366                 if (token == null)
2367                         return;
2368
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
2371
2372                 boolean staticsOnly = false;
2373                 // need to know if we're in a static context (or inside a constructor)
2374                 int tokenLength = token.length;
2375
2376                 ObjectVector localsFound = new ObjectVector();
2377                 ObjectVector fieldsFound = new ObjectVector();
2378                 ObjectVector methodsFound = new ObjectVector();
2379
2380                 Scope currentScope = scope;
2381
2382                 done1 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
2383
2384                         switch (currentScope.kind) {
2385
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;
2390
2391                                 case Scope.BLOCK_SCOPE :
2392                                         BlockScope blockScope = (BlockScope) currentScope;
2393
2394                                         next : for (int i = 0, length = blockScope.locals.length; i < length; i++) {
2395                                                 LocalVariableBinding local = blockScope.locals[i];
2396
2397                                                 if (local == null)
2398                                                         break next;
2399
2400                                                 if (tokenLength > local.name.length)
2401                                                         continue next;
2402
2403                                                 if (!CharOperation.prefixEquals(token, local.name, false /* ignore case */
2404                                                         ))
2405                                                         continue next;
2406
2407                                                 if (local.isSecret())
2408                                                         continue next;
2409
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))
2414                                                                 continue next;
2415                                                 }
2416                                                 localsFound.add(local);
2417
2418                                                 int relevance = R_DEFAULT;
2419                                                 relevance += computeRelevanceForCaseMatching(token, local.name);
2420                                                 relevance += computeRelevanceForExpectingType(local.type);
2421                                                 
2422                                                 requestor.acceptLocalVariable(
2423                                                         local.name,
2424                                                         local.type == null 
2425                                                                 ? NoChar
2426                                                                 : local.type.qualifiedPackageName(),
2427                                                         local.type == null
2428                                                                 ? local.declaration.type.toString().toCharArray()
2429                                                                 : local.type.qualifiedSourceName(),
2430                                                         local.modifiers,
2431                                                         startPosition - offset,
2432                                                         endPosition - offset,
2433                                                         relevance);
2434                                         }
2435                                         break;
2436
2437                                 case Scope.COMPILATION_UNIT_SCOPE :
2438                                         break done1;
2439                         }
2440                         currentScope = currentScope.parent;
2441                 }
2442
2443                 currentScope = scope;
2444
2445                 done2 : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
2446
2447                         switch (currentScope.kind) {
2448
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);
2455                                                                                 break done;
2456                                                                         } else { */
2457                                         findFields(
2458                                                 token,
2459                                                 enclosingType,
2460                                                 classScope,
2461                                                 fieldsFound,
2462                                                 localsFound,
2463                                                 staticsOnly,
2464                                                 invocationSite,
2465                                                 invocationScope,
2466                                                 true);
2467
2468                                         findMethods(
2469                                                 token,
2470                                                 null,
2471                                                 enclosingType,
2472                                                 classScope,
2473                                                 methodsFound,
2474                                                 staticsOnly,
2475                                                 false,
2476                                                 false,
2477                                                 invocationSite,
2478                                                 invocationScope,
2479                                                 true);
2480                                         staticsOnly |= enclosingType.isStatic();
2481                                         //                              }
2482                                         break;
2483
2484                                 case Scope.COMPILATION_UNIT_SCOPE :
2485                                         break done2;
2486                         }
2487                         currentScope = currentScope.parent;
2488                 }
2489         }
2490
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)
2494                                 return;
2495                                 
2496                         char[] name = null;
2497                         
2498                         // compute variable name for base type
2499                         try{
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)
2511 //                                                      return;
2512 //                                              name = computeBaseNames(sourceName[0], excludeNames);
2513 //                                              break;
2514 //                              }
2515                                 if(name != null) {
2516                                         int relevance = R_DEFAULT;
2517                                         relevance += computeRelevanceForCaseMatching(token, name);
2518                                         
2519                                         // accept result
2520                                         requestor.acceptVariableName(
2521                                                 qualifiedPackageName,
2522                                                 qualifiedSourceName,
2523                                                 name,
2524                                                 name,
2525                                                 startPosition - offset,
2526                                                 endPosition - offset,
2527                                                 relevance);
2528                                         return;
2529                                 }
2530                         } catch(InvalidInputException e){
2531                         }
2532                         
2533                         // compute variable name for non base type
2534                         char[][] names = computeNames(sourceName, dim > 0);
2535                         char[] displayName;
2536                         if (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] = ']';
2543                                 }
2544                         } else {
2545                                 displayName = qualifiedSourceName;
2546                         }
2547                         next : for(int i = 0 ; i < names.length ; i++){
2548                                 name = names[i];
2549                                 
2550                                 if (!CharOperation.prefixEquals(token, name, false))
2551                                         continue next;
2552                                 
2553                                 // completion must be an identifier (not a keyword, ...).
2554                                 try{
2555                                         nameScanner.setSource(name);
2556                                         if(nameScanner.getNextToken() != TokenNameIdentifier)
2557                                                 continue next;
2558                                 } catch(InvalidInputException e){
2559                                         continue next;
2560                                 }
2561                                 
2562                                 int count = 2;
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());
2567                                                 j = 0;
2568                                         }       
2569                                 }
2570                                 
2571                                 int relevance = R_DEFAULT;
2572                                 relevance += computeRelevanceForCaseMatching(token, name);
2573                                 
2574                                 // accept result
2575                                 requestor.acceptVariableName(
2576                                         qualifiedPackageName,
2577                                         displayName,
2578                                         name,
2579                                         name,
2580                                         startPosition - offset,
2581                                         endPosition - offset,
2582                                         relevance);
2583                         }
2584         }
2585
2586         private void findVariableNames(char[] name, TypeReference type , char[][] excludeNames){
2587
2588                 if(type != null &&
2589                         type.binding != null &&
2590                         type.binding.problemId() == Binding.NoError){
2591                         TypeBinding tb = type.binding;
2592                         findVariableName(
2593                                 name,
2594                                 tb.leafComponentType().qualifiedPackageName(),
2595                                 tb.leafComponentType().qualifiedSourceName(),
2596                                 tb.leafComponentType().sourceName(),
2597                                 excludeNames,
2598                                 type.dimensions());
2599                 }/*     else {
2600                         char[][] typeName = type.getTypeName();
2601                         findVariableName(
2602                                 name,
2603                                 NoChar,
2604                                 CharOperation.concatWith(typeName, '.'),
2605                                 typeName[typeName.length - 1],
2606                                 excludeNames,
2607                                 type.dimensions());
2608                 }*/
2609         }
2610         
2611         public AssistParser getParser() {
2612
2613                 return parser;
2614         }
2615
2616         protected void reset() {
2617
2618                 super.reset();
2619                 this.knownPkgs = new HashtableOfObject(10);
2620                 this.knownTypes = new HashtableOfObject(10);
2621         }
2622
2623         private void setSourceRange(int start, int end) {
2624
2625                 this.startPosition = start;
2626                 this.endPosition = end + 1;
2627         }
2628         
2629         private char[] computeBaseNames(char firstName, char[][] excludeNames){
2630                 char[] name = new char[]{firstName};
2631                 
2632                 for(int i = 0 ; i < excludeNames.length ; i++){
2633                         if(CharOperation.equals(name, excludeNames[i], false)) {
2634                                 name[0]++;
2635                                 if(name[0] > 'z')
2636                                         name[0] = 'a';
2637                                 if(name[0] == firstName)
2638                                         return null;
2639                                 i = 0;
2640                         }       
2641                 }
2642                 
2643                 return name;
2644         }
2645         private void computeExpectedTypes(AstNode parent, Scope scope){
2646                 int expectedTypeCount = 0;
2647                 expectedTypes = new TypeBinding[1];
2648                 
2649                 if(parent instanceof AbstractVariableDeclaration) {
2650                         TypeBinding binding = ((AbstractVariableDeclaration)parent).type.binding;
2651                         if(binding != null) {
2652                                 expectedTypes[expectedTypeCount++] = binding;
2653                         }
2654                 } else if(parent instanceof Assignment) {
2655                         TypeBinding binding = ((Assignment)parent).lhsType;
2656                         if(binding != null) {
2657                                 expectedTypes[expectedTypeCount++] = binding;
2658                         }
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;
2664                         }
2665                 }
2666                 
2667                 System.arraycopy(expectedTypes, 0, expectedTypes = new TypeBinding[expectedTypeCount], 0, expectedTypeCount);
2668         }
2669         private char[][] computeNames(char[] sourceName, boolean forArray){
2670                 char[][] names = new char[5][];
2671                 int nameCount = 0;
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);
2680                                         }
2681                                         name[0] = Character.toLowerCase(name[0]);
2682                                         
2683                                         if(forArray) {
2684                                                 int length = name.length;
2685                                                 if (name[length-1] == 's'){
2686                                                         System.arraycopy(name, 0, name = new char[length + 2], 0, length);
2687                                                         name[length] = 'e';
2688                                                         name[length+1] = 's';
2689                                                 } else {
2690                                                         System.arraycopy(name, 0, name = new char[length + 1], 0, length);
2691                                                         name[length] = 's';
2692                                                 }
2693                                         }                                       
2694                                         names[nameCount++] = name;
2695                                 }
2696                         }
2697                         previousIsUpperCase = isUpperCase;
2698                 }
2699                 if(nameCount == 0){
2700                         char[] name = CharOperation.toLowerCase(sourceName);
2701                         if(forArray) {
2702                                 int length = name.length;
2703                                 if (name[length-1] == 's'){
2704                                         System.arraycopy(name, 0, name = new char[length + 2], 0, length);
2705                                         name[length] = 'e';
2706                                         name[length+1] = 's';
2707                                 } else {
2708                                         System.arraycopy(name, 0, name = new char[length + 1], 0, length);
2709                                         name[length] = 's';
2710                                 }
2711                         }                                       
2712                         names[nameCount++] = name;
2713                         
2714                 }
2715                 System.arraycopy(names, 0, names = new char[nameCount][], 0, nameCount);
2716                 return names;
2717         }
2718         
2719         private char[] computePrefix(SourceTypeBinding declarationType, SourceTypeBinding invocationType, boolean isStatic){
2720                 
2721                 StringBuffer completion = new StringBuffer(10);
2722
2723                 if (isStatic) {
2724                         completion.append(declarationType.sourceName());
2725                         
2726                 } else if (declarationType == invocationType) {
2727                         completion.append(THIS);
2728                         
2729                 } else {
2730                         
2731                         if (!declarationType.isNestedType()) {
2732                                 
2733                                 completion.append(declarationType.sourceName());
2734                                 completion.append('.');
2735                                 completion.append(THIS);
2736
2737                         } else if (!declarationType.isAnonymousType()) {
2738                                 
2739                                 completion.append(declarationType.sourceName());
2740                                 completion.append('.');
2741                                 completion.append(THIS);
2742                                 
2743                         }
2744                 }
2745                 
2746                 return completion.toString().toCharArray();
2747         }
2748         
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)
2754                                         return true;
2755                                 enclosing = enclosing.enclosingType();
2756                         }
2757                 }
2758                 return false;
2759         }
2760
2761 }