KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > codeassist > UnresolvedReferenceNameFinder


1 /*******************************************************************************
2  * Copyright (c) 2006, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.codeassist;
12
13 import org.eclipse.jdt.core.compiler.CharOperation;
14 import org.eclipse.jdt.internal.codeassist.complete.CompletionParser;
15 import org.eclipse.jdt.internal.codeassist.complete.CompletionScanner;
16 import org.eclipse.jdt.internal.compiler.ASTVisitor;
17 import org.eclipse.jdt.internal.compiler.ast.ASTNode;
18 import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
19 import org.eclipse.jdt.internal.compiler.ast.Argument;
20 import org.eclipse.jdt.internal.compiler.ast.Block;
21 import org.eclipse.jdt.internal.compiler.ast.ConstructorDeclaration;
22 import org.eclipse.jdt.internal.compiler.ast.FieldDeclaration;
23 import org.eclipse.jdt.internal.compiler.ast.Initializer;
24 import org.eclipse.jdt.internal.compiler.ast.LocalDeclaration;
25 import org.eclipse.jdt.internal.compiler.ast.MethodDeclaration;
26 import org.eclipse.jdt.internal.compiler.ast.Statement;
27 import org.eclipse.jdt.internal.compiler.ast.TypeDeclaration;
28 import org.eclipse.jdt.internal.compiler.lookup.BlockScope;
29 import org.eclipse.jdt.internal.compiler.lookup.ClassScope;
30 import org.eclipse.jdt.internal.compiler.lookup.MethodScope;
31 import org.eclipse.jdt.internal.compiler.lookup.Scope;
32 import org.eclipse.jdt.internal.compiler.util.SimpleSetOfCharArray;
33 import org.eclipse.jdt.internal.compiler.util.Util;
34
35 public class UnresolvedReferenceNameFinder extends ASTVisitor {
36     private static final int MAX_LINE_COUNT = 100;
37     private static final int FAKE_BLOCKS_COUNT = 20;
38     
39     public static interface UnresolvedReferenceNameRequestor {
40         public void acceptName(char[] name);
41     }
42     
43     private UnresolvedReferenceNameRequestor requestor;
44     
45     private CompletionEngine completionEngine;
46     private CompletionParser parser;
47     private CompletionScanner completionScanner;
48     
49     private int parentsPtr;
50     private ASTNode[] parents;
51     
52     private int potentialVariableNamesPtr;
53     private char[][] potentialVariableNames;
54     private int[] potentialVariableNameStarts;
55     
56     private SimpleSetOfCharArray acceptedNames = new SimpleSetOfCharArray();
57     
58     public UnresolvedReferenceNameFinder(CompletionEngine completionEngine) {
59         this.completionEngine = completionEngine;
60         this.parser = completionEngine.parser;
61         this.completionScanner = (CompletionScanner) parser.scanner;
62     }
63     
64     private void acceptName(char[] name) {
65         // the null check is added to fix bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=166570
66
if (name == null) return;
67                         
68         if (!CharOperation.prefixEquals(this.completionEngine.completionToken, name, false /* ignore case */)
69                 && !(this.completionEngine.options.camelCaseMatch && CharOperation.camelCaseMatch(this.completionEngine.completionToken, name))) return;
70         
71         if (acceptedNames.includes(name)) return;
72         
73         this.acceptedNames.add(name);
74         
75         // accept result
76
this.requestor.acceptName(name);
77     }
78     
79     public void find(
80             char[] startWith,
81             Initializer initializer,
82             ClassScope scope,
83             int from,
84             char[][] discouragedNames,
85             UnresolvedReferenceNameRequestor nameRequestor) {
86         MethodDeclaration fakeMethod =
87             this.findAfter(startWith, scope, from, initializer.bodyEnd, MAX_LINE_COUNT, false, discouragedNames, nameRequestor);
88         if (fakeMethod != null) fakeMethod.traverse(this, scope);
89     }
90     
91     public void find(
92             char[] startWith,
93             AbstractMethodDeclaration methodDeclaration,
94             int from,
95             char[][] discouragedNames,
96             UnresolvedReferenceNameRequestor nameRequestor) {
97         MethodDeclaration fakeMethod =
98             this.findAfter(startWith, methodDeclaration.scope, from, methodDeclaration.bodyEnd, MAX_LINE_COUNT, false, discouragedNames, nameRequestor);
99         if (fakeMethod != null) fakeMethod.traverse(this, methodDeclaration.scope.classScope());
100     }
101     
102     public void findAfter(
103             char[] startWith,
104             Scope scope,
105             ClassScope classScope,
106             int from,
107             int to,
108             char[][] discouragedNames,
109             UnresolvedReferenceNameRequestor nameRequestor) {
110         MethodDeclaration fakeMethod =
111             this.findAfter(startWith, scope, from, to, MAX_LINE_COUNT / 2, true, discouragedNames, nameRequestor);
112         if (fakeMethod != null) fakeMethod.traverse(this, classScope);
113     }
114     
115     private MethodDeclaration findAfter(
116             char[] startWith,
117             Scope s,
118             int from,
119             int to,
120             int maxLineCount,
121             boolean outsideEnclosingBlock,
122             char[][] discouragedNames,
123             UnresolvedReferenceNameRequestor nameRequestor) {
124         this.requestor = nameRequestor;
125         
126         // reinitialize completion scanner to be usable as a normal scanner
127
this.completionScanner.cursorLocation = 0;
128         
129         if (!outsideEnclosingBlock) {
130             // compute location of the end of the current block
131
this.completionScanner.resetTo(from + 1, to);
132             this.completionScanner.jumpOverBlock();
133             
134             to = this.completionScanner.startPosition - 1;
135         }
136         
137         int maxEnd =
138             this.completionScanner.getLineEnd(
139                     Util.getLineNumber(from, this.completionScanner.lineEnds, 0, this.completionScanner.linePtr) + maxLineCount);
140         
141         int end;
142         if (maxEnd < 0) {
143             end = to;
144         } else {
145             end = maxEnd < to ? maxEnd : to;
146         }
147         
148         this.parser.startRecordingIdentifiers(from, end);
149         
150         MethodDeclaration fakeMethod = this.parser.parseSomeStatements(
151                 from,
152                 end,
153                 outsideEnclosingBlock ? FAKE_BLOCKS_COUNT : 0,
154                 s.compilationUnitScope().referenceContext);
155         
156         this.parser.stopRecordingIdentifiers();
157         
158         if(!this.initPotentialNamesTables(discouragedNames)) return null;
159         
160         this.parentsPtr = -1;
161         this.parents = new ASTNode[10];
162         
163         return fakeMethod;
164     }
165     
166     public void findBefore(
167             char[] startWith,
168             Scope scope,
169             ClassScope classScope,
170             int from,
171             int recordTo,
172             int parseTo,
173             char[][] discouragedNames,
174             UnresolvedReferenceNameRequestor nameRequestor) {
175         MethodDeclaration fakeMethod =
176             this.findBefore(startWith, scope, from, recordTo, parseTo, MAX_LINE_COUNT / 2, discouragedNames, nameRequestor);
177         if (fakeMethod != null) fakeMethod.traverse(this, classScope);
178     }
179     
180     private MethodDeclaration findBefore(
181             char[] startWith,
182             Scope s,
183             int from,
184             int recordTo,
185             int parseTo,
186             int maxLineCount,
187             char[][] discouragedNames,
188             UnresolvedReferenceNameRequestor nameRequestor) {
189         this.requestor = nameRequestor;
190         
191         // reinitialize completion scanner to be usable as a normal scanner
192
this.completionScanner.cursorLocation = 0;
193         
194         int minStart =
195             this.completionScanner.getLineStart(
196                     Util.getLineNumber(recordTo, this.completionScanner.lineEnds, 0, this.completionScanner.linePtr) - maxLineCount);
197         
198         int start;
199         int fakeBlocksCount;
200         if (minStart <= from) {
201             start = from;
202             fakeBlocksCount = 0;
203         } else {
204             start = minStart;
205             fakeBlocksCount = FAKE_BLOCKS_COUNT;
206         }
207         
208         this.parser.startRecordingIdentifiers(start, recordTo);
209         
210         MethodDeclaration fakeMethod = this.parser.parseSomeStatements(
211                 start,
212                 parseTo,
213                 fakeBlocksCount,
214                 s.compilationUnitScope().referenceContext);
215         
216         this.parser.stopRecordingIdentifiers();
217         
218         if(!this.initPotentialNamesTables(discouragedNames)) return null;
219         
220         this.parentsPtr = -1;
221         this.parents = new ASTNode[10];
222         
223         return fakeMethod;
224     }
225     
226     private boolean initPotentialNamesTables(char[][] discouragedNames) {
227         char[][] pvns = this.parser.potentialVariableNames;
228         int[] pvnss = this.parser.potentialVariableNameStarts;
229         int pvnsPtr = this.parser.potentialVariableNamesPtr;
230         
231         if (pvnsPtr < 0) return false; // there is no potential names
232

233         // remove null and discouragedNames
234
int discouragedNamesCount = discouragedNames == null ? 0 : discouragedNames.length;
235         int j = -1;
236         next : for (int i = 0; i <= pvnsPtr; i++) {
237             char[] temp = pvns[i];
238             
239             if (temp == null) continue next;
240             
241             for (int k = 0; k < discouragedNamesCount; k++) {
242                 if (CharOperation.equals(temp, discouragedNames[k], false)) {
243                     continue next;
244                 }
245             }
246             
247             pvns[i] = null;
248             pvns[++j] = temp;
249             pvnss[j] = pvnss[i];
250         }
251         pvnsPtr = j;
252         
253         if (pvnsPtr < 0) return false; // there is no potential names
254

255         this.potentialVariableNames = pvns;
256         this.potentialVariableNameStarts = pvnss;
257         this.potentialVariableNamesPtr = pvnsPtr;
258         
259         return true;
260     }
261     
262     private void popParent() {
263         this.parentsPtr--;
264     }
265     private void pushParent(ASTNode parent) {
266         int length = this.parents.length;
267         if (this.parentsPtr >= length - 1) {
268             System.arraycopy(this.parents, 0, this.parents = new ASTNode[length * 2], 0, length);
269         }
270         this.parents[++this.parentsPtr] = parent;
271     }
272     
273     private ASTNode getEnclosingDeclaration() {
274         int i = this.parentsPtr;
275         while (i > -1) {
276             ASTNode parent = parents[i];
277             if (parent instanceof AbstractMethodDeclaration) {
278                 return parent;
279             } else if (parent instanceof Initializer) {
280                 return parent;
281             } else if (parent instanceof FieldDeclaration) {
282                 return parent;
283             } else if (parent instanceof TypeDeclaration) {
284                 return parent;
285             }
286             i--;
287         }
288         return null;
289     }
290     
291     public boolean visit(Block block, BlockScope blockScope) {
292         ASTNode enclosingDeclaration = getEnclosingDeclaration();
293         removeLocals(block.statements, enclosingDeclaration.sourceStart, block.sourceEnd);
294         pushParent(block);
295         return true;
296     }
297     
298     public boolean visit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) {
299         if (((constructorDeclaration.bits & ASTNode.IsDefaultConstructor) == 0) && !constructorDeclaration.isClinit()) {
300             removeLocals(
301                     constructorDeclaration.arguments,
302                     constructorDeclaration.declarationSourceStart,
303                     constructorDeclaration.declarationSourceEnd);
304             removeLocals(
305                     constructorDeclaration.statements,
306                     constructorDeclaration.declarationSourceStart,
307                     constructorDeclaration.declarationSourceEnd);
308         }
309         pushParent(constructorDeclaration);
310         return true;
311     }
312     
313     public boolean visit(FieldDeclaration fieldDeclaration, MethodScope methodScope) {
314         pushParent(fieldDeclaration);
315         return true;
316     }
317     
318     public boolean visit(Initializer initializer, MethodScope methodScope) {
319         pushParent(initializer);
320         return true;
321     }
322     
323     public boolean visit(MethodDeclaration methodDeclaration, ClassScope classScope) {
324         removeLocals(
325                 methodDeclaration.arguments,
326                 methodDeclaration.declarationSourceStart,
327                 methodDeclaration.declarationSourceEnd);
328         removeLocals(
329                 methodDeclaration.statements,
330                 methodDeclaration.declarationSourceStart,
331                 methodDeclaration.declarationSourceEnd);
332         pushParent(methodDeclaration);
333         return true;
334     }
335     
336     public boolean visit(TypeDeclaration localTypeDeclaration, BlockScope blockScope) {
337         removeFields(localTypeDeclaration);
338         pushParent(localTypeDeclaration);
339         return true;
340     }
341     
342     public boolean visit(TypeDeclaration memberTypeDeclaration, ClassScope classScope) {
343         removeFields(memberTypeDeclaration);
344         pushParent(memberTypeDeclaration);
345         return true;
346     }
347     
348     public void endVisit(Block block, BlockScope blockScope) {
349         popParent();
350     }
351     
352     public void endVisit(Argument argument, BlockScope blockScope) {
353         endVisitRemoved(argument.declarationSourceStart, argument.sourceEnd);
354     }
355     
356     public void endVisit(Argument argument, ClassScope classScope) {
357         endVisitRemoved(argument.declarationSourceStart, argument.sourceEnd);
358     }
359     
360     public void endVisit(ConstructorDeclaration constructorDeclaration, ClassScope classScope) {
361         if (((constructorDeclaration.bits & ASTNode.IsDefaultConstructor) == 0) && !constructorDeclaration.isClinit()) {
362             endVisitPreserved(constructorDeclaration.bodyStart, constructorDeclaration.bodyEnd);
363         }
364         popParent();
365     }
366     
367     public void endVisit(FieldDeclaration fieldDeclaration, MethodScope methodScope) {
368         endVisitRemoved(fieldDeclaration.declarationSourceStart, fieldDeclaration.sourceEnd);
369         endVisitPreserved(fieldDeclaration.sourceEnd, fieldDeclaration.declarationEnd);
370         popParent();
371     }
372     
373     public void endVisit(Initializer initializer, MethodScope methodScope) {
374         endVisitPreserved(initializer.bodyStart, initializer.bodyEnd);
375         popParent();
376     }
377     
378     public void endVisit(LocalDeclaration localDeclaration, BlockScope blockScope) {
379         endVisitRemoved(localDeclaration.declarationSourceStart, localDeclaration.sourceEnd);
380     }
381     
382     public void endVisit(MethodDeclaration methodDeclaration, ClassScope classScope) {
383         endVisitPreserved(
384                 methodDeclaration.bodyStart,
385                 methodDeclaration.bodyEnd);
386         popParent();
387     }
388     
389     public void endVisit(TypeDeclaration typeDeclaration, BlockScope blockScope) {
390         endVisitRemoved(typeDeclaration.sourceStart, typeDeclaration.declarationSourceEnd);
391         popParent();
392     }
393     
394     public void endVisit(TypeDeclaration typeDeclaration, ClassScope classScope) {
395         endVisitRemoved(typeDeclaration.sourceStart, typeDeclaration.declarationSourceEnd);
396         popParent();
397     }
398     
399     private int indexOfFisrtNameAfter(int position) {
400         int left = 0;
401         int right = this.potentialVariableNamesPtr;
402         
403         next : while (true) {
404             if (right < left) return -1;
405             
406             int mid = left + (right - left) / 2;
407             int midPosition = this.potentialVariableNameStarts[mid];
408             if (midPosition < 0) {
409                 int nextMid = indexOfNextName(mid);
410                 if (nextMid < 0 || right < nextMid) { // no next index or next index is after 'right'
411
right = mid - 1;
412                     continue next;
413                 }
414                 mid = nextMid;
415                 midPosition = this.potentialVariableNameStarts[nextMid];
416                 
417                 if (mid == right) { // mid and right are at the same index, we must move 'left'
418
int leftPosition = this.potentialVariableNameStarts[left];
419                     if (leftPosition < 0 || leftPosition < position) { // 'left' is empty or 'left' is before the position
420
int nextLeft = indexOfNextName(left);
421                         if (nextLeft < 0) return - 1;
422                         
423                         left = nextLeft;
424                         continue next;
425                     }
426                     
427                     return left;
428                 }
429             }
430             
431             if (left != right) {
432                 if (midPosition < position) {
433                     left = mid + 1;
434                 } else {
435                     right = mid;
436                 }
437             } else {
438                 if (midPosition < position) {
439                     return -1;
440                 }
441                 return mid;
442             }
443         }
444     }
445     
446     private int indexOfNextName(int index) {
447         int nextIndex = index + 1;
448         while (nextIndex <= this.potentialVariableNamesPtr &&
449                 this.potentialVariableNames[nextIndex] == null) {
450             int jumpIndex = -this.potentialVariableNameStarts[nextIndex];
451             if (jumpIndex > 0) {
452                 nextIndex = jumpIndex;
453             } else {
454                 nextIndex++;
455             }
456         }
457         
458         if (this.potentialVariableNamesPtr < nextIndex) {
459             if (index < this.potentialVariableNamesPtr) {
460                 this.potentialVariableNamesPtr = index;
461             }
462             return -1;
463         }
464         if (index + 1 < nextIndex) {
465             this.potentialVariableNameStarts[index + 1] = -nextIndex;
466         }
467         return nextIndex;
468     }
469     
470     private void removeNameAt(int index) {
471         this.potentialVariableNames[index] = null;
472         int nextIndex = indexOfNextName(index);
473         if (nextIndex != -1) {
474             this.potentialVariableNameStarts[index] = -nextIndex;
475         } else {
476             this.potentialVariableNamesPtr = index - 1;
477         }
478     }
479     
480     private void endVisitPreserved(int start, int end) {
481         int i = indexOfFisrtNameAfter(start);
482         done : while (i != -1) {
483             int nameStart = this.potentialVariableNameStarts[i];
484             if (start < nameStart && nameStart < end) {
485                 this.acceptName(this.potentialVariableNames[i]);
486                 this.removeNameAt(i);
487             }
488             
489             if (end < nameStart) break done;
490             i = indexOfNextName(i);
491         }
492     }
493
494     private void endVisitRemoved(int start, int end) {
495         int i = indexOfFisrtNameAfter(start);
496         done : while (i != -1) {
497             int nameStart = this.potentialVariableNameStarts[i];
498             if (start < nameStart && nameStart < end) {
499                 this.removeNameAt(i);
500             }
501             
502             if (end < nameStart) break done;
503             i = indexOfNextName(i);
504         }
505     }
506     
507     private void removeLocals(Statement[] statements, int start, int end) {
508         if (statements != null) {
509             for (int i = 0; i < statements.length; i++) {
510                 if (statements[i] instanceof LocalDeclaration) {
511                     LocalDeclaration localDeclaration = (LocalDeclaration) statements[i];
512                     int j = indexOfFisrtNameAfter(start);
513                     done : while (j != -1) {
514                         int nameStart = this.potentialVariableNameStarts[j];
515                         if (start <= nameStart && nameStart <= end) {
516                             if (CharOperation.equals(this.potentialVariableNames[j], localDeclaration.name, false)) {
517                                 this.removeNameAt(j);
518                             }
519                         }
520                         
521                         if (end < nameStart) break done;
522                         j = indexOfNextName(j);
523                     }
524                 }
525             }
526             
527         }
528     }
529     
530     private void removeFields(TypeDeclaration typeDeclaration) {
531         int start = typeDeclaration.declarationSourceStart;
532         int end = typeDeclaration.declarationSourceEnd;
533         
534         FieldDeclaration[] fieldDeclarations = typeDeclaration.fields;
535         if (fieldDeclarations != null) {
536             for (int i = 0; i < fieldDeclarations.length; i++) {
537                 int j = indexOfFisrtNameAfter(start);
538                 done : while (j != -1) {
539                     int nameStart = this.potentialVariableNameStarts[j];
540                     if (start <= nameStart && nameStart <= end) {
541                         if (CharOperation.equals(this.potentialVariableNames[j], fieldDeclarations[i].name, false)) {
542                             this.removeNameAt(j);
543                         }
544                     }
545                     
546                     if (end < nameStart) break done;
547                     j = indexOfNextName(j);
548                 }
549             }
550         }
551     }
552 }
553
Popular Tags