KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > core > dom > rewrite > ImportRewriteAnalyzer


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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.core.dom.rewrite;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.HashSet JavaDoc;
16 import java.util.List JavaDoc;
17 import java.util.Set JavaDoc;
18
19 import org.eclipse.core.runtime.IProgressMonitor;
20 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.eclipse.jdt.core.IBuffer;
22 import org.eclipse.jdt.core.ICompilationUnit;
23 import org.eclipse.jdt.core.IJavaElement;
24 import org.eclipse.jdt.core.JavaCore;
25 import org.eclipse.jdt.core.JavaModelException;
26 import org.eclipse.jdt.core.Signature;
27 import org.eclipse.jdt.core.dom.ASTNode;
28 import org.eclipse.jdt.core.dom.CompilationUnit;
29 import org.eclipse.jdt.core.dom.ImportDeclaration;
30 import org.eclipse.jdt.core.dom.PackageDeclaration;
31 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
32 import org.eclipse.jdt.core.search.IJavaSearchConstants;
33 import org.eclipse.jdt.core.search.IJavaSearchScope;
34 import org.eclipse.jdt.core.search.SearchEngine;
35 import org.eclipse.jdt.core.search.TypeNameRequestor;
36 import org.eclipse.jface.text.IRegion;
37 import org.eclipse.jface.text.Region;
38 import org.eclipse.text.edits.DeleteEdit;
39 import org.eclipse.text.edits.InsertEdit;
40 import org.eclipse.text.edits.MultiTextEdit;
41
42 public final class ImportRewriteAnalyzer {
43     
44     private final ICompilationUnit compilationUnit;
45     private final ArrayList JavaDoc packageEntries;
46     
47     private final List JavaDoc importsCreated;
48     private final List JavaDoc staticImportsCreated;
49
50     private final IRegion replaceRange;
51     
52     private final int importOnDemandThreshold;
53     private final int staticImportOnDemandThreshold;
54
55     private boolean filterImplicitImports;
56     private boolean findAmbiguousImports;
57     
58     private int flags= 0;
59     
60     private static final int F_NEEDS_LEADING_DELIM= 2;
61     private static final int F_NEEDS_TRAILING_DELIM= 4;
62     
63     private static final String JavaDoc JAVA_LANG= "java.lang"; //$NON-NLS-1$
64

65     public ImportRewriteAnalyzer(ICompilationUnit cu, CompilationUnit root, String JavaDoc[] importOrder, int threshold, int staticThreshold, boolean restoreExistingImports) {
66         this.compilationUnit= cu;
67         this.importOnDemandThreshold= threshold;
68         this.staticImportOnDemandThreshold= staticThreshold;
69         
70         this.filterImplicitImports= true;
71         this.findAmbiguousImports= true; //!restoreExistingImports;
72

73         this.packageEntries= new ArrayList JavaDoc(20);
74         this.importsCreated= new ArrayList JavaDoc();
75         this.staticImportsCreated= new ArrayList JavaDoc();
76         this.flags= 0;
77         
78         this.replaceRange= evaluateReplaceRange(root);
79         if (restoreExistingImports) {
80             addExistingImports(root);
81         }
82
83         PackageEntry[] order= new PackageEntry[importOrder.length];
84         for (int i= 0; i < order.length; i++) {
85             String JavaDoc curr= importOrder[i];
86             if (curr.length() > 0 && curr.charAt(0) == '#') {
87                 curr= curr.substring(1);
88                 order[i]= new PackageEntry(curr, curr, true); // static import group
89
} else {
90                 order[i]= new PackageEntry(curr, curr, false); // normal import group
91
}
92         }
93         
94         addPreferenceOrderHolders(order);
95     }
96     
97     private int getSpacesBetweenImportGroups() {
98         try {
99             int num= Integer.parseInt(this.compilationUnit.getJavaProject().getOption(DefaultCodeFormatterConstants.FORMATTER_BLANK_LINES_BETWEEN_IMPORT_GROUPS, true));
100             if (num >= 0)
101                 return num;
102         } catch (NumberFormatException JavaDoc e) {
103             // fall through
104
}
105         return 1;
106     }
107     
108     private void addPreferenceOrderHolders(PackageEntry[] preferenceOrder) {
109         if (this.packageEntries.isEmpty()) {
110             // all new: copy the elements
111
for (int i= 0; i < preferenceOrder.length; i++) {
112                 this.packageEntries.add(preferenceOrder[i]);
113             }
114         } else {
115             // match the preference order entries to existing imports
116
// entries not found are appended after the last successfully matched entry
117

118             PackageEntry[] lastAssigned= new PackageEntry[preferenceOrder.length];
119             
120             // find an existing package entry that matches most
121
for (int k= 0; k < this.packageEntries.size(); k++) {
122                 PackageEntry entry= (PackageEntry) this.packageEntries.get(k);
123                 if (!entry.isComment()) {
124                     String JavaDoc currName= entry.getName();
125                     int currNameLen= currName.length();
126                     int bestGroupIndex= -1;
127                     int bestGroupLen= -1;
128                     for (int i= 0; i < preferenceOrder.length; i++) {
129                         boolean currPrevStatic= preferenceOrder[i].isStatic();
130                         if (currPrevStatic == entry.isStatic()) {
131                             String JavaDoc currPrefEntry= preferenceOrder[i].getName();
132                             int currPrefLen= currPrefEntry.length();
133                             if (currName.startsWith(currPrefEntry) && currPrefLen >= bestGroupLen) {
134                                 if (currPrefLen == currNameLen || currName.charAt(currPrefLen) == '.') {
135                                     if (bestGroupIndex == -1 || currPrefLen > bestGroupLen) {
136                                         bestGroupLen= currPrefLen;
137                                         bestGroupIndex= i;
138                                     }
139                                 }
140                             }
141                         }
142                     }
143                     if (bestGroupIndex != -1) {
144                         entry.setGroupID(preferenceOrder[bestGroupIndex].getName());
145                         lastAssigned[bestGroupIndex]= entry; // remember last entry
146
}
147                 }
148             }
149             // fill in not-assigned categories, keep partial order
150
int currAppendIndex= 0;
151             for (int i= 0; i < lastAssigned.length; i++) {
152                 PackageEntry entry= lastAssigned[i];
153                 if (entry == null) {
154                     PackageEntry newEntry= preferenceOrder[i];
155                     if (currAppendIndex == 0 && !newEntry.isStatic()) {
156                         currAppendIndex= getIndexAfterStatics();
157                     }
158                     this.packageEntries.add(currAppendIndex, newEntry);
159                     currAppendIndex++;
160                 } else {
161                     currAppendIndex= this.packageEntries.indexOf(entry) + 1;
162                 }
163             }
164         }
165     }
166
167     private static String JavaDoc getQualifier(ImportDeclaration decl) {
168         String JavaDoc name= decl.getName().getFullyQualifiedName();
169         return decl.isOnDemand() ? name : Signature.getQualifier(name);
170     }
171
172     private static String JavaDoc getFullName(ImportDeclaration decl) {
173         String JavaDoc name= decl.getName().getFullyQualifiedName();
174         return decl.isOnDemand() ? name + ".*": name; //$NON-NLS-1$
175
}
176     
177     private void addExistingImports(CompilationUnit root) {
178         List JavaDoc/*ImportDeclaration*/ decls= root.imports();
179         if (decls.isEmpty()) {
180             return;
181         }
182         PackageEntry currPackage= null;
183             
184         ImportDeclaration curr= (ImportDeclaration) decls.get(0);
185         int currOffset= curr.getStartPosition();
186         int currLength= curr.getLength();
187         int currEndLine= root.getLineNumber(currOffset + currLength);
188         
189         for (int i= 1; i < decls.size(); i++) {
190             boolean isStatic= curr.isStatic();
191             String JavaDoc name= getFullName(curr);
192             String JavaDoc packName= getQualifier(curr);
193             if (currPackage == null || currPackage.compareTo(packName, isStatic) != 0) {
194                 currPackage= new PackageEntry(packName, null, isStatic);
195                 this.packageEntries.add(currPackage);
196             }
197
198             ImportDeclaration next= (ImportDeclaration) decls.get(i);
199             int nextOffset= next.getStartPosition();
200             int nextLength= next.getLength();
201             int nextOffsetLine= root.getLineNumber(nextOffset);
202
203             // if next import is on a different line, modify the end position to the next line begin offset
204
if (currEndLine < nextOffsetLine) {
205                 currEndLine++;
206                 nextOffset= root.getPosition(currEndLine, 0);
207             }
208             currPackage.add(new ImportDeclEntry(name, isStatic, new Region(currOffset, nextOffset - currOffset)));
209             currOffset= nextOffset;
210             curr= next;
211                 
212             // add a comment entry for spacing between imports
213
if (currEndLine < nextOffsetLine) {
214                 nextOffset= root.getPosition(nextOffsetLine, 0);
215                 
216                 currPackage= new PackageEntry(); // create a comment package entry for this
217
this.packageEntries.add(currPackage);
218                 currPackage.add(new ImportDeclEntry(null, false, new Region(currOffset, nextOffset - currOffset)));
219                     
220                 currOffset= nextOffset;
221             }
222             currEndLine= root.getLineNumber(nextOffset + nextLength);
223         }
224
225         boolean isStatic= curr.isStatic();
226         String JavaDoc name= getFullName(curr);
227         String JavaDoc packName= getQualifier(curr);
228         if (currPackage == null || currPackage.compareTo(packName, isStatic) != 0) {
229             currPackage= new PackageEntry(packName, null, isStatic);
230             this.packageEntries.add(currPackage);
231         }
232         int length= this.replaceRange.getOffset() + this.replaceRange.getLength() - curr.getStartPosition();
233         currPackage.add(new ImportDeclEntry(name, isStatic, new Region(curr.getStartPosition(), length)));
234     }
235             
236     /**
237      * Sets that implicit imports (types in default package, CU- package and
238      * 'java.lang') should not be created. Note that this is a heuristic filter and can
239      * lead to missing imports, e.g. in cases where a type is forced to be specified
240      * due to a name conflict.
241      * By default, the filter is enabled.
242      * @param filterImplicitImports The filterImplicitImports to set
243      */

244     public void setFilterImplicitImports(boolean filterImplicitImports) {
245         this.filterImplicitImports= filterImplicitImports;
246     }
247     
248     /**
249      * When set searches for imports that can not be folded into on-demand
250      * imports but must be specified explicitly
251      * @param findAmbiguousImports The new value
252      */

253     public void setFindAmbiguousImports(boolean findAmbiguousImports) {
254         this.findAmbiguousImports= findAmbiguousImports;
255     }
256             
257     private static class PackageMatcher {
258         private String JavaDoc newName;
259         private String JavaDoc bestName;
260         private int bestMatchLen;
261         
262         public PackageMatcher() {
263             // initialization in 'initialize'
264
}
265         
266         public void initialize(String JavaDoc newImportName, String JavaDoc bestImportName) {
267             this.newName= newImportName;
268             this.bestName= bestImportName;
269             this.bestMatchLen= getCommonPrefixLength(bestImportName, newImportName);
270         }
271         
272         public boolean isBetterMatch(String JavaDoc currName, boolean preferCurr) {
273             boolean isBetter;
274             int currMatchLen= getCommonPrefixLength(currName, this.newName);
275             int matchDiff= currMatchLen - this.bestMatchLen;
276             if (matchDiff == 0) {
277                 if (currMatchLen == this.newName.length() && currMatchLen == currName.length() && currMatchLen == this.bestName.length()) {
278                     // duplicate entry and complete match
279
isBetter= preferCurr;
280                 } else {
281                     isBetter= sameMatchLenTest(currName);
282                 }
283             } else {
284                 isBetter= (matchDiff > 0); // curr has longer match
285
}
286             if (isBetter) {
287                 this.bestName= currName;
288                 this.bestMatchLen= currMatchLen;
289             }
290             return isBetter;
291         }
292                 
293         private boolean sameMatchLenTest(String JavaDoc currName) {
294             int matchLen= this.bestMatchLen;
295             // known: bestName and currName differ from newName at position 'matchLen'
296
// currName and bestName don't have to differ at position 'matchLen'
297

298             // determine the order and return true if currName is closer to newName
299
char newChar= getCharAt(this.newName, matchLen);
300             char currChar= getCharAt(currName, matchLen);
301             char bestChar= getCharAt(this.bestName, matchLen);
302
303             if (newChar < currChar) {
304                 if (bestChar < newChar) { // b < n < c
305
return (currChar - newChar) < (newChar - bestChar); // -> (c - n) < (n - b)
306
} else { // n < b && n < c
307
if (currChar == bestChar) { // longer match between curr and best
308
return false; // keep curr and best together, new should be before both
309
} else {
310                         return currChar < bestChar; // -> (c < b)
311
}
312                 }
313             } else {
314                 if (bestChar > newChar) { // c < n < b
315
return (newChar - currChar) < (bestChar - newChar); // -> (n - c) < (b - n)
316
} else { // n > b && n > c
317
if (currChar == bestChar) { // longer match between curr and best
318
return true; // keep curr and best together, new should be ahead of both
319
} else {
320                         return currChar > bestChar; // -> (c > b)
321
}
322                 }
323             }
324         }
325     }
326
327     /* package */ static int getCommonPrefixLength(String JavaDoc s, String JavaDoc t) {
328         int len= Math.min(s.length(), t.length());
329         for (int i= 0; i < len; i++) {
330             if (s.charAt(i) != t.charAt(i)) {
331                 return i;
332             }
333         }
334         return len;
335     }
336
337     /* package */ static char getCharAt(String JavaDoc str, int index) {
338         if (str.length() > index) {
339             return str.charAt(index);
340         }
341         return 0;
342     }
343     
344     private PackageEntry findBestMatch(String JavaDoc newName, boolean isStatic) {
345         if (this.packageEntries.isEmpty()) {
346             return null;
347         }
348         String JavaDoc groupId= null;
349         int longestPrefix= -1;
350         // find the matching group
351
for (int i= 0; i < this.packageEntries.size(); i++) {
352             PackageEntry curr= (PackageEntry) this.packageEntries.get(i);
353             if (isStatic == curr.isStatic()) {
354                 String JavaDoc currGroup= curr.getGroupID();
355                 if (currGroup != null && newName.startsWith(currGroup)) {
356                     int prefixLen= currGroup.length();
357                     if (prefixLen == newName.length()) {
358                         return curr; // perfect fit, use entry
359
}
360                     if ((newName.charAt(prefixLen) == '.') && prefixLen > longestPrefix) {
361                         longestPrefix= prefixLen;
362                         groupId= currGroup;
363                     }
364                 }
365             }
366         }
367         PackageEntry bestMatch= null;
368         PackageMatcher matcher= new PackageMatcher();
369         matcher.initialize(newName, ""); //$NON-NLS-1$
370
for (int i= 0; i < this.packageEntries.size(); i++) { // find the best match with the same group
371
PackageEntry curr= (PackageEntry) this.packageEntries.get(i);
372             if (!curr.isComment() && curr.isStatic() == isStatic) {
373                 if (groupId == null || groupId.equals(curr.getGroupID())) {
374                     boolean preferrCurr= (bestMatch == null) || (curr.getNumberOfImports() > bestMatch.getNumberOfImports());
375                     if (matcher.isBetterMatch(curr.getName(), preferrCurr)) {
376                         bestMatch= curr;
377                     }
378                 }
379             }
380         }
381         return bestMatch;
382     }
383         
384     private static boolean isImplicitImport(String JavaDoc qualifier, ICompilationUnit cu) {
385         if (JAVA_LANG.equals(qualifier)) {
386             return true;
387         }
388         String JavaDoc packageName= cu.getParent().getElementName();
389         if (qualifier.equals(packageName)) {
390             return true;
391         }
392         String JavaDoc mainTypeName= JavaCore.removeJavaLikeExtension(cu.getElementName());
393         if (packageName.length() == 0) {
394             return qualifier.equals(mainTypeName);
395         }
396         return qualifier.equals(packageName +'.' + mainTypeName);
397     }
398     
399     public void addImport(String JavaDoc fullTypeName, boolean isStatic) {
400         String JavaDoc typeContainerName= Signature.getQualifier(fullTypeName);
401         ImportDeclEntry decl= new ImportDeclEntry(fullTypeName, isStatic, null);
402         sortIn(typeContainerName, decl, isStatic);
403     }
404     
405     public boolean removeImport(String JavaDoc qualifiedName, boolean isStatic) {
406         String JavaDoc containerName= Signature.getQualifier(qualifiedName);
407         
408         int nPackages= this.packageEntries.size();
409         for (int i= 0; i < nPackages; i++) {
410             PackageEntry entry= (PackageEntry) this.packageEntries.get(i);
411             if (entry.compareTo(containerName, isStatic) == 0) {
412                 if (entry.remove(qualifiedName, isStatic)) {
413                     return true;
414                 }
415             }
416         }
417         return false;
418     }
419     
420     private int getIndexAfterStatics() {
421         for (int i= 0; i < this.packageEntries.size(); i++) {
422             if (!((PackageEntry) this.packageEntries.get(i)).isStatic()) {
423                 return i;
424             }
425         }
426         return this.packageEntries.size();
427     }
428     
429     
430     private void sortIn(String JavaDoc typeContainerName, ImportDeclEntry decl, boolean isStatic) {
431         PackageEntry bestMatch= findBestMatch(typeContainerName, isStatic);
432         if (bestMatch == null) {
433             PackageEntry packEntry= new PackageEntry(typeContainerName, null, isStatic);
434             packEntry.add(decl);
435             int insertPos= packEntry.isStatic() ? 0 : getIndexAfterStatics();
436             this.packageEntries.add(insertPos, packEntry);
437         } else {
438             int cmp= typeContainerName.compareTo(bestMatch.getName());
439             if (cmp == 0) {
440                 bestMatch.sortIn(decl);
441             } else {
442                 // create a new package entry
443
String JavaDoc group= bestMatch.getGroupID();
444                 if (group != null) {
445                     if (!typeContainerName.startsWith(group)) {
446                         group= null;
447                     }
448                 }
449                 PackageEntry packEntry= new PackageEntry(typeContainerName, group, isStatic);
450                 packEntry.add(decl);
451                 int index= this.packageEntries.indexOf(bestMatch);
452                 if (cmp < 0) { // insert ahead of best match
453
this.packageEntries.add(index, packEntry);
454                 } else { // insert after best match
455
this.packageEntries.add(index + 1, packEntry);
456                 }
457             }
458         }
459     }
460             
461     private IRegion evaluateReplaceRange(CompilationUnit root) {
462         List JavaDoc imports= root.imports();
463         if (!imports.isEmpty()) {
464             ImportDeclaration first= (ImportDeclaration) imports.get(0);
465             ImportDeclaration last= (ImportDeclaration) imports.get(imports.size() - 1);
466             
467             int startPos= first.getStartPosition(); // no extended range for first: bug 121428
468
int endPos= root.getExtendedStartPosition(last) + root.getExtendedLength(last);
469             int endLine= root.getLineNumber(endPos);
470             if (endLine > 0) {
471                 int nextLinePos= root.getPosition(endLine + 1, 0);
472                 if (nextLinePos >= 0) {
473                     int firstTypePos= getFirstTypeBeginPos(root);
474                     if (firstTypePos != -1 && firstTypePos < nextLinePos) {
475                         endPos= firstTypePos;
476                     } else {
477                         endPos= nextLinePos;
478                     }
479                 }
480             }
481             return new Region(startPos, endPos - startPos);
482         } else {
483             int start= getPackageStatementEndPos(root);
484             return new Region(start, 0);
485         }
486     }
487     
488     public MultiTextEdit getResultingEdits(IProgressMonitor monitor) throws JavaModelException {
489         if (monitor == null) {
490             monitor= new NullProgressMonitor();
491         }
492         try {
493             int importsStart= this.replaceRange.getOffset();
494             int importsLen= this.replaceRange.getLength();
495                     
496             String JavaDoc lineDelim= this.compilationUnit.findRecommendedLineSeparator();
497             IBuffer buffer= this.compilationUnit.getBuffer();
498                                     
499             int currPos= importsStart;
500             MultiTextEdit resEdit= new MultiTextEdit();
501             
502             if ((this.flags & F_NEEDS_LEADING_DELIM) != 0) {
503                 // new import container
504
resEdit.addChild(new InsertEdit(currPos, lineDelim));
505             }
506             
507             PackageEntry lastPackage= null;
508             
509             Set JavaDoc onDemandConflicts= null;
510             if (this.findAmbiguousImports) {
511                 onDemandConflicts= evaluateStarImportConflicts(monitor);
512             }
513             
514             int spacesBetweenGroups= getSpacesBetweenImportGroups();
515             
516             ArrayList JavaDoc stringsToInsert= new ArrayList JavaDoc();
517             
518             int nPackageEntries= this.packageEntries.size();
519             for (int i= 0; i < nPackageEntries; i++) {
520                 PackageEntry pack= (PackageEntry) this.packageEntries.get(i);
521                 int nImports= pack.getNumberOfImports();
522     
523                 if (this.filterImplicitImports && !pack.isStatic() && isImplicitImport(pack.getName(), this.compilationUnit)) {
524                     pack.removeAllNew(onDemandConflicts);
525                     nImports= pack.getNumberOfImports();
526                 }
527                 if (nImports == 0) {
528                     continue;
529                 }
530                 
531
532                 if (spacesBetweenGroups > 0) {
533                     // add a space between two different groups by looking at the two adjacent imports
534
if (lastPackage != null && !pack.isComment() && !pack.isSameGroup(lastPackage)) {
535                         ImportDeclEntry last= lastPackage.getImportAt(lastPackage.getNumberOfImports() - 1);
536                         ImportDeclEntry first= pack.getImportAt(0);
537                         if (!lastPackage.isComment() && (last.isNew() || first.isNew())) {
538                             for (int k= spacesBetweenGroups; k > 0; k--) {
539                                 stringsToInsert.add(lineDelim);
540                             }
541                         }
542                     }
543                 }
544                 lastPackage= pack;
545                 
546                 boolean isStatic= pack.isStatic();
547                 int threshold= isStatic ? staticImportOnDemandThreshold : importOnDemandThreshold;
548                 
549                 boolean doStarImport= pack.hasStarImport(threshold, onDemandConflicts);
550                 if (doStarImport && (pack.find("*") == null)) { //$NON-NLS-1$
551
String JavaDoc starImportString= pack.getName() + ".*"; //$NON-NLS-1$
552
String JavaDoc str= getNewImportString(starImportString, isStatic, lineDelim);
553                     stringsToInsert.add(str);
554                 }
555                 
556                 for (int k= 0; k < nImports; k++) {
557                     ImportDeclEntry currDecl= pack.getImportAt(k);
558                     IRegion region= currDecl.getSourceRange();
559                     
560                     if (region == null) { // new entry
561
if (!doStarImport || currDecl.isOnDemand() || (onDemandConflicts != null && onDemandConflicts.contains(currDecl.getSimpleName()))) {
562                             String JavaDoc str= getNewImportString(currDecl.getElementName(), isStatic, lineDelim);
563                             stringsToInsert.add(str);
564                         }
565                     } else {
566                         if (!doStarImport || currDecl.isOnDemand() || onDemandConflicts == null || onDemandConflicts.contains(currDecl.getSimpleName())) {
567                             int offset= region.getOffset();
568                             removeAndInsertNew(buffer, currPos, offset, stringsToInsert, resEdit);
569                             stringsToInsert.clear();
570                             currPos= offset + region.getLength();
571                         }
572                     }
573                 }
574             }
575             
576             int end= importsStart + importsLen;
577             removeAndInsertNew(buffer, currPos, end, stringsToInsert, resEdit);
578             
579             if (importsLen == 0) {
580                 if (!this.importsCreated.isEmpty() || !this.staticImportsCreated.isEmpty()) { // new import container
581
if ((this.flags & F_NEEDS_TRAILING_DELIM) != 0) {
582                         resEdit.addChild(new InsertEdit(currPos, lineDelim));
583                     }
584                 } else {
585                     return new MultiTextEdit(); // no changes
586
}
587             }
588             return resEdit;
589         } finally {
590             monitor.done();
591         }
592     }
593
594     private void removeAndInsertNew(IBuffer buffer, int contentOffset, int contentEnd, ArrayList JavaDoc stringsToInsert, MultiTextEdit resEdit) {
595         int pos= contentOffset;
596         for (int i= 0; i < stringsToInsert.size(); i++) {
597             String JavaDoc curr= (String JavaDoc) stringsToInsert.get(i);
598             int idx= findInBuffer(buffer, curr, pos, contentEnd);
599             if (idx != -1) {
600                 if (idx != pos) {
601                     resEdit.addChild(new DeleteEdit(pos, idx - pos));
602                 }
603                 pos= idx + curr.length();
604             } else {
605                 resEdit.addChild(new InsertEdit(pos, curr));
606             }
607         }
608         if (pos < contentEnd) {
609             resEdit.addChild(new DeleteEdit(pos, contentEnd - pos));
610         }
611     }
612
613     private int findInBuffer(IBuffer buffer, String JavaDoc str, int start, int end) {
614         int pos= start;
615         int len= str.length();
616         if (pos + len > end || str.length() == 0) {
617             return -1;
618         }
619         char first= str.charAt(0);
620         int step= str.indexOf(first, 1);
621         if (step == -1) {
622             step= len;
623         }
624         while (pos + len <= end) {
625             if (buffer.getChar(pos) == first) {
626                 int k= 1;
627                 while (k < len && buffer.getChar(pos + k) == str.charAt(k)) {
628                     k++;
629                 }
630                 if (k == len) {
631                     return pos; // found
632
}
633                 if (k < step) {
634                     pos+= k;
635                 } else {
636                     pos+= step;
637                 }
638             } else {
639                 pos++;
640             }
641         }
642         return -1;
643     }
644     
645     private Set JavaDoc evaluateStarImportConflicts(IProgressMonitor monitor) throws JavaModelException {
646         //long start= System.currentTimeMillis();
647

648         final HashSet JavaDoc/*String*/ onDemandConflicts= new HashSet JavaDoc();
649         
650         IJavaSearchScope scope= SearchEngine.createJavaSearchScope(new IJavaElement[] { this.compilationUnit.getJavaProject() });
651
652         ArrayList JavaDoc/*<char[][]>*/ starImportPackages= new ArrayList JavaDoc();
653         ArrayList JavaDoc/*<char[][]>*/ simpleTypeNames= new ArrayList JavaDoc();
654         int nPackageEntries= this.packageEntries.size();
655         for (int i= 0; i < nPackageEntries; i++) {
656             PackageEntry pack= (PackageEntry) this.packageEntries.get(i);
657             if (!pack.isStatic() && pack.hasStarImport(importOnDemandThreshold, null)) {
658                 starImportPackages.add(pack.getName().toCharArray());
659                 for (int k= 0; k < pack.getNumberOfImports(); k++) {
660                     ImportDeclEntry curr= pack.getImportAt(k);
661                     if (!curr.isOnDemand() && !curr.isComment()) {
662                         simpleTypeNames.add(curr.getSimpleName().toCharArray());
663                     }
664                 }
665             }
666         }
667         if (starImportPackages.isEmpty()) {
668             return null;
669         }
670         
671         starImportPackages.add(this.compilationUnit.getParent().getElementName().toCharArray());
672         starImportPackages.add(JAVA_LANG.toCharArray());
673         
674         char[][] allPackages= (char[][]) starImportPackages.toArray(new char[starImportPackages.size()][]);
675         char[][] allTypes= (char[][]) simpleTypeNames.toArray(new char[simpleTypeNames.size()][]);
676         
677         TypeNameRequestor requestor= new TypeNameRequestor() {
678             HashMap JavaDoc foundTypes= new HashMap JavaDoc();
679             
680             private String JavaDoc getTypeContainerName(char[] packageName, char[][] enclosingTypeNames) {
681                 StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
682                 buf.append(packageName);
683                 for (int i= 0; i < enclosingTypeNames.length; i++) {
684                     if (buf.length() > 0)
685                         buf.append('.');
686                     buf.append(enclosingTypeNames[i]);
687                 }
688                 return buf.toString();
689             }
690             
691             public void acceptType(int modifiers, char[] packageName, char[] simpleTypeName, char[][] enclosingTypeNames, String JavaDoc path) {
692                 String JavaDoc name= new String JavaDoc(simpleTypeName);
693                 String JavaDoc containerName= getTypeContainerName(packageName, enclosingTypeNames);
694                 
695                 String JavaDoc oldContainer= (String JavaDoc) this.foundTypes.put(name, containerName);
696                 if (oldContainer != null && !oldContainer.equals(containerName)) {
697                     onDemandConflicts.add(name);
698                 }
699             }
700         };
701         new SearchEngine().searchAllTypeNames(allPackages, allTypes, scope, requestor, IJavaSearchConstants.WAIT_UNTIL_READY_TO_SEARCH, monitor);
702         return onDemandConflicts;
703     }
704         
705     private String JavaDoc getNewImportString(String JavaDoc importName, boolean isStatic, String JavaDoc lineDelim) {
706         StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
707         buf.append("import "); //$NON-NLS-1$
708
if (isStatic) {
709             buf.append("static "); //$NON-NLS-1$
710
}
711         buf.append(importName);
712         buf.append(';');
713         buf.append(lineDelim);
714         
715         if (isStatic) {
716             this.staticImportsCreated.add(importName);
717         } else {
718             this.importsCreated.add(importName);
719         }
720         return buf.toString();
721     }
722     
723     private static int getFirstTypeBeginPos(CompilationUnit root) {
724         List JavaDoc types= root.types();
725         if (!types.isEmpty()) {
726             return root.getExtendedStartPosition(((ASTNode) types.get(0)));
727         }
728         return -1;
729     }
730     
731     private int getPackageStatementEndPos(CompilationUnit root) {
732         PackageDeclaration packDecl= root.getPackage();
733         if (packDecl != null) {
734             int lineAfterPackage= root.getLineNumber(packDecl.getStartPosition() + packDecl.getLength()) + 1;
735             int afterPackageStatementPos= root.getPosition(lineAfterPackage, 0);
736             if (afterPackageStatementPos >= 0) {
737                 int firstTypePos= getFirstTypeBeginPos(root);
738                 if (firstTypePos != -1 && firstTypePos <= afterPackageStatementPos) {
739                     if (firstTypePos <= afterPackageStatementPos) {
740                         this.flags |= F_NEEDS_TRAILING_DELIM;
741                         if (firstTypePos == afterPackageStatementPos) {
742                             this.flags |= F_NEEDS_LEADING_DELIM;
743                         }
744                         return firstTypePos;
745                     }
746                 }
747                 this.flags |= F_NEEDS_LEADING_DELIM;
748                 return afterPackageStatementPos; // insert a line after after package statement
749
}
750         }
751         this.flags |= F_NEEDS_TRAILING_DELIM;
752         return 0;
753     }
754     
755     public String JavaDoc toString() {
756         int nPackages= this.packageEntries.size();
757         StringBuffer JavaDoc buf= new StringBuffer JavaDoc("\n-----------------------\n"); //$NON-NLS-1$
758
for (int i= 0; i < nPackages; i++) {
759             PackageEntry entry= (PackageEntry) this.packageEntries.get(i);
760             if (entry.isStatic()) {
761                 buf.append("static "); //$NON-NLS-1$
762
}
763             buf.append(entry.toString());
764         }
765         return buf.toString();
766     }
767     
768     private static final class ImportDeclEntry {
769         
770         private String JavaDoc elementName;
771         private IRegion sourceRange;
772         private final boolean isStatic;
773         
774         public ImportDeclEntry(String JavaDoc elementName, boolean isStatic, IRegion sourceRange) {
775             this.elementName= elementName;
776             this.sourceRange= sourceRange;
777             this.isStatic= isStatic;
778         }
779                 
780         public String JavaDoc getElementName() {
781             return this.elementName;
782         }
783         
784         public int compareTo(String JavaDoc fullName, boolean isStaticImport) {
785             int cmp= this.elementName.compareTo(fullName);
786             if (cmp == 0) {
787                 if (this.isStatic == isStaticImport) {
788                     return 0;
789                 }
790                 return this.isStatic ? -1 : 1;
791             }
792             return cmp;
793         }
794         
795         public String JavaDoc getSimpleName() {
796             return Signature.getSimpleName(this.elementName);
797         }
798         
799         public boolean isOnDemand() {
800             return this.elementName != null && this.elementName.endsWith(".*"); //$NON-NLS-1$
801
}
802         
803         public boolean isStatic() {
804             return this.isStatic;
805         }
806             
807         public boolean isNew() {
808             return this.sourceRange == null;
809         }
810         
811         public boolean isComment() {
812             return this.elementName == null;
813         }
814         
815         public IRegion getSourceRange() {
816             return this.sourceRange;
817         }
818                 
819     }
820     
821     /*
822      * Internal element for the import structure: A container for imports
823      * of all types from the same package
824      */

825     private final static class PackageEntry {
826         
827         public static PackageEntry createOnPlaceholderEntry(String JavaDoc preferenceOrder) {
828             if (preferenceOrder.length() > 0 && preferenceOrder.charAt(0) == '#') {
829                 String JavaDoc curr= preferenceOrder.substring(1);
830                 return new PackageEntry(curr, curr, true);
831             }
832             return new PackageEntry(preferenceOrder, preferenceOrder, false);
833         }
834         
835         private String JavaDoc name;
836         private ArrayList JavaDoc importEntries;
837         private String JavaDoc group;
838         private boolean isStatic;
839     
840         /**
841          * Comment package entry
842          */

843         public PackageEntry() {
844             this("!", null, false); //$NON-NLS-1$
845
}
846         
847         /**
848          * @param name Name of the package entry. e.g. org.eclipse.jdt.ui, containing imports like
849          * org.eclipse.jdt.ui.JavaUI.
850          * @param group The index of the preference order entry assigned
851          * different group id's will result in spacers between the entries
852          */

853         public PackageEntry(String JavaDoc name, String JavaDoc group, boolean isStatic) {
854             this.name= name;
855             this.importEntries= new ArrayList JavaDoc(5);
856             this.group= group;
857             this.isStatic= isStatic;
858         }
859         
860         public boolean isStatic() {
861             return this.isStatic;
862         }
863         
864         public int compareTo(String JavaDoc otherName, boolean isOtherStatic) {
865             int cmp= this.name.compareTo(otherName);
866             if (cmp == 0) {
867                 if (this.isStatic == isOtherStatic) {
868                     return 0;
869                 }
870                 return this.isStatic ? -1 : 1;
871             }
872             return cmp;
873         }
874                         
875         public void sortIn(ImportDeclEntry imp) {
876             String JavaDoc fullImportName= imp.getElementName();
877             int insertPosition= -1;
878             int nInports= this.importEntries.size();
879             for (int i= 0; i < nInports; i++) {
880                 ImportDeclEntry curr= getImportAt(i);
881                 if (!curr.isComment()) {
882                     int cmp= curr.compareTo(fullImportName, imp.isStatic());
883                     if (cmp == 0) {
884                         return; // exists already
885
} else if (cmp > 0 && insertPosition == -1) {
886                         insertPosition= i;
887                     }
888                 }
889             }
890             if (insertPosition == -1) {
891                 this.importEntries.add(imp);
892             } else {
893                 this.importEntries.add(insertPosition, imp);
894             }
895         }
896         
897         
898         public void add(ImportDeclEntry imp) {
899             this.importEntries.add(imp);
900         }
901         
902         public ImportDeclEntry find(String JavaDoc simpleName) {
903             int nInports= this.importEntries.size();
904             for (int i= 0; i < nInports; i++) {
905                 ImportDeclEntry curr= getImportAt(i);
906                 if (!curr.isComment()) {
907                     String JavaDoc currName= curr.getElementName();
908                     if (currName.endsWith(simpleName)) {
909                         int dotPos= currName.length() - simpleName.length() - 1;
910                         if ((dotPos == -1) || (dotPos > 0 && currName.charAt(dotPos) == '.')) {
911                             return curr;
912                         }
913                     }
914                 }
915             }
916             return null;
917         }
918         
919         public boolean remove(String JavaDoc fullName, boolean isStaticImport) {
920             int nInports= this.importEntries.size();
921             for (int i= 0; i < nInports; i++) {
922                 ImportDeclEntry curr= getImportAt(i);
923                 if (!curr.isComment() && curr.compareTo(fullName, isStaticImport) == 0) {
924                     this.importEntries.remove(i);
925                     return true;
926                 }
927             }
928             return false;
929         }
930         
931         public void removeAllNew(Set JavaDoc onDemandConflicts) {
932             int nInports= this.importEntries.size();
933             for (int i= nInports - 1; i >= 0; i--) {
934                 ImportDeclEntry curr= getImportAt(i);
935                 if (curr.isNew() /*&& (onDemandConflicts == null || onDemandConflicts.contains(curr.getSimpleName()))*/) {
936                     this.importEntries.remove(i);
937                 }
938             }
939         }
940         
941         public ImportDeclEntry getImportAt(int index) {
942             return (ImportDeclEntry) this.importEntries.get(index);
943         }
944         
945         public boolean hasStarImport(int threshold, Set JavaDoc explicitImports) {
946             if (isComment() || isDefaultPackage()) { // can not star import default package
947
return false;
948             }
949             int nImports= getNumberOfImports();
950             int count= 0;
951             boolean containsNew= false;
952             for (int i= 0; i < nImports; i++) {
953                 ImportDeclEntry curr= getImportAt(i);
954                 if (curr.isOnDemand()) {
955                     return true;
956                 }
957                 if (!curr.isComment()) {
958                     count++;
959                     boolean isExplicit= !curr.isStatic() && (explicitImports != null) && explicitImports.contains(curr.getSimpleName());
960                     containsNew |= curr.isNew() && !isExplicit;
961                 }
962             }
963             return (count >= threshold) && containsNew;
964         }
965         
966         public int getNumberOfImports() {
967             return this.importEntries.size();
968         }
969             
970         public String JavaDoc getName() {
971             return this.name;
972         }
973         
974         public String JavaDoc getGroupID() {
975             return this.group;
976         }
977         
978         public void setGroupID(String JavaDoc groupID) {
979             this.group= groupID;
980         }
981         
982         public boolean isSameGroup(PackageEntry other) {
983             if (this.group == null) {
984                 return other.getGroupID() == null;
985             } else {
986                 return this.group.equals(other.getGroupID()) && (this.isStatic == other.isStatic());
987             }
988         }
989                 
990         public ImportDeclEntry getLast() {
991             int nImports= getNumberOfImports();
992             if (nImports > 0) {
993                 return getImportAt(nImports - 1);
994             }
995             return null;
996         }
997         
998         public boolean isComment() {
999             return "!".equals(this.name); //$NON-NLS-1$
1000
}
1001        
1002        public boolean isDefaultPackage() {
1003            return this.name.length() == 0;
1004        }
1005        
1006        public String JavaDoc toString() {
1007            StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
1008            if (isComment()) {
1009                buf.append("comment\n"); //$NON-NLS-1$
1010
} else {
1011                buf.append(this.name); buf.append(", groupId: "); buf.append(this.group); buf.append("\n"); //$NON-NLS-1$ //$NON-NLS-2$
1012
int nImports= getNumberOfImports();
1013                for (int i= 0; i < nImports; i++) {
1014                    ImportDeclEntry curr= getImportAt(i);
1015                    buf.append(" "); //$NON-NLS-1$
1016
if (curr.isStatic()) {
1017                        buf.append("static "); //$NON-NLS-1$
1018
}
1019                    buf.append(curr.getSimpleName());
1020                    if (curr.isNew()) {
1021                        buf.append(" (new)"); //$NON-NLS-1$
1022
}
1023                    buf.append("\n"); //$NON-NLS-1$
1024
}
1025            }
1026            return buf.toString();
1027        }
1028    }
1029    
1030    public String JavaDoc[] getCreatedImports() {
1031        return (String JavaDoc[]) this.importsCreated.toArray(new String JavaDoc[this.importsCreated.size()]);
1032    }
1033    
1034    public String JavaDoc[] getCreatedStaticImports() {
1035        return (String JavaDoc[]) this.staticImportsCreated.toArray(new String JavaDoc[this.staticImportsCreated.size()]);
1036    }
1037    
1038}
1039
Popular Tags