1 11 package org.eclipse.jdt.internal.corext.fix; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Hashtable ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 20 import org.eclipse.text.edits.MultiTextEdit; 21 import org.eclipse.text.edits.TextEdit; 22 import org.eclipse.text.edits.TextEditGroup; 23 import org.eclipse.text.edits.TextEditVisitor; 24 import org.eclipse.text.edits.UndoEdit; 25 26 import org.eclipse.core.runtime.CoreException; 27 import org.eclipse.core.runtime.IProgressMonitor; 28 import org.eclipse.core.runtime.NullProgressMonitor; 29 import org.eclipse.core.runtime.OperationCanceledException; 30 import org.eclipse.core.runtime.SubProgressMonitor; 31 import org.eclipse.core.runtime.jobs.ISchedulingRule; 32 33 import org.eclipse.core.resources.IFile; 34 import org.eclipse.core.resources.ProjectScope; 35 import org.eclipse.core.resources.ResourcesPlugin; 36 37 import org.eclipse.ltk.core.refactoring.CategorizedTextEditGroup; 38 import org.eclipse.ltk.core.refactoring.Change; 39 import org.eclipse.ltk.core.refactoring.CompositeChange; 40 import org.eclipse.ltk.core.refactoring.ContentStamp; 41 import org.eclipse.ltk.core.refactoring.GroupCategory; 42 import org.eclipse.ltk.core.refactoring.GroupCategorySet; 43 import org.eclipse.ltk.core.refactoring.NullChange; 44 import org.eclipse.ltk.core.refactoring.Refactoring; 45 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 46 import org.eclipse.ltk.core.refactoring.RefactoringTickProvider; 47 import org.eclipse.ltk.core.refactoring.TextChange; 48 import org.eclipse.ltk.core.refactoring.TextEditBasedChangeGroup; 49 import org.eclipse.ltk.core.refactoring.TextFileChange; 50 51 import org.eclipse.jdt.core.ICompilationUnit; 52 import org.eclipse.jdt.core.IJavaProject; 53 import org.eclipse.jdt.core.IPackageFragment; 54 import org.eclipse.jdt.core.JavaModelException; 55 import org.eclipse.jdt.core.WorkingCopyOwner; 56 import org.eclipse.jdt.core.dom.ASTParser; 57 import org.eclipse.jdt.core.dom.ASTRequestor; 58 import org.eclipse.jdt.core.dom.CompilationUnit; 59 60 import org.eclipse.jdt.internal.corext.refactoring.Checks; 61 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; 62 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange; 63 import org.eclipse.jdt.internal.corext.refactoring.changes.MultiStateCompilationUnitChange; 64 import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility; 65 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 66 import org.eclipse.jdt.internal.corext.util.Messages; 67 68 import org.eclipse.jdt.ui.JavaElementLabels; 69 70 import org.eclipse.jdt.internal.ui.JavaPlugin; 71 import org.eclipse.jdt.internal.ui.fix.CodeFormatCleanUp; 72 import org.eclipse.jdt.internal.ui.fix.CodeStyleCleanUp; 73 import org.eclipse.jdt.internal.ui.fix.CommentFormatCleanUp; 74 import org.eclipse.jdt.internal.ui.fix.ControlStatementsCleanUp; 75 import org.eclipse.jdt.internal.ui.fix.ConvertLoopCleanUp; 76 import org.eclipse.jdt.internal.ui.fix.ExpressionsCleanUp; 77 import org.eclipse.jdt.internal.ui.fix.ICleanUp; 78 import org.eclipse.jdt.internal.ui.fix.ImportsCleanUp; 79 import org.eclipse.jdt.internal.ui.fix.Java50CleanUp; 80 import org.eclipse.jdt.internal.ui.fix.PotentialProgrammingProblemsCleanUp; 81 import org.eclipse.jdt.internal.ui.fix.SortMembersCleanUp; 82 import org.eclipse.jdt.internal.ui.fix.StringCleanUp; 83 import org.eclipse.jdt.internal.ui.fix.UnnecessaryCodeCleanUp; 84 import org.eclipse.jdt.internal.ui.fix.UnusedCodeCleanUp; 85 import org.eclipse.jdt.internal.ui.fix.VariableDeclarationCleanUp; 86 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; 87 import org.eclipse.jdt.internal.ui.refactoring.IScheduledRefactoring; 88 89 public class CleanUpRefactoring extends Refactoring implements IScheduledRefactoring { 90 91 public static class CleanUpChange extends CompilationUnitChange { 92 93 private UndoEdit fUndoEdit; 94 95 public CleanUpChange(String name, ICompilationUnit cunit) { 96 super(name, cunit); 97 } 98 99 102 protected Change createUndoChange(UndoEdit edit, ContentStamp stampToRestore) { 103 fUndoEdit= edit; 104 return super.createUndoChange(edit, stampToRestore); 105 } 106 107 public UndoEdit getUndoEdit() { 108 return fUndoEdit; 109 } 110 } 111 112 private static class FixCalculationException extends RuntimeException { 113 114 private static final long serialVersionUID= 3807273310144726165L; 115 116 private final CoreException fException; 117 118 public FixCalculationException(CoreException exception) { 119 fException= exception; 120 } 121 122 public CoreException getException() { 123 return fException; 124 } 125 } 126 127 private static class ParseListElement { 128 129 private final ICompilationUnit fUnit; 130 private final ICleanUp[] fCleanUpsArray; 131 132 public ParseListElement(ICompilationUnit unit) { 133 fUnit= unit; 134 fCleanUpsArray= new ICleanUp[0]; 135 } 136 137 public ParseListElement(ICompilationUnit unit, ICleanUp[] cleanUps) { 138 fUnit= unit; 139 fCleanUpsArray= cleanUps; 140 } 141 142 public ICompilationUnit getCompilationUnit() { 143 return fUnit; 144 } 145 146 public ICleanUp[] getCleanUps() { 147 return fCleanUpsArray; 148 } 149 } 150 151 private final class CleanUpRefactoringProgressMonitor extends SubProgressMonitor { 152 153 private double fRealWork; 154 private int fFlushCount; 155 private final int fSize; 156 private final int fIndex; 157 158 private CleanUpRefactoringProgressMonitor(IProgressMonitor monitor, int ticks, int size, int index) { 159 super(monitor, ticks); 160 fFlushCount= 0; 161 fSize= size; 162 fIndex= index; 163 } 164 165 168 public void internalWorked(double work) { 169 fRealWork+= work; 170 } 171 172 public void flush() { 173 super.internalWorked(fRealWork); 174 reset(); 175 fFlushCount++; 176 } 177 178 public void reset() { 179 fRealWork= 0.0; 180 } 181 182 public void done() {} 183 184 public int getIndex() { 185 return fIndex + fFlushCount; 186 } 187 188 public String getSubTaskMessage(ICompilationUnit source) { 189 String typeName= source.getElementName(); 190 return Messages.format(FixMessages.CleanUpRefactoring_ProcessingCompilationUnit_message, new Object [] {new Integer (getIndex()), new Integer (fSize), typeName}); 191 } 192 } 193 194 private static class CleanUpASTRequestor extends ASTRequestor { 195 196 private final List fUndoneElements; 197 private final Hashtable fSolutions; 198 private final Hashtable fCompilationUnitCleanUpMap; 199 private final CleanUpRefactoringProgressMonitor fMonitor; 200 201 public CleanUpASTRequestor(List parseList, Hashtable solutions, CleanUpRefactoringProgressMonitor monitor) { 202 fSolutions= solutions; 203 fMonitor= monitor; 204 fUndoneElements= new ArrayList (); 205 fCompilationUnitCleanUpMap= new Hashtable (parseList.size()); 206 for (Iterator iter= parseList.iterator(); iter.hasNext();) { 207 ParseListElement element= (ParseListElement)iter.next(); 208 fCompilationUnitCleanUpMap.put(element.getCompilationUnit(), element.getCleanUps()); 209 } 210 } 211 212 215 public void acceptAST(ICompilationUnit source, CompilationUnit ast) { 216 217 fMonitor.subTask(fMonitor.getSubTaskMessage(source)); 218 219 ICompilationUnit primary= (ICompilationUnit)source.getPrimaryElement(); 220 ICleanUp[] cleanUps= (ICleanUp[])fCompilationUnitCleanUpMap.get(primary); 221 222 ICleanUp[] rejectedCleanUps= calculateSolutions(source, ast, cleanUps); 223 224 if (rejectedCleanUps.length > 0) { 225 fUndoneElements.add(new ParseListElement(primary, rejectedCleanUps)); 226 fMonitor.reset(); 227 } else { 228 fMonitor.flush(); 229 } 230 } 231 232 public void acceptSource(ICompilationUnit source) { 233 acceptAST(source, null); 234 } 235 236 public List getUndoneElements() { 237 return fUndoneElements; 238 } 239 240 private ICleanUp[] calculateSolutions(ICompilationUnit source, CompilationUnit ast, ICleanUp[] cleanUps) { 241 List result= new ArrayList (); 242 CleanUpChange solution; 243 try { 244 solution= calculateChange(ast, source, cleanUps, result); 245 } catch (CoreException e) { 246 throw new FixCalculationException(e); 247 } 248 249 if (solution != null) { 250 try { 251 integrateSolution(solution, source); 252 } catch (JavaModelException e) { 253 throw new FixCalculationException(e); 254 } 255 } 256 257 return (ICleanUp[])result.toArray(new ICleanUp[result.size()]); 258 } 259 260 private void integrateSolution(CleanUpChange solution, ICompilationUnit source) throws JavaModelException { 261 ICompilationUnit primary= source.getPrimary(); 262 263 List changes= (List )fSolutions.get(primary); 264 if (changes == null) { 265 changes= new ArrayList (); 266 fSolutions.put(primary, changes); 267 } 268 changes.add(solution); 269 } 270 } 271 272 private static abstract class CleanUpParser { 273 274 private static final int MAX_AT_ONCE; 275 static { 276 long maxMemory= Runtime.getRuntime().maxMemory(); 277 int ratio= (int)Math.round((double)maxMemory / (64 * 0x100000)); 278 switch (ratio) { 279 case 0: 280 MAX_AT_ONCE= 25; 281 break; 282 case 1: 283 MAX_AT_ONCE= 100; 284 break; 285 case 2: 286 MAX_AT_ONCE= 200; 287 break; 288 case 3: 289 MAX_AT_ONCE= 300; 290 break; 291 case 4: 292 MAX_AT_ONCE= 400; 293 break; 294 default: 295 MAX_AT_ONCE= 500; 296 break; 297 } 298 } 299 300 public void createASTs(ICompilationUnit[] units, String [] bindingKeys, CleanUpASTRequestor requestor, IProgressMonitor monitor) { 301 if (monitor == null) 302 monitor= new NullProgressMonitor(); 303 304 try { 305 monitor.beginTask("", units.length); 307 List list= Arrays.asList(units); 308 int end= 0; 309 int cursor= 0; 310 while (cursor < units.length) { 311 end= Math.min(end + MAX_AT_ONCE, units.length); 312 List toParse= list.subList(cursor, end); 313 314 createParser().createASTs((ICompilationUnit[])toParse.toArray(new ICompilationUnit[toParse.size()]), bindingKeys, requestor, new SubProgressMonitor(monitor, toParse.size())); 315 cursor= end; 316 } 317 } finally { 318 monitor.done(); 319 } 320 } 321 322 protected abstract ASTParser createParser(); 323 } 324 325 private class CleanUpFixpointIterator { 326 327 private List fParseList; 328 private final Hashtable fSolutions; 329 private final Hashtable fWorkingCopies; 330 private final IJavaProject fProject; 331 private final Map fCleanUpOptions; 332 private final int fSize; 333 private int fIndex; 334 335 public CleanUpFixpointIterator(IJavaProject project, ICompilationUnit[] units, ICleanUp[] cleanUps) { 336 fProject= project; 337 fSolutions= new Hashtable (units.length); 338 fWorkingCopies= new Hashtable (); 339 340 fParseList= new ArrayList (units.length); 341 for (int i= 0; i < units.length; i++) { 342 fParseList.add(new ParseListElement(units[i], cleanUps)); 343 } 344 345 fCleanUpOptions= new Hashtable (); 346 for (int i= 0; i < cleanUps.length; i++) { 347 ICleanUp cleanUp= cleanUps[i]; 348 Map currentCleanUpOption= cleanUp.getRequiredOptions(); 349 if (currentCleanUpOption != null) 350 fCleanUpOptions.putAll(currentCleanUpOption); 351 } 352 353 fSize= units.length; 354 fIndex= 1; 355 } 356 357 public boolean hasNext() { 358 return !fParseList.isEmpty(); 359 } 360 361 public void next(IProgressMonitor monitor) throws CoreException { 362 List parseList= new ArrayList (); 363 List sourceList= new ArrayList (); 364 365 try { 366 for (Iterator iter= fParseList.iterator(); iter.hasNext();) { 367 ParseListElement element= (ParseListElement)iter.next(); 368 369 ICompilationUnit compilationUnit= element.getCompilationUnit(); 370 if (fSolutions.containsKey(compilationUnit)) { 371 if (fWorkingCopies.containsKey(compilationUnit)) { 372 compilationUnit= (ICompilationUnit)fWorkingCopies.get(compilationUnit); 373 } else { 374 compilationUnit= compilationUnit.getWorkingCopy(new WorkingCopyOwner() {}, null); 375 fWorkingCopies.put(compilationUnit.getPrimary(), compilationUnit); 376 } 377 applyChange(compilationUnit, (List )fSolutions.get(compilationUnit.getPrimary())); 378 } 379 380 if (requiresAST(compilationUnit, element.getCleanUps())) { 381 parseList.add(compilationUnit); 382 } else { 383 sourceList.add(compilationUnit); 384 } 385 } 386 387 CleanUpRefactoringProgressMonitor cuMonitor= new CleanUpRefactoringProgressMonitor(monitor, parseList.size() + sourceList.size(), fSize, fIndex); 388 CleanUpASTRequestor requestor= new CleanUpASTRequestor(fParseList, fSolutions, cuMonitor); 389 CleanUpParser parser= new CleanUpParser() { 390 protected ASTParser createParser() { 391 ASTParser result= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL); 392 result.setResolveBindings(true); 393 result.setProject(fProject); 394 395 Map options= RefactoringASTParser.getCompilerOptions(fProject); 396 options.putAll(fCleanUpOptions); 397 result.setCompilerOptions(options); 398 return result; 399 } 400 }; 401 try { 402 ICompilationUnit[] units= (ICompilationUnit[])parseList.toArray(new ICompilationUnit[parseList.size()]); 403 parser.createASTs(units, new String [0], requestor, cuMonitor); 404 } catch (FixCalculationException e) { 405 throw e.getException(); 406 } 407 408 for (Iterator iterator= sourceList.iterator(); iterator.hasNext();) { 409 ICompilationUnit cu= (ICompilationUnit)iterator.next(); 410 requestor.acceptSource(cu); 411 } 412 413 fParseList= requestor.getUndoneElements(); 414 fIndex= cuMonitor.getIndex(); 415 } finally { 416 } 417 } 418 419 public void dispose() { 420 for (Iterator iterator= fWorkingCopies.values().iterator(); iterator.hasNext();) { 421 ICompilationUnit cu= (ICompilationUnit)iterator.next(); 422 try { 423 cu.discardWorkingCopy(); 424 } catch (JavaModelException e) { 425 JavaPlugin.log(e); 426 } 427 } 428 } 429 430 private boolean requiresAST(ICompilationUnit compilationUnit, ICleanUp[] cleanUps) throws CoreException { 431 for (int i= 0; i < cleanUps.length; i++) { 432 if (cleanUps[i].requireAST(compilationUnit)) 433 return true; 434 } 435 return false; 436 } 437 438 public Change[] getResult() { 439 440 Change[] result= new Change[fSolutions.size()]; 441 int i=0; 442 for (Iterator iterator= fSolutions.entrySet().iterator(); iterator.hasNext();) { 443 Map.Entry entry= (Map.Entry )iterator.next(); 444 445 List changes= (List )entry.getValue(); 446 ICompilationUnit unit= (ICompilationUnit)entry.getKey(); 447 448 int saveMode; 449 try { 450 if (fLeaveFilesDirty || unit.getBuffer().hasUnsavedChanges()) { 451 saveMode= TextFileChange.LEAVE_DIRTY; 452 } else { 453 saveMode= TextFileChange.FORCE_SAVE; 454 } 455 } catch (JavaModelException e) { 456 saveMode= TextFileChange.LEAVE_DIRTY; 457 JavaPlugin.log(e); 458 } 459 460 if (changes.size() == 1) { 461 CleanUpChange change= (CleanUpChange)changes.get(0); 462 change.setSaveMode(saveMode); 463 result[i]= change; 464 } else { 465 MultiStateCompilationUnitChange mscuc= new MultiStateCompilationUnitChange(getChangeName(unit), unit); 466 for (int j= 0; j < changes.size(); j++) { 467 mscuc.addChange(createGroupFreeChange((CleanUpChange)changes.get(j))); 468 } 469 mscuc.setSaveMode(saveMode); 470 result[i]= mscuc; 471 } 472 473 i++; 474 } 475 476 return result; 477 } 478 479 private TextChange createGroupFreeChange(CleanUpChange change) { 480 CleanUpChange result= new CleanUpChange(change.getName(), change.getCompilationUnit()); 481 result.setEdit(change.getEdit()); 482 result.setSaveMode(change.getSaveMode()); 483 return result; 484 } 485 486 private void applyChange(ICompilationUnit compilationUnit, List changes) throws JavaModelException, CoreException { 487 if (changes.size() == 1) { 488 CleanUpChange change= (CleanUpChange)changes.get(changes.size() - 1); 489 compilationUnit.getBuffer().setContents(change.getPreviewContent(null)); 490 } else { 491 MultiStateCompilationUnitChange mscuc= new MultiStateCompilationUnitChange("", compilationUnit.getPrimary()); for (int i= 0; i < changes.size(); i++) { 493 mscuc.addChange((CleanUpChange)changes.get(i)); 494 } 495 compilationUnit.getBuffer().setContents(mscuc.getPreviewContent(null)); 496 } 497 } 498 } 499 500 private static final RefactoringTickProvider CLEAN_UP_REFACTORING_TICK_PROVIDER= new RefactoringTickProvider(0, 1, 0, 0); 501 502 private final List fCleanUps; 503 private final Hashtable fProjects; 504 private Change fChange; 505 private boolean fLeaveFilesDirty; 506 private final String fName; 507 508 public CleanUpRefactoring() { 509 this(FixMessages.CleanUpRefactoring_Refactoring_name); 510 } 511 512 public CleanUpRefactoring(String name) { 513 fName= name; 514 fCleanUps= new ArrayList (); 515 fProjects= new Hashtable (); 516 } 517 518 public void addCompilationUnit(ICompilationUnit unit) { 519 IJavaProject javaProject= unit.getJavaProject(); 520 if (!fProjects.containsKey(javaProject)) 521 fProjects.put(javaProject, new ArrayList ()); 522 523 List cus= (List )fProjects.get(javaProject); 524 cus.add(unit); 525 } 526 527 public void clearCompilationUnits() { 528 fProjects.clear(); 529 } 530 531 public boolean hasCompilationUnits() { 532 return !fProjects.isEmpty(); 533 } 534 535 public ICompilationUnit[] getCompilationUnits() { 536 List cus= new ArrayList (); 537 for (Iterator iter= fProjects.values().iterator(); iter.hasNext();) { 538 List pcus= (List )iter.next(); 539 cus.addAll(pcus); 540 } 541 return (ICompilationUnit[])cus.toArray(new ICompilationUnit[cus.size()]); 542 } 543 544 public void addCleanUp(ICleanUp fix) { 545 fCleanUps.add(fix); 546 } 547 548 public void clearCleanUps() { 549 fCleanUps.clear(); 550 } 551 552 public boolean hasCleanUps() { 553 return !fCleanUps.isEmpty(); 554 } 555 556 public ICleanUp[] getCleanUps() { 557 return (ICleanUp[])fCleanUps.toArray(new ICleanUp[fCleanUps.size()]); 558 } 559 560 public IJavaProject[] getProjects() { 561 return (IJavaProject[])fProjects.keySet().toArray(new IJavaProject[fProjects.keySet().size()]); 562 } 563 564 public void setLeaveFilesDirty(boolean leaveFilesDirty) { 565 fLeaveFilesDirty= leaveFilesDirty; 566 } 567 568 571 public String getName() { 572 return fName; 573 } 574 575 578 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { 579 if (pm != null) { 580 pm.beginTask("", 1); pm.worked(1); 582 pm.done(); 583 } 584 return new RefactoringStatus(); 585 } 586 587 590 public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { 591 if (pm != null) { 592 pm.beginTask("", 1); pm.worked(1); 594 pm.done(); 595 } 596 return fChange; 597 } 598 599 602 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { 603 604 if (pm == null) 605 pm= new NullProgressMonitor(); 606 607 if (fProjects.size() == 0 || fCleanUps.size() == 0) { 608 pm.beginTask("", 1); pm.worked(1); 610 pm.done(); 611 fChange= new NullChange(); 612 613 return new RefactoringStatus(); 614 } 615 616 int cuCount= 0; 617 for (Iterator iter= fProjects.keySet().iterator(); iter.hasNext();) { 618 IJavaProject project= (IJavaProject)iter.next(); 619 cuCount+= ((List )fProjects.get(project)).size(); 620 } 621 622 RefactoringStatus result= new RefactoringStatus(); 623 624 pm.beginTask("", cuCount * 2 * fCleanUps.size() + 4 * fCleanUps.size()); try { 626 DynamicValidationStateChange change= new DynamicValidationStateChange(getName()); 627 change.setSchedulingRule(getSchedulingRule()); 628 for (Iterator projectIter= fProjects.keySet().iterator(); projectIter.hasNext();) { 629 IJavaProject project= (IJavaProject)projectIter.next(); 630 631 List compilationUnits= (List )fProjects.get(project); 632 ICompilationUnit[] cus= (ICompilationUnit[])compilationUnits.toArray(new ICompilationUnit[compilationUnits.size()]); 633 634 ICleanUp[] cleanUps= (ICleanUp[])fCleanUps.toArray(new ICleanUp[fCleanUps.size()]); 635 result.merge(initialize(project)); 636 if (result.hasFatalError()) 637 return result; 638 639 result.merge(checkPreConditions(project, cus, new SubProgressMonitor(pm, 3 * cleanUps.length))); 640 if (result.hasFatalError()) 641 return result; 642 643 Change[] changes= cleanUpProject(project, cus, cleanUps, pm); 644 645 result.merge(checkPostConditions(new SubProgressMonitor(pm, cleanUps.length))); 646 if (result.hasFatalError()) 647 return result; 648 649 for (int i= 0; i < changes.length; i++) { 650 change.add(changes[i]); 651 } 652 } 653 fChange= change; 654 655 List files= new ArrayList (); 656 findFilesToBeModified(change, files); 657 result.merge(Checks.validateModifiesFiles((IFile[])files.toArray(new IFile[files.size()]), getValidationContext())); 658 if (result.hasFatalError()) 659 return result; 660 } finally { 661 pm.done(); 662 } 663 664 return result; 665 } 666 667 private void findFilesToBeModified(CompositeChange change, List result) throws JavaModelException { 668 Change[] children= change.getChildren(); 669 for (int i= 0; i < children.length; i++) { 670 Change child= children[i]; 671 if (child instanceof CompositeChange) { 672 findFilesToBeModified((CompositeChange)child, result); 673 } else if (child instanceof MultiStateCompilationUnitChange) { 674 result.add(((MultiStateCompilationUnitChange)child).getCompilationUnit().getCorrespondingResource()); 675 } else if (child instanceof CompilationUnitChange) { 676 result.add(((CompilationUnitChange)child).getCompilationUnit().getCorrespondingResource()); 677 } 678 } 679 } 680 681 private Change[] cleanUpProject(IJavaProject project, ICompilationUnit[] compilationUnits, ICleanUp[] cleanUps, IProgressMonitor monitor) throws CoreException { 682 CleanUpFixpointIterator iter= new CleanUpFixpointIterator(project, compilationUnits, cleanUps); 683 684 SubProgressMonitor subMonitor= new SubProgressMonitor(monitor, 2 * compilationUnits.length * cleanUps.length); 685 subMonitor.beginTask("", compilationUnits.length); subMonitor.subTask(Messages.format(FixMessages.CleanUpRefactoring_Parser_Startup_message, project.getElementName())); 687 try { 688 while (iter.hasNext()) { 689 iter.next(subMonitor); 690 } 691 692 return iter.getResult(); 693 } finally { 694 iter.dispose(); 695 subMonitor.done(); 696 } 697 } 698 699 private RefactoringStatus initialize(IJavaProject javaProject) throws CoreException { 700 Map options= CleanUpPreferenceUtil.loadOptions(new ProjectScope(javaProject.getProject())); 701 if (options == null) { 702 return RefactoringStatus.createFatalErrorStatus(Messages.format(FixMessages.CleanUpRefactoring_could_not_retrive_profile, javaProject.getElementName())); 703 } 704 705 ICleanUp[] cleanUps= getCleanUps(); 706 for (int j= 0; j < cleanUps.length; j++) { 707 cleanUps[j].initialize(options); 708 } 709 710 return new RefactoringStatus(); 711 } 712 713 private RefactoringStatus checkPreConditions(IJavaProject javaProject, ICompilationUnit[] compilationUnits, IProgressMonitor monitor) throws CoreException { 714 RefactoringStatus result= new RefactoringStatus(); 715 716 ICleanUp[] cleanUps= getCleanUps(); 717 monitor.beginTask("", compilationUnits.length * cleanUps.length); monitor.subTask(Messages.format(FixMessages.CleanUpRefactoring_Initialize_message, javaProject.getElementName())); 719 try { 720 for (int j= 0; j < cleanUps.length; j++) { 721 result.merge(cleanUps[j].checkPreConditions(javaProject, compilationUnits, new SubProgressMonitor(monitor, compilationUnits.length))); 722 if (result.hasFatalError()) 723 return result; 724 } 725 } finally { 726 monitor.done(); 727 } 728 729 return result; 730 } 731 732 private RefactoringStatus checkPostConditions(SubProgressMonitor monitor) throws CoreException { 733 RefactoringStatus result= new RefactoringStatus(); 734 735 ICleanUp[] cleanUps= getCleanUps(); 736 monitor.beginTask("", cleanUps.length); monitor.subTask(FixMessages.CleanUpRefactoring_checkingPostConditions_message); 738 try { 739 for (int j= 0; j < cleanUps.length; j++) { 740 result.merge(cleanUps[j].checkPostConditions(new SubProgressMonitor(monitor, 1))); 741 if (result.hasFatalError()) 742 return result; 743 } 744 } finally { 745 monitor.done(); 746 } 747 return result; 748 } 749 750 private static String getChangeName(ICompilationUnit compilationUnit) { 751 StringBuffer buf= new StringBuffer (); 752 JavaElementLabels.getCompilationUnitLabel(compilationUnit, JavaElementLabels.ALL_DEFAULT, buf); 753 buf.append(JavaElementLabels.CONCAT_STRING); 754 755 StringBuffer buf2= new StringBuffer (); 756 JavaElementLabels.getPackageFragmentLabel((IPackageFragment)compilationUnit.getParent(), JavaElementLabels.P_QUALIFIED, buf2); 757 buf.append(buf2.toString().replace('.', '/')); 758 759 return buf.toString(); 760 } 761 762 public static CleanUpChange calculateChange(CompilationUnit ast, ICompilationUnit source, ICleanUp[] cleanUps, List undoneCleanUps) throws CoreException { 763 if (cleanUps.length == 0) 764 return null; 765 766 CleanUpChange solution= null; 767 int i= 0; 768 do { 769 ICleanUp cleanUp= cleanUps[i]; 770 IFix fix; 771 if (ast == null || !cleanUp.requireAST(source)) { 772 fix= cleanUp.createFix(source); 773 } else { 774 fix= cleanUp.createFix(ast); 775 } 776 if (fix != null) { 777 TextChange current= fix.createChange(); 778 TextEdit currentEdit= pack(current.getEdit()); 779 780 if (solution != null) { 781 if (intersects(currentEdit, solution.getEdit())) { 782 undoneCleanUps.add(cleanUp); 783 } else { 784 CleanUpChange merge= new CleanUpChange(FixMessages.CleanUpRefactoring_clean_up_multi_chang_name, source); 785 merge.setEdit(merge(currentEdit, solution.getEdit())); 786 787 copyChangeGroups(merge, solution); 788 copyChangeGroups(merge, current); 789 790 solution= merge; 791 } 792 } else { 793 solution= new CleanUpChange(current.getName(), source); 794 solution.setEdit(currentEdit); 795 796 copyChangeGroups(solution, current); 797 } 798 } 799 i++; 800 } while (i < cleanUps.length && (solution == null || ast != null && !cleanUps[i].needsFreshAST(ast))); 801 802 for (; i < cleanUps.length; i++) { 803 undoneCleanUps.add(cleanUps[i]); 804 } 805 return solution; 806 } 807 808 private static void copyChangeGroups(CompilationUnitChange target, TextChange source) { 809 TextEditBasedChangeGroup[] changeGroups= source.getChangeGroups(); 810 for (int i= 0; i < changeGroups.length; i++) { 811 TextEditGroup textEditGroup= changeGroups[i].getTextEditGroup(); 812 TextEditGroup newGroup; 813 if (textEditGroup instanceof CategorizedTextEditGroup) { 814 String label= textEditGroup.getName(); 815 newGroup= new CategorizedTextEditGroup(label, new GroupCategorySet(new GroupCategory(label, label, label))); 816 } else { 817 newGroup= new TextEditGroup(textEditGroup.getName()); 818 } 819 TextEdit[] textEdits= textEditGroup.getTextEdits(); 820 for (int j= 0; j < textEdits.length; j++) { 821 newGroup.addTextEdit(textEdits[j]); 822 } 823 target.addTextEditGroup(newGroup); 824 } 825 } 826 827 private static TextEdit pack(TextEdit edit) { 828 final List edits= new ArrayList (); 829 edit.accept(new TextEditVisitor() { 830 public boolean visitNode(TextEdit node) { 831 if (node instanceof MultiTextEdit) 832 return true; 833 834 edits.add(node); 835 return false; 836 } 837 }); 838 MultiTextEdit result= new MultiTextEdit(); 839 for (Iterator iterator= edits.iterator(); iterator.hasNext();) { 840 TextEdit child= (TextEdit)iterator.next(); 841 child.getParent().removeChild(child); 842 TextChangeCompatibility.insert(result, child); 843 } 844 return result; 845 } 846 847 private static boolean intersects(TextEdit edit1, TextEdit edit2) { 848 if (edit1 instanceof MultiTextEdit && edit2 instanceof MultiTextEdit) { 849 MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1; 850 TextEdit[] children1= multiTextEdit1.getChildren(); 851 852 MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2; 853 TextEdit[] children2= multiTextEdit2.getChildren(); 854 855 int i1= 0; 856 int i2= 0; 857 while (i1 < children1.length && i2 < children2.length) { 858 while (children1[i1].getExclusiveEnd() < children2[i2].getOffset()) { 859 i1++; 860 if (i1 >= children1.length) 861 return false; 862 } 863 while (children2[i2].getExclusiveEnd() < children1[i1].getOffset()) { 864 i2++; 865 if (i2 >= children2.length) 866 return false; 867 } 868 if (intersects(children1[i1], children2[i2])) 869 return true; 870 871 if (children1[i1].getExclusiveEnd() < children2[i2].getExclusiveEnd()) { 872 i1++; 873 } else { 874 i2++; 875 } 876 } 877 878 return false; 879 880 } else if (edit1 instanceof MultiTextEdit) { 881 MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1; 882 TextEdit[] children= multiTextEdit1.getChildren(); 883 for (int i= 0; i < children.length; i++) { 884 TextEdit child= children[i]; 885 if (intersects(child, edit2)) 886 return true; 887 } 888 return false; 889 890 } else if (edit2 instanceof MultiTextEdit) { 891 MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2; 892 TextEdit[] children= multiTextEdit2.getChildren(); 893 for (int i= 0; i < children.length; i++) { 894 TextEdit child= children[i]; 895 if (intersects(child, edit1)) 896 return true; 897 } 898 return false; 899 900 } else { 901 int start1= edit1.getOffset(); 902 int end1= start1 + edit1.getLength(); 903 int start2= edit2.getOffset(); 904 int end2= start2 + edit2.getLength(); 905 906 if (start1 > end2) 907 return false; 908 909 if (start2 > end1) 910 return false; 911 912 return true; 913 } 914 } 915 916 private static TextEdit merge(TextEdit edit1, TextEdit edit2) { 917 MultiTextEdit result= new MultiTextEdit(); 918 if (edit1 instanceof MultiTextEdit && edit2 instanceof MultiTextEdit) { 919 MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1; 920 TextEdit[] children1= multiTextEdit1.getChildren(); 921 922 if (children1.length == 0) 923 return edit2; 924 925 MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2; 926 TextEdit[] children2= multiTextEdit2.getChildren(); 927 928 if (children2.length == 0) 929 return edit1; 930 931 int i1= 0; 932 int i2= 0; 933 while (i1 < children1.length && i2 < children2.length) { 934 935 while (i1 < children1.length && children1[i1].getExclusiveEnd() < children2[i2].getOffset()) { 936 edit1.removeChild(0); 937 result.addChild(children1[i1]); 938 i1++; 939 } 940 if (i1 >= children1.length) { 941 for (int i= i2; i < children2.length; i++) { 942 edit2.removeChild(0); 943 result.addChild(children2[i]); 944 } 945 return result; 946 } 947 while (i2 < children2.length && children2[i2].getExclusiveEnd() < children1[i1].getOffset()) { 948 edit2.removeChild(0); 949 result.addChild(children2[i2]); 950 i2++; 951 } 952 if (i2 >= children2.length) { 953 for (int i= i1; i < children1.length; i++) { 954 edit1.removeChild(0); 955 result.addChild(children1[i]); 956 } 957 return result; 958 } 959 960 if (!(children1[i1].getExclusiveEnd() < children2[i2].getOffset())) { 961 edit1.removeChild(0); 962 edit2.removeChild(0); 963 result.addChild(merge(children1[i1], children2[i2])); 964 i1++; 965 i2++; 966 } 967 } 968 969 return result; 970 } else if (edit1 instanceof MultiTextEdit) { 971 TextEdit[] children= edit1.getChildren(); 972 973 int i= 0; 974 while (children[i].getExclusiveEnd() < edit2.getOffset()) { 975 edit1.removeChild(0); 976 result.addChild(children[i]); 977 i++; 978 if (i >= children.length) { 979 result.addChild(edit2); 980 return result; 981 } 982 } 983 edit1.removeChild(0); 984 result.addChild(merge(children[i], edit2)); 985 i++; 986 while (i < children.length) { 987 edit1.removeChild(0); 988 result.addChild(children[i]); 989 i++; 990 } 991 992 return result; 993 } else if (edit2 instanceof MultiTextEdit) { 994 TextEdit[] children= edit2.getChildren(); 995 996 int i= 0; 997 while (children[i].getExclusiveEnd() < edit1.getOffset()) { 998 edit2.removeChild(0); 999 result.addChild(children[i]); 1000 i++; 1001 if (i >= children.length) { 1002 result.addChild(edit1); 1003 return result; 1004 } 1005 } 1006 edit2.removeChild(0); 1007 result.addChild(merge(edit1, children[i])); 1008 i++; 1009 while (i < children.length) { 1010 edit2.removeChild(0); 1011 result.addChild(children[i]); 1012 i++; 1013 } 1014 1015 return result; 1016 } else { 1017 if (edit1.getExclusiveEnd() < edit2.getOffset()) { 1018 result.addChild(edit1); 1019 result.addChild(edit2); 1020 } else { 1021 result.addChild(edit2); 1022 result.addChild(edit1); 1023 } 1024 1025 return result; 1026 } 1027 } 1028 1029 1032 protected RefactoringTickProvider doGetRefactoringTickProvider() { 1033 return CLEAN_UP_REFACTORING_TICK_PROVIDER; 1034 } 1035 1036 1039 public ISchedulingRule getSchedulingRule() { 1040 return ResourcesPlugin.getWorkspace().getRoot(); 1041 } 1042 1043 public static ICleanUp[] createCleanUps() { 1044 return new ICleanUp[] { 1045 new CodeStyleCleanUp(), 1046 new ControlStatementsCleanUp(), 1047 new ConvertLoopCleanUp(), 1048 new VariableDeclarationCleanUp(), 1049 new ExpressionsCleanUp(), 1050 new UnusedCodeCleanUp(), 1051 new Java50CleanUp(), 1052 new PotentialProgrammingProblemsCleanUp(), 1053 new UnnecessaryCodeCleanUp(), 1054 new StringCleanUp(), 1055 new SortMembersCleanUp(), 1056 new ImportsCleanUp(), 1057 new CodeFormatCleanUp(), 1058 new CommentFormatCleanUp()}; 1059 } 1060 1061 public static ICleanUp[] createCleanUps(Map settings) { 1062 return new ICleanUp[] { 1063 new CodeStyleCleanUp(settings), 1064 new ControlStatementsCleanUp(settings), 1065 new ConvertLoopCleanUp(settings), 1066 new VariableDeclarationCleanUp(settings), 1067 new ExpressionsCleanUp(settings), 1068 new UnusedCodeCleanUp(settings), 1069 new Java50CleanUp(settings), 1070 new PotentialProgrammingProblemsCleanUp(settings), 1071 new UnnecessaryCodeCleanUp(settings), 1072 new StringCleanUp(settings), 1073 new SortMembersCleanUp(settings), 1074 new ImportsCleanUp(settings), 1075 new CodeFormatCleanUp(settings), 1076 new CommentFormatCleanUp(settings)}; 1077 } 1078} 1079 | Popular Tags |