KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > corext > fix > CleanUpRefactoring


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

11 package org.eclipse.jdt.internal.corext.fix;
12
13 import java.util.ArrayList JavaDoc;
14 import java.util.Arrays JavaDoc;
15 import java.util.Hashtable JavaDoc;
16 import java.util.Iterator JavaDoc;
17 import java.util.List JavaDoc;
18 import java.util.Map JavaDoc;
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 JavaDoc name, ICompilationUnit cunit) {
96             super(name, cunit);
97         }
98         
99         /**
100          * {@inheritDoc}
101          */

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 JavaDoc {
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         /**
166          * {@inheritDoc}
167          */

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 JavaDoc getSubTaskMessage(ICompilationUnit source) {
189             String JavaDoc typeName= source.getElementName();
190             return Messages.format(FixMessages.CleanUpRefactoring_ProcessingCompilationUnit_message, new Object JavaDoc[] {new Integer JavaDoc(getIndex()), new Integer JavaDoc(fSize), typeName});
191         }
192     }
193     
194     private static class CleanUpASTRequestor extends ASTRequestor {
195         
196         private final List JavaDoc/*<ParseListElement>*/fUndoneElements;
197         private final Hashtable JavaDoc/*<ICompilationUnit, Change>*/fSolutions;
198         private final Hashtable JavaDoc/*<ICompilationUnit, ICleanUp[]>*/fCompilationUnitCleanUpMap;
199         private final CleanUpRefactoringProgressMonitor fMonitor;
200         
201         public CleanUpASTRequestor(List JavaDoc parseList, Hashtable JavaDoc solutions, CleanUpRefactoringProgressMonitor monitor) {
202             fSolutions= solutions;
203             fMonitor= monitor;
204             fUndoneElements= new ArrayList JavaDoc();
205             fCompilationUnitCleanUpMap= new Hashtable JavaDoc(parseList.size());
206             for (Iterator JavaDoc iter= parseList.iterator(); iter.hasNext();) {
207                 ParseListElement element= (ParseListElement)iter.next();
208                 fCompilationUnitCleanUpMap.put(element.getCompilationUnit(), element.getCleanUps());
209             }
210         }
211         
212         /**
213          * {@inheritDoc}
214          */

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 JavaDoc getUndoneElements() {
237             return fUndoneElements;
238         }
239         
240         private ICleanUp[] calculateSolutions(ICompilationUnit source, CompilationUnit ast, ICleanUp[] cleanUps) {
241             List JavaDoc/*<ICleanUp>*/result= new ArrayList JavaDoc();
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 JavaDoc changes= (List JavaDoc)fSolutions.get(primary);
264             if (changes == null) {
265                 changes= new ArrayList JavaDoc();
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 JavaDoc[] bindingKeys, CleanUpASTRequestor requestor, IProgressMonitor monitor) {
301             if (monitor == null)
302                 monitor= new NullProgressMonitor();
303             
304             try {
305                 monitor.beginTask("", units.length); //$NON-NLS-1$
306

307                 List JavaDoc 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 JavaDoc 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 JavaDoc/*<ParseListElement>*/fParseList;
328         private final Hashtable JavaDoc/*<ICompilationUnit, List<CleanUpChange>>*/fSolutions;
329         private final Hashtable JavaDoc/*<ICompilationUnit (primary), ICompilationUnit (working copy)>*/fWorkingCopies;
330         private final IJavaProject fProject;
331         private final Map JavaDoc 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 JavaDoc(units.length);
338             fWorkingCopies= new Hashtable JavaDoc();
339             
340             fParseList= new ArrayList JavaDoc(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 JavaDoc();
346             for (int i= 0; i < cleanUps.length; i++) {
347                 ICleanUp cleanUp= cleanUps[i];
348                 Map JavaDoc 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 JavaDoc parseList= new ArrayList JavaDoc();
363             List JavaDoc sourceList= new ArrayList JavaDoc();
364             
365             try {
366                 for (Iterator JavaDoc 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 JavaDoc)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 JavaDoc 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 JavaDoc[0], requestor, cuMonitor);
404                 } catch (FixCalculationException e) {
405                     throw e.getException();
406                 }
407                 
408                 for (Iterator JavaDoc 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 JavaDoc 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 JavaDoc iterator= fSolutions.entrySet().iterator(); iterator.hasNext();) {
443                 Map.Entry JavaDoc entry= (Map.Entry JavaDoc)iterator.next();
444                 
445                 List JavaDoc changes= (List JavaDoc)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 JavaDoc 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()); //$NON-NLS-1$
492
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 JavaDoc/*<ICleanUp>*/fCleanUps;
503     private final Hashtable JavaDoc/*<IJavaProject, List<ICompilationUnit>*/fProjects;
504     private Change fChange;
505     private boolean fLeaveFilesDirty;
506     private final String JavaDoc fName;
507     
508     public CleanUpRefactoring() {
509         this(FixMessages.CleanUpRefactoring_Refactoring_name);
510     }
511     
512     public CleanUpRefactoring(String JavaDoc name) {
513         fName= name;
514         fCleanUps= new ArrayList JavaDoc();
515         fProjects= new Hashtable JavaDoc();
516     }
517     
518     public void addCompilationUnit(ICompilationUnit unit) {
519         IJavaProject javaProject= unit.getJavaProject();
520         if (!fProjects.containsKey(javaProject))
521             fProjects.put(javaProject, new ArrayList JavaDoc());
522         
523         List JavaDoc cus= (List JavaDoc)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 JavaDoc cus= new ArrayList JavaDoc();
537         for (Iterator JavaDoc iter= fProjects.values().iterator(); iter.hasNext();) {
538             List JavaDoc pcus= (List JavaDoc)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     /* (non-Javadoc)
569      * @see org.eclipse.ltk.core.refactoring.Refactoring#getName()
570      */

571     public String JavaDoc getName() {
572         return fName;
573     }
574     
575     /* (non-Javadoc)
576      * @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)
577      */

578     public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
579         if (pm != null) {
580             pm.beginTask("", 1); //$NON-NLS-1$
581
pm.worked(1);
582             pm.done();
583         }
584         return new RefactoringStatus();
585     }
586     
587     /* (non-Javadoc)
588      * @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor)
589      */

590     public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
591         if (pm != null) {
592             pm.beginTask("", 1); //$NON-NLS-1$
593
pm.worked(1);
594             pm.done();
595         }
596         return fChange;
597     }
598     
599     /* (non-Javadoc)
600      * @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor)
601      */

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); //$NON-NLS-1$
609
pm.worked(1);
610             pm.done();
611             fChange= new NullChange();
612             
613             return new RefactoringStatus();
614         }
615         
616         int cuCount= 0;
617         for (Iterator JavaDoc iter= fProjects.keySet().iterator(); iter.hasNext();) {
618             IJavaProject project= (IJavaProject)iter.next();
619             cuCount+= ((List JavaDoc)fProjects.get(project)).size();
620         }
621         
622         RefactoringStatus result= new RefactoringStatus();
623         
624         pm.beginTask("", cuCount * 2 * fCleanUps.size() + 4 * fCleanUps.size()); //$NON-NLS-1$
625
try {
626             DynamicValidationStateChange change= new DynamicValidationStateChange(getName());
627             change.setSchedulingRule(getSchedulingRule());
628             for (Iterator JavaDoc projectIter= fProjects.keySet().iterator(); projectIter.hasNext();) {
629                 IJavaProject project= (IJavaProject)projectIter.next();
630                 
631                 List JavaDoc compilationUnits= (List JavaDoc)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 JavaDoc files= new ArrayList JavaDoc();
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 JavaDoc 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); //$NON-NLS-1$
686
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 JavaDoc 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); //$NON-NLS-1$
718
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); //$NON-NLS-1$
737
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 JavaDoc getChangeName(ICompilationUnit compilationUnit) {
751         StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
752         JavaElementLabels.getCompilationUnitLabel(compilationUnit, JavaElementLabels.ALL_DEFAULT, buf);
753         buf.append(JavaElementLabels.CONCAT_STRING);
754         
755         StringBuffer JavaDoc buf2= new StringBuffer JavaDoc();
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 JavaDoc 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 JavaDoc 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 JavaDoc edits= new ArrayList JavaDoc();
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 JavaDoc 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    /* (non-Javadoc)
1030     * @see org.eclipse.ltk.core.refactoring.Refactoring#getRefactoringTickProvider()
1031     */

1032    protected RefactoringTickProvider doGetRefactoringTickProvider() {
1033        return CLEAN_UP_REFACTORING_TICK_PROVIDER;
1034    }
1035    
1036    /**
1037     * {@inheritDoc}
1038     */

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 JavaDoc 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