1 11 package org.eclipse.jdt.internal.corext.refactoring.reorg; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.HashMap ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 20 import org.eclipse.text.edits.ReplaceEdit; 21 import org.eclipse.text.edits.TextEdit; 22 23 import org.eclipse.core.runtime.Assert; 24 import org.eclipse.core.runtime.CoreException; 25 import org.eclipse.core.runtime.IProgressMonitor; 26 import org.eclipse.core.runtime.OperationCanceledException; 27 import org.eclipse.core.runtime.SubProgressMonitor; 28 29 import org.eclipse.core.resources.IResource; 30 31 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 32 import org.eclipse.ltk.core.refactoring.TextChange; 33 34 import org.eclipse.jdt.core.Flags; 35 import org.eclipse.jdt.core.IBuffer; 36 import org.eclipse.jdt.core.ICompilationUnit; 37 import org.eclipse.jdt.core.IImportDeclaration; 38 import org.eclipse.jdt.core.IJavaElement; 39 import org.eclipse.jdt.core.IPackageFragment; 40 import org.eclipse.jdt.core.IType; 41 import org.eclipse.jdt.core.JavaModelException; 42 import org.eclipse.jdt.core.ToolFactory; 43 import org.eclipse.jdt.core.compiler.IScanner; 44 import org.eclipse.jdt.core.compiler.ITerminalSymbols; 45 import org.eclipse.jdt.core.compiler.InvalidInputException; 46 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 47 import org.eclipse.jdt.core.search.IJavaSearchConstants; 48 import org.eclipse.jdt.core.search.SearchEngine; 49 import org.eclipse.jdt.core.search.SearchMatch; 50 import org.eclipse.jdt.core.search.SearchPattern; 51 import org.eclipse.jdt.core.search.TypeReferenceMatch; 52 53 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 54 import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor; 55 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 56 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; 57 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine; 58 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; 59 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility; 60 import org.eclipse.jdt.internal.corext.refactoring.structure.ReferenceFinderUtil; 61 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager; 62 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 63 import org.eclipse.jdt.internal.corext.util.Messages; 64 import org.eclipse.jdt.internal.corext.util.SearchUtils; 65 66 import org.eclipse.jdt.internal.ui.JavaPlugin; 67 68 public class MoveCuUpdateCreator { 69 70 private final String fNewPackage; 71 private ICompilationUnit[] fCus; 72 private IPackageFragment fDestination; 73 74 private Map fImportRewrites; 76 public MoveCuUpdateCreator(ICompilationUnit cu, IPackageFragment pack){ 77 this(new ICompilationUnit[]{cu}, pack); 78 } 79 80 public MoveCuUpdateCreator(ICompilationUnit[] cus, IPackageFragment pack){ 81 Assert.isNotNull(cus); 82 Assert.isNotNull(pack); 83 fCus= cus; 84 fDestination= pack; 85 fImportRewrites= new HashMap (); 86 fNewPackage= fDestination.isDefaultPackage() ? "" : fDestination.getElementName() + '.'; } 88 89 public TextChangeManager createChangeManager(IProgressMonitor pm, RefactoringStatus status) throws JavaModelException{ 90 pm.beginTask("", 5); try{ 92 TextChangeManager changeManager= new TextChangeManager(); 93 addUpdates(changeManager, new SubProgressMonitor(pm, 4), status); 94 addImportRewriteUpdates(changeManager); 95 return changeManager; 96 } catch (JavaModelException e){ 97 throw e; 98 } catch (CoreException e){ 99 throw new JavaModelException(e); 100 } finally{ 101 pm.done(); 102 } 103 104 } 105 106 private void addImportRewriteUpdates(TextChangeManager changeManager) throws CoreException { 107 for (Iterator iter= fImportRewrites.keySet().iterator(); iter.hasNext();) { 108 ICompilationUnit cu= (ICompilationUnit) iter.next(); 109 ImportRewrite importRewrite= (ImportRewrite) fImportRewrites.get(cu); 110 if (importRewrite != null && importRewrite.hasRecordedChanges()) { 111 TextChangeCompatibility.addTextEdit(changeManager.get(cu), RefactoringCoreMessages.MoveCuUpdateCreator_update_imports, importRewrite.rewriteImports(null)); 112 } 113 } 114 } 115 116 private void addUpdates(TextChangeManager changeManager, IProgressMonitor pm, RefactoringStatus status) throws CoreException { 117 pm.beginTask("", fCus.length); for (int i= 0; i < fCus.length; i++){ 119 if (pm.isCanceled()) 120 throw new OperationCanceledException(); 121 122 addUpdates(changeManager, fCus[i], new SubProgressMonitor(pm, 1), status); 123 } 124 } 125 126 private void addUpdates(TextChangeManager changeManager, ICompilationUnit movedUnit, IProgressMonitor pm, RefactoringStatus status) throws CoreException{ 127 try{ 128 pm.beginTask("", 3); pm.subTask(Messages.format(RefactoringCoreMessages.MoveCuUpdateCreator_searching, movedUnit.getElementName())); 130 131 if (isInAnotherFragmentOfSamePackage(movedUnit, fDestination)){ 132 pm.worked(3); 133 return; 134 } 135 136 addImportToSourcePackageTypes(movedUnit, new SubProgressMonitor(pm, 1)); 137 removeImportsToDestinationPackageTypes(movedUnit); 138 addReferenceUpdates(changeManager, movedUnit, new SubProgressMonitor(pm, 2), status); 139 } finally{ 140 pm.done(); 141 } 142 } 143 144 private void addReferenceUpdates(TextChangeManager changeManager, ICompilationUnit movedUnit, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException, CoreException { 145 List cuList= Arrays.asList(fCus); 146 SearchResultGroup[] references= getReferences(movedUnit, pm, status); 147 for (int i= 0; i < references.length; i++) { 148 SearchResultGroup searchResultGroup= references[i]; 149 ICompilationUnit referencingCu= searchResultGroup.getCompilationUnit(); 150 if (referencingCu == null) 151 continue; 152 153 boolean simpleReferencesNeedNewImport= simpleReferencesNeedNewImport(movedUnit, referencingCu, cuList); 154 SearchMatch[] results= searchResultGroup.getSearchResults(); 155 for (int j= 0; j < results.length; j++) { 156 TypeReference reference= (TypeReference) results[j]; 158 if (reference.isImportDeclaration()) { 159 ImportRewrite rewrite= getImportRewrite(referencingCu); 160 IImportDeclaration importDecl= (IImportDeclaration) SearchUtils.getEnclosingJavaElement(results[j]); 161 if (Flags.isStatic(importDecl.getFlags())) { 162 rewrite.removeStaticImport(importDecl.getElementName()); 163 addStaticImport(movedUnit, importDecl, rewrite); 164 } else { 165 rewrite.removeImport(importDecl.getElementName()); 166 rewrite.addImport(createStringForNewImport(movedUnit, importDecl)); 167 } 168 } else if (reference.isQualified()) { 169 TextChange textChange= changeManager.get(referencingCu); 170 String changeName= RefactoringCoreMessages.MoveCuUpdateCreator_update_references; 171 TextEdit replaceEdit= new ReplaceEdit(reference.getOffset(), reference.getSimpleNameStart() - reference.getOffset(), fNewPackage); 172 TextChangeCompatibility.addTextEdit(textChange, changeName, replaceEdit); 173 } else if (simpleReferencesNeedNewImport) { 174 ImportRewrite importEdit= getImportRewrite(referencingCu); 175 String typeName= reference.getSimpleName(); 176 importEdit.addImport(getQualifiedType(fDestination.getElementName(), typeName)); 177 } 178 } 179 } 180 } 181 182 private void addStaticImport(ICompilationUnit movedUnit, IImportDeclaration importDecl, ImportRewrite rewrite) { 183 String old= importDecl.getElementName(); 184 int oldPackLength= movedUnit.getParent().getElementName().length(); 185 186 StringBuffer result= new StringBuffer (fDestination.getElementName()); 187 if (oldPackLength == 0) result.append('.').append(old); 189 else if (result.length() == 0) result.append(old.substring(oldPackLength + 1)); else 192 result.append(old.substring(oldPackLength)); 193 int index= result.lastIndexOf("."); if (index > 0 && index < result.length() - 1) 195 rewrite.addStaticImport(result.substring(0, index), result.substring(index + 1, result.length()), true); 196 } 197 198 private String getQualifiedType(String packageName, String typeName) { 199 if (packageName.length() == 0) 200 return typeName; 201 else 202 return packageName + '.' + typeName; 203 } 204 205 private String createStringForNewImport(ICompilationUnit movedUnit, IImportDeclaration importDecl) { 206 String old= importDecl.getElementName(); 207 int oldPackLength= movedUnit.getParent().getElementName().length(); 208 209 StringBuffer result= new StringBuffer (fDestination.getElementName()); 210 if (oldPackLength == 0) result.append('.').append(old); 212 else if (result.length() == 0) result.append(old.substring(oldPackLength + 1)); else 215 result.append(old.substring(oldPackLength)); 216 return result.toString(); 217 } 218 219 private void removeImportsToDestinationPackageTypes(ICompilationUnit movedUnit) throws CoreException{ 220 ImportRewrite importEdit= getImportRewrite(movedUnit); 221 IType[] destinationTypes= getDestinationPackageTypes(); 222 for (int i= 0; i < destinationTypes.length; i++) { 223 importEdit.removeImport(JavaModelUtil.getFullyQualifiedName(destinationTypes[i])); 224 } 225 } 226 227 private IType[] getDestinationPackageTypes() throws JavaModelException { 228 List types= new ArrayList (); 229 if (fDestination.exists()) { 230 ICompilationUnit[] cus= fDestination.getCompilationUnits(); 231 for (int i= 0; i < cus.length; i++) { 232 types.addAll(Arrays.asList(cus[i].getAllTypes())); 233 } 234 } 235 return (IType[]) types.toArray(new IType[types.size()]); 236 } 237 238 private void addImportToSourcePackageTypes(ICompilationUnit movedUnit, IProgressMonitor pm) throws CoreException{ 239 List cuList= Arrays.asList(fCus); 240 IType[] allCuTypes= movedUnit.getAllTypes(); 241 IType[] referencedTypes= ReferenceFinderUtil.getTypesReferencedIn(allCuTypes, pm); 242 ImportRewrite importEdit= getImportRewrite(movedUnit); 243 importEdit.setFilterImplicitImports(false); 244 IPackageFragment srcPack= (IPackageFragment)movedUnit.getParent(); 245 for (int i= 0; i < referencedTypes.length; i++) { 246 IType iType= referencedTypes[i]; 247 if (! iType.exists()) 248 continue; 249 if (! iType.getPackageFragment().equals(srcPack)) 250 continue; 251 if (cuList.contains(iType.getCompilationUnit())) 252 continue; 253 importEdit.addImport(JavaModelUtil.getFullyQualifiedName(iType)); 254 } 255 } 256 257 private ImportRewrite getImportRewrite(ICompilationUnit cu) throws CoreException{ 258 if (fImportRewrites.containsKey(cu)) 259 return (ImportRewrite)fImportRewrites.get(cu); 260 ImportRewrite importEdit= StubUtility.createImportRewrite(cu, true); 261 fImportRewrites.put(cu, importEdit); 262 return importEdit; 263 } 264 265 private boolean simpleReferencesNeedNewImport(ICompilationUnit movedUnit, ICompilationUnit referencingCu, List cuList) { 266 if (referencingCu.equals(movedUnit)) 267 return false; 268 if (cuList.contains(referencingCu)) 269 return false; 270 if (isReferenceInAnotherFragmentOfSamePackage(referencingCu, movedUnit)) { 271 273 return true; 274 } 275 276 if (referencingCu.getImport(movedUnit.getParent().getElementName() + ".*").exists()) return true; if (referencingCu.getParent().equals(movedUnit.getParent())) 280 return true; return false; 282 } 283 284 private boolean isReferenceInAnotherFragmentOfSamePackage(ICompilationUnit referencingCu, ICompilationUnit movedUnit) { 285 if (referencingCu == null) 286 return false; 287 if (! (referencingCu.getParent() instanceof IPackageFragment)) 288 return false; 289 IPackageFragment pack= (IPackageFragment) referencingCu.getParent(); 290 return isInAnotherFragmentOfSamePackage(movedUnit, pack); 291 } 292 293 private static boolean isInAnotherFragmentOfSamePackage(ICompilationUnit cu, IPackageFragment pack) { 294 if (! (cu.getParent() instanceof IPackageFragment)) 295 return false; 296 IPackageFragment cuPack= (IPackageFragment) cu.getParent(); 297 return ! cuPack.equals(pack) && JavaModelUtil.isSamePackage(cuPack, pack); 298 } 299 300 private static SearchResultGroup[] getReferences(ICompilationUnit unit, IProgressMonitor pm, RefactoringStatus status) throws CoreException { 301 final SearchPattern pattern= RefactoringSearchEngine.createOrPattern(unit.getTypes(), IJavaSearchConstants.REFERENCES); 302 if (pattern != null) 303 return RefactoringSearchEngine.search(pattern, RefactoringScopeFactory.create(unit), new Collector(((IPackageFragment) unit.getParent())), new SubProgressMonitor(pm, 1), status); 304 return new SearchResultGroup[] {}; 305 } 306 307 private final static class Collector extends CollectingSearchRequestor { 308 private IPackageFragment fSource; 309 private IScanner fScanner; 310 311 public Collector(IPackageFragment source) { 312 fSource= source; 313 fScanner= ToolFactory.createScanner(false, false, false, false); 314 } 315 316 319 public void acceptSearchMatch(SearchMatch match) throws CoreException { 320 324 IJavaElement element= SearchUtils.getEnclosingJavaElement(match); 326 int accuracy= match.getAccuracy(); 327 int start= match.getOffset(); 328 int length= match.getLength(); 329 boolean insideDocComment= match.isInsideDocComment(); 330 IResource res= match.getResource(); 331 if (element.getAncestor(IJavaElement.IMPORT_DECLARATION) != null) { 332 super.acceptSearchMatch(TypeReference.createImportReference(element, accuracy, start, length, insideDocComment, res)); 333 } else { 334 ICompilationUnit unit= (ICompilationUnit) element.getAncestor(IJavaElement.COMPILATION_UNIT); 335 if (unit != null) { 336 IBuffer buffer= unit.getBuffer(); 337 String matchText= buffer.getText(start, length); 338 if (fSource.isDefaultPackage()) { 339 super.acceptSearchMatch(TypeReference.createSimpleReference(element, accuracy, start, length, insideDocComment, res, matchText)); 340 } else { 341 int simpleNameStart= getLastSimpleNameStart(matchText); 343 if (simpleNameStart != 0) { 344 super.acceptSearchMatch(TypeReference.createQualifiedReference(element, accuracy, start, length, insideDocComment, res, start + simpleNameStart)); 345 } else { 346 super.acceptSearchMatch(TypeReference.createSimpleReference(element, accuracy, start, length, insideDocComment, res, matchText)); 347 } 348 } 349 } 350 } 351 } 352 353 private int getLastSimpleNameStart(String reference) { 354 fScanner.setSource(reference.toCharArray()); 355 int lastIdentifierStart= -1; 356 try { 357 int tokenType= fScanner.getNextToken(); 358 while (tokenType != ITerminalSymbols.TokenNameEOF) { 359 if (tokenType == ITerminalSymbols.TokenNameIdentifier) 360 lastIdentifierStart= fScanner.getCurrentTokenStartPosition(); 361 tokenType= fScanner.getNextToken(); 362 } 363 } catch (InvalidInputException e) { 364 JavaPlugin.log(e); 365 } 366 return lastIdentifierStart; 367 } 368 } 369 370 371 private final static class TypeReference extends TypeReferenceMatch { 372 private String fSimpleTypeName; 373 private int fSimpleNameStart; 374 375 private TypeReference(IJavaElement enclosingElement, int accuracy, int start, int length, 376 boolean insideDocComment, IResource resource, int simpleNameStart, String simpleName) { 377 super(enclosingElement, accuracy, start, length, 378 insideDocComment, SearchEngine.getDefaultSearchParticipant(), resource); 379 fSimpleNameStart= simpleNameStart; 380 fSimpleTypeName= simpleName; 381 } 382 383 public static TypeReference createQualifiedReference(IJavaElement enclosingElement, int accuracy, int start, int length, 384 boolean insideDocComment, IResource resource, int simpleNameStart) { 385 Assert.isTrue(start < simpleNameStart && simpleNameStart < start + length); 386 return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, simpleNameStart, null); 387 } 388 389 public static TypeReference createImportReference(IJavaElement enclosingElement, int accuracy, int start, int length, 390 boolean insideDocComment, IResource resource) { 391 return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, -1, null); 392 } 393 394 public static TypeReference createSimpleReference(IJavaElement enclosingElement, int accuracy, int start, int length, 395 boolean insideDocComment, IResource resource, String simpleName) { 396 return new TypeReference(enclosingElement, accuracy, start, length, insideDocComment, resource, -1, simpleName); 397 } 398 399 public boolean isImportDeclaration() { 400 return SearchUtils.getEnclosingJavaElement(this).getAncestor(IJavaElement.IMPORT_DECLARATION) != null; 401 } 402 403 public boolean isQualified() { 404 return fSimpleNameStart != -1; 405 } 406 407 public boolean isSimpleReference() { 408 return fSimpleTypeName != null; 409 } 410 411 414 public int getSimpleNameStart() { 415 return fSimpleNameStart; 416 } 417 418 421 public String getSimpleName() { 422 return fSimpleTypeName; 423 } 424 } 425 426 } 427 | Popular Tags |