| /******************************************************************************* |
| * Copyright (c) 2000, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.fix; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.text.edits.DeleteEdit; |
| import org.eclipse.text.edits.MoveSourceEdit; |
| import org.eclipse.text.edits.MultiTextEdit; |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| import org.eclipse.text.edits.TextEditVisitor; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.OperationCanceledException; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.core.resources.IFile; |
| |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.CompositeChange; |
| import org.eclipse.ltk.core.refactoring.NullChange; |
| import org.eclipse.ltk.core.refactoring.Refactoring; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.RefactoringTickProvider; |
| import org.eclipse.ltk.core.refactoring.TextChange; |
| import org.eclipse.ltk.core.refactoring.TextEditBasedChangeGroup; |
| import org.eclipse.ltk.core.refactoring.TextFileChange; |
| |
| import org.eclipse.jdt.core.IBuffer; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.WorkingCopyOwner; |
| import org.eclipse.jdt.core.dom.ASTParser; |
| import org.eclipse.jdt.core.dom.ASTRequestor; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| |
| import org.eclipse.jdt.internal.corext.refactoring.Checks; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.MultiStateCompilationUnitChange; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.TextChangeCompatibility; |
| import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| |
| import org.eclipse.jdt.internal.ui.fix.ICleanUp; |
| import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider; |
| |
| public class CleanUpRefactoring extends Refactoring { |
| |
| private static final int BATCH_SIZE= 40; |
| |
| private class FixCalculationException extends RuntimeException { |
| |
| private static final long serialVersionUID= 3807273310144726165L; |
| |
| private final CoreException fException; |
| |
| public FixCalculationException(CoreException exception) { |
| fException= exception; |
| } |
| |
| public CoreException getException() { |
| return fException; |
| } |
| |
| } |
| |
| private class ParseListElement { |
| |
| private final ICompilationUnit fUnit; |
| private List fCleanUpsToGo; |
| private ICleanUp[] fCleanUpsArray; |
| |
| public ParseListElement(ICompilationUnit unit) { |
| fUnit= unit; |
| fCleanUpsToGo= new ArrayList(); |
| fCleanUpsArray= new ICleanUp[0]; |
| } |
| |
| public ParseListElement(ICompilationUnit unit, ICleanUp[] cleanUps) { |
| fUnit= unit; |
| fCleanUpsArray= cleanUps; |
| fCleanUpsToGo= null; |
| } |
| |
| public void addCleanUp(ICleanUp multiFix) { |
| if (fCleanUpsToGo == null) { |
| fCleanUpsToGo= Arrays.asList(fCleanUpsArray); |
| } |
| fCleanUpsToGo.add(multiFix); |
| fCleanUpsArray= null; |
| } |
| |
| public ICompilationUnit getCompilationUnit() { |
| return fUnit; |
| } |
| |
| public ICleanUp[] getCleanUps() { |
| if (fCleanUpsArray == null) { |
| fCleanUpsArray= (ICleanUp[])fCleanUpsToGo.toArray(new ICleanUp[fCleanUpsToGo.size()]); |
| } |
| return fCleanUpsArray; |
| } |
| } |
| |
| private class IndexCounter { |
| |
| private int fIndex; |
| private final int fSize; |
| |
| public IndexCounter(int index, int size) { |
| fIndex= index; |
| fSize= size; |
| } |
| |
| public void inc() { |
| fIndex++; |
| } |
| |
| public int value() { |
| return fIndex; |
| } |
| |
| public int size() { |
| return fSize; |
| } |
| } |
| |
| private final class CleanUpRefactoringProgressMonitor extends SubProgressMonitor { |
| private int worked= 0; |
| |
| private CleanUpRefactoringProgressMonitor(IProgressMonitor monitor, int ticks) { |
| super(monitor, ticks); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void worked(int work) { |
| worked+=work; |
| } |
| |
| public void flush() { |
| super.worked(worked); |
| reset(); |
| } |
| |
| public void reset() { |
| worked= 0; |
| } |
| |
| public void done() { |
| } |
| } |
| |
| private final class SolutionGenerator extends ASTRequestor { |
| |
| private final CleanUpRefactoringProgressMonitor fMonitor; |
| private final List fResult; |
| private final Hashtable fSolutions; |
| private final Iterator fToParseIter; |
| private ParseListElement fCurElement; |
| private IndexCounter fIndex; |
| |
| private SolutionGenerator(List/*<ParseListElement>*/ toSolve, IndexCounter startIndex, Hashtable solutions, CleanUpRefactoringProgressMonitor monitor) { |
| fMonitor= monitor; |
| fResult= new ArrayList(); |
| fSolutions= solutions; |
| fIndex= startIndex; |
| |
| fToParseIter= toSolve.iterator(); |
| fCurElement= (ParseListElement)fToParseIter.next(); |
| fMonitor.subTask(getSubTaskMessage(fCurElement.getCompilationUnit(), fIndex.value(), fIndex.size())); |
| } |
| |
| public List getResult() { |
| return fResult; |
| } |
| |
| public void acceptAST(ICompilationUnit source, CompilationUnit ast) { |
| ParseListElement tuple= calculateSolution(fSolutions, ast, fCurElement.getCleanUps()); |
| if (fMonitor.isCanceled()) |
| throw new OperationCanceledException(); |
| if (tuple != null) { |
| fResult.add(tuple); |
| fMonitor.reset(); |
| } else { |
| fIndex.inc(); |
| fMonitor.flush(); |
| } |
| if (fToParseIter.hasNext()) { |
| fCurElement= (ParseListElement)fToParseIter.next(); |
| fMonitor.subTask(getSubTaskMessage(fCurElement.getCompilationUnit(), fIndex.value(), fIndex.size())); |
| } |
| } |
| |
| private String getSubTaskMessage(ICompilationUnit cu, int index, int size) { |
| String typeName= JavaCore.removeJavaLikeExtension(cu.getElementName()); |
| return Messages.format(FixMessages.CleanUpRefactoring_ProcessingCompilationUnit_message, new Object[] {typeName, new Integer(index), new Integer(size)}); |
| } |
| |
| private ParseListElement calculateSolution(Hashtable solutions, CompilationUnit ast, ICleanUp[] cleanUps) { |
| TextChange solution= null; |
| ParseListElement result= null; |
| for (int i= 0; i < cleanUps.length; i++) { |
| ICleanUp cleanUp= cleanUps[i]; |
| try { |
| IFix fix= cleanUp.createFix(ast); |
| if (fix != null) { |
| TextChange current= fix.createChange(); |
| if (current instanceof TextFileChange && fLeaveFilesDirty) |
| ((TextFileChange)current).setSaveMode(TextFileChange.LEAVE_DIRTY); |
| |
| if (solution != null) { |
| if (intersects(current.getEdit(),solution.getEdit())) { |
| if (result == null) { |
| result= new ParseListElement((ICompilationUnit)ast.getJavaElement().getPrimaryElement()); |
| } |
| result.addCleanUp(cleanUp); |
| } else { |
| mergeTextChanges(current, solution); |
| solution= current; |
| } |
| } else { |
| solution= current; |
| } |
| } |
| } catch (CoreException e) { |
| throw new FixCalculationException(e); |
| } |
| } |
| |
| if (solution != null) { |
| if (solutions.containsKey(ast.getJavaElement().getPrimaryElement())) { |
| MultiStateCompilationUnitChange oldChange= (MultiStateCompilationUnitChange)solutions.get(ast.getJavaElement().getPrimaryElement()); |
| oldChange.addChange(solution); |
| } else { |
| solutions.put(ast.getJavaElement(), solution); |
| } |
| } |
| |
| return result; |
| } |
| } |
| |
| |
| private static final RefactoringTickProvider CLEAN_UP_REFACTORING_TICK_PROVIDER= new RefactoringTickProvider(0, 1, 0, 0); |
| |
| private List/*<ICleanUp>*/ fCleanUps; |
| private Hashtable/*<IJavaProject, List<ICompilationUnit>*/ fProjects; |
| |
| private Change fChange; |
| |
| private boolean fLeaveFilesDirty; |
| |
| public CleanUpRefactoring() { |
| fCleanUps= new ArrayList(); |
| fProjects= new Hashtable(); |
| } |
| |
| public void addCompilationUnit(ICompilationUnit unit) { |
| IJavaProject javaProject= unit.getJavaProject(); |
| if (!fProjects.containsKey(javaProject)) |
| fProjects.put(javaProject, new ArrayList()); |
| |
| List cus= (List)fProjects.get(javaProject); |
| cus.add(unit); |
| } |
| |
| public void clearCompilationUnits() { |
| fProjects.clear(); |
| } |
| |
| public boolean hasCompilationUnits() { |
| return !fProjects.isEmpty(); |
| } |
| |
| public ICompilationUnit[] getCompilationUnits() { |
| List cus= new ArrayList(); |
| for (Iterator iter= fProjects.values().iterator(); iter.hasNext();) { |
| List pcus= (List)iter.next(); |
| cus.addAll(pcus); |
| } |
| return (ICompilationUnit[])cus.toArray(new ICompilationUnit[cus.size()]); |
| } |
| |
| public void addCleanUp(ICleanUp fix) { |
| fCleanUps.add(fix); |
| } |
| |
| public void clearCleanUps() { |
| fCleanUps.clear(); |
| } |
| |
| public boolean hasCleanUps() { |
| return !fCleanUps.isEmpty(); |
| } |
| |
| public ICleanUp[] getCleanUps() { |
| return (ICleanUp[])fCleanUps.toArray(new ICleanUp[fCleanUps.size()]); |
| } |
| |
| public IJavaProject[] getProjects() { |
| return (IJavaProject[])fProjects.keySet().toArray(new IJavaProject[fProjects.keySet().size()]); |
| } |
| |
| public void setLeaveFilesDirty(boolean leaveFilesDirty) { |
| fLeaveFilesDirty= leaveFilesDirty; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ltk.core.refactoring.Refactoring#getName() |
| */ |
| public String getName() { |
| return FixMessages.CleanUpRefactoring_Refactoring_name; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { |
| if (pm != null) { |
| pm.beginTask("", 1); //$NON-NLS-1$ |
| pm.worked(1); |
| pm.done(); |
| } |
| return new RefactoringStatus(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { |
| if (pm != null) { |
| pm.beginTask("", 1); //$NON-NLS-1$ |
| pm.worked(1); |
| pm.done(); |
| } |
| return fChange; |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { |
| |
| if (pm == null) |
| pm= new NullProgressMonitor(); |
| |
| if (fProjects.size() == 0 || fCleanUps.size() == 0) { |
| pm.beginTask("", 1); //$NON-NLS-1$ |
| pm.worked(1); |
| pm.done(); |
| fChange= new NullChange(); |
| |
| return new RefactoringStatus(); |
| } |
| |
| int cuCount= 0; |
| for (Iterator iter= fProjects.keySet().iterator(); iter.hasNext();) { |
| IJavaProject project= (IJavaProject)iter.next(); |
| cuCount+= ((List)fProjects.get(project)).size(); |
| } |
| |
| pm.beginTask("", cuCount * 2 * fCleanUps.size() + 4 * fCleanUps.size()); //$NON-NLS-1$ |
| |
| try { |
| CompositeChange change= new DynamicValidationStateChange(getName()); |
| for (Iterator projectIter= fProjects.keySet().iterator(); projectIter.hasNext();) { |
| IJavaProject project= (IJavaProject)projectIter.next(); |
| |
| List compilationUnits= (List)fProjects.get(project); |
| ICompilationUnit[] cus= (ICompilationUnit[])compilationUnits.toArray(new ICompilationUnit[compilationUnits.size()]); |
| |
| ICleanUp[] cleanUps= (ICleanUp[])fCleanUps.toArray(new ICleanUp[fCleanUps.size()]); |
| |
| cleanUpProject(project, cus, cleanUps, change, pm); |
| } |
| fChange= change; |
| |
| RefactoringStatus result= new RefactoringStatus(); |
| List files= new ArrayList(); |
| findFilesToBeModified(change, files); |
| result.merge(Checks.validateModifiesFiles((IFile[])files.toArray(new IFile[files.size()]), getValidationContext())); |
| if (result.hasFatalError()) |
| return result; |
| } finally { |
| pm.done(); |
| } |
| |
| return new RefactoringStatus(); |
| } |
| |
| private void findFilesToBeModified(CompositeChange change, List result) throws JavaModelException { |
| Change[] children= change.getChildren(); |
| for (int i=0;i < children.length;i++) { |
| Change child= children[i]; |
| if (child instanceof CompositeChange) { |
| findFilesToBeModified((CompositeChange)child, result); |
| } else if (child instanceof MultiStateCompilationUnitChange) { |
| result.add(((MultiStateCompilationUnitChange)child).getCompilationUnit().getCorrespondingResource()); |
| } else if (child instanceof CompilationUnitChange) { |
| result.add(((CompilationUnitChange)child).getCompilationUnit().getCorrespondingResource()); |
| } |
| } |
| } |
| |
| private void cleanUpProject(IJavaProject project, ICompilationUnit[] compilationUnits, ICleanUp[] cleanUps, CompositeChange result, IProgressMonitor monitor) throws CoreException { |
| initCleanUps(project, compilationUnits, new SubProgressMonitor(monitor, 4 * cleanUps.length)); |
| |
| List toGo= new ArrayList(); |
| for (int i= 0; i < compilationUnits.length; i++) { |
| toGo.add(new ParseListElement(compilationUnits[i], cleanUps)); |
| } |
| Hashtable resultingFixes= new Hashtable(); |
| Map cleanUpOptions= getCleanUpOptions(); |
| |
| IndexCounter index= new IndexCounter(1, compilationUnits.length); |
| int start= 0; |
| int end= 0; |
| while (end < toGo.size()) { |
| end= Math.min(start + BATCH_SIZE, toGo.size()); |
| List toParse= toGo.subList(start, end); |
| |
| ASTParser parser= createParser(cleanUpOptions, project); |
| List redoList= parse(toParse, parser, resultingFixes, index, new CleanUpRefactoringProgressMonitor(monitor, toParse.size() * 2 * cleanUps.length)); |
| toGo.addAll(redoList); |
| |
| start= end; |
| } |
| for (Iterator iter= resultingFixes.values().iterator(); iter.hasNext();) { |
| Change element= (Change)iter.next(); |
| result.add(element); |
| } |
| |
| endCleanUps(); |
| } |
| |
| private void initCleanUps(IJavaProject javaProject, ICompilationUnit[] compilationUnits, IProgressMonitor monitor) throws CoreException { |
| ICleanUp[] cleanUps= getCleanUps(); |
| monitor.beginTask(Messages.format(FixMessages.CleanUpRefactoring_Initialize_message, javaProject.getElementName()), compilationUnits.length * cleanUps.length); |
| try { |
| for (int j= 0; j < cleanUps.length; j++) { |
| cleanUps[j].beginCleanUp(javaProject, compilationUnits, new SubProgressMonitor(monitor, compilationUnits.length)); |
| } |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| private void endCleanUps() throws CoreException { |
| ICleanUp[] cleanUps= getCleanUps(); |
| for (int j= 0; j < cleanUps.length; j++) { |
| cleanUps[j].endCleanUp(); |
| } |
| } |
| |
| /** |
| * @return Options for all multi-fixes in <code>fMultiFixes</code> |
| */ |
| private Map getCleanUpOptions() { |
| Map cleanUpOptions= new Hashtable(); |
| for (Iterator iter= fCleanUps.iterator(); iter.hasNext();) { |
| ICleanUp cleanUp= (ICleanUp)iter.next(); |
| Map currentCleanUpOption= cleanUp.getRequiredOptions(); |
| if (currentCleanUpOption != null) |
| cleanUpOptions.putAll(currentCleanUpOption); |
| } |
| return cleanUpOptions; |
| } |
| |
| private List/*<ParseListElement>*/ parse(List/*<ParseListElement*/ toParse, ASTParser parser, final Hashtable solutions, final IndexCounter index, final CleanUpRefactoringProgressMonitor monitor) throws CoreException { |
| |
| final ICompilationUnit[] compilationUnits= new ICompilationUnit[toParse.size()]; |
| final List workingCopys= new ArrayList(); |
| try { |
| int i= 0; |
| for (Iterator iter= toParse.iterator(); iter.hasNext();) { |
| ParseListElement element= (ParseListElement) iter.next(); |
| |
| ICompilationUnit compilationUnit= element.getCompilationUnit(); |
| if (solutions.containsKey(compilationUnit)) { |
| |
| ICompilationUnit workingCopy= createWorkingCopy(solutions, compilationUnit); |
| |
| compilationUnits[i]= workingCopy; |
| workingCopys.add(workingCopy); |
| } else { |
| compilationUnits[i]= compilationUnit; |
| } |
| i++; |
| } |
| |
| SolutionGenerator solutionGenerator= new SolutionGenerator(toParse, index, solutions, monitor); |
| try { |
| parser.createASTs(compilationUnits, new String[0], solutionGenerator, monitor); |
| } catch (FixCalculationException e) { |
| throw e.getException(); |
| } |
| return solutionGenerator.getResult(); |
| } finally { |
| if (!workingCopys.isEmpty()) { |
| for (Iterator iter= workingCopys.iterator(); iter.hasNext();) { |
| ICompilationUnit cu= (ICompilationUnit)iter.next(); |
| cu.discardWorkingCopy(); |
| } |
| } |
| monitor.done(); |
| } |
| } |
| |
| private ICompilationUnit createWorkingCopy(final Hashtable solutions, ICompilationUnit compilationUnit) throws JavaModelException, CoreException { |
| Change oldChange= (Change)solutions.get(compilationUnit); |
| |
| MultiStateCompilationUnitChange mscuc; |
| if (!(oldChange instanceof MultiStateCompilationUnitChange)) { |
| mscuc= new MultiStateCompilationUnitChange(getChangeName(compilationUnit), compilationUnit); |
| mscuc.setKeepPreviewEdits(true); |
| mscuc.addChange((TextChange)oldChange); |
| solutions.remove(compilationUnit); |
| solutions.put(compilationUnit, mscuc); |
| } else { |
| mscuc= (MultiStateCompilationUnitChange)oldChange; |
| } |
| |
| ICompilationUnit workingCopy= compilationUnit.getWorkingCopy(new WorkingCopyOwner() {}, null, null); |
| |
| IBuffer buffer= workingCopy.getBuffer(); |
| buffer.setContents(mscuc.getPreviewContent(null)); |
| return workingCopy; |
| } |
| |
| private String getChangeName(ICompilationUnit compilationUnit) { |
| StringBuffer buf= new StringBuffer(); |
| JavaElementLabels.getCompilationUnitLabel(compilationUnit, JavaElementLabels.ALL_DEFAULT, buf); |
| buf.append(JavaElementLabels.CONCAT_STRING); |
| |
| StringBuffer buf2= new StringBuffer(); |
| JavaElementLabels.getPackageFragmentLabel((IPackageFragment) compilationUnit.getParent(), JavaElementLabels.P_QUALIFIED, buf2); |
| buf.append(buf2.toString().replace('.', '/')); |
| |
| return buf.toString(); |
| } |
| |
| private ASTParser createParser(Map cleanUpOptions, IJavaProject javaProject) { |
| ASTParser parser= ASTParser.newParser(ASTProvider.SHARED_AST_LEVEL); |
| parser.setResolveBindings(true); |
| parser.setProject(javaProject); |
| |
| Map options= RefactoringASTParser.getCompilerOptions(javaProject); |
| options.putAll(cleanUpOptions); |
| parser.setCompilerOptions(options); |
| return parser; |
| } |
| |
| private static boolean intersects(TextEdit edit1, TextEdit edit2) { |
| if (edit1 instanceof MultiTextEdit && edit2 instanceof MultiTextEdit) { |
| MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1; |
| TextEdit[] children1= multiTextEdit1.getChildren(); |
| |
| MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2; |
| TextEdit[] children2= multiTextEdit2.getChildren(); |
| |
| int i1= 0; |
| int i2= 0; |
| while (i1 < children1.length && i2 < children2.length) { |
| while (children1[i1].getExclusiveEnd() < children2[i2].getOffset()) { |
| i1++; |
| if (i1 >= children1.length) |
| return false; |
| } |
| while (children2[i2].getExclusiveEnd() < children1[i1].getOffset()) { |
| i2++; |
| if (i2 >= children2.length) |
| return false; |
| } |
| if (intersects(children1[i1], children2[i2])) |
| return true; |
| |
| if (children1[i1].getExclusiveEnd() < children2[i2].getExclusiveEnd()) { |
| i1++; |
| } else { |
| i2++; |
| } |
| } |
| |
| return false; |
| |
| } else if (edit1 instanceof MultiTextEdit) { |
| MultiTextEdit multiTextEdit1= (MultiTextEdit)edit1; |
| TextEdit[] children= multiTextEdit1.getChildren(); |
| for (int i= 0; i < children.length; i++) { |
| TextEdit child= children[i]; |
| if (intersects(child, edit2)) |
| return true; |
| } |
| return false; |
| |
| } else if (edit2 instanceof MultiTextEdit) { |
| MultiTextEdit multiTextEdit2= (MultiTextEdit)edit2; |
| TextEdit[] children= multiTextEdit2.getChildren(); |
| for (int i= 0; i < children.length; i++) { |
| TextEdit child= children[i]; |
| if (intersects(child, edit1)) |
| return true; |
| } |
| return false; |
| |
| } else { |
| int start1= edit1.getOffset(); |
| int end1= start1 + edit1.getLength(); |
| int start2= edit2.getOffset(); |
| int end2= start2 + edit2.getLength(); |
| |
| if (start1 > end2) |
| return false; |
| |
| if (start2 > end1) |
| return false; |
| |
| return true; |
| } |
| } |
| |
| private static void mergeTextChanges(TextChange target, TextChange source) { |
| final List edits= new ArrayList(); |
| source.getEdit().accept(new TextEditVisitor() { |
| public boolean visitNode(TextEdit edit) { |
| if (edit instanceof MoveSourceEdit) |
| return false; |
| |
| if (edit instanceof MultiTextEdit) |
| return true; |
| |
| edits.add(edit); |
| return super.visitNode(edit); |
| } |
| |
| }); |
| if (edits.isEmpty()) |
| return; |
| |
| final List removedEdits= new ArrayList(); |
| target.getEdit().accept(new TextEditVisitor() { |
| public boolean visit(DeleteEdit deleteEdit) { |
| int start= deleteEdit.getOffset(); |
| int end= start + deleteEdit.getLength(); |
| |
| List toRemove= new ArrayList(); |
| for (Iterator iter= edits.iterator(); iter.hasNext();) { |
| TextEdit edit= (TextEdit)iter.next(); |
| int offset= edit.getOffset(); |
| if (offset >= start && offset <= end) { |
| toRemove.add(edit); |
| } |
| } |
| |
| if (!toRemove.isEmpty()) { |
| edits.removeAll(toRemove); |
| removedEdits.addAll(toRemove); |
| } |
| |
| return super.visit(deleteEdit); |
| } |
| }); |
| for (Iterator iter= edits.iterator(); iter.hasNext();) { |
| TextEdit edit= (TextEdit)iter.next(); |
| edit.getParent().removeChild(edit); |
| TextChangeCompatibility.insert(target.getEdit(), edit); |
| } |
| TextEditBasedChangeGroup[] changeGroups= source.getChangeGroups(); |
| for (int i= 0; i < changeGroups.length; i++) { |
| TextEditGroup textEditGroup= changeGroups[i].getTextEditGroup(); |
| TextEditGroup newGroup= new TextEditGroup(textEditGroup.getName()); |
| TextEdit[] textEdits= textEditGroup.getTextEdits(); |
| for (int j= 0; j < textEdits.length; j++) { |
| if (!removedEdits.contains(textEdits[j])) |
| newGroup.addTextEdit(textEdits[j]); |
| } |
| target.addTextEditGroup(newGroup); |
| } |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.ltk.core.refactoring.Refactoring#getRefactoringTickProvider() |
| */ |
| protected RefactoringTickProvider doGetRefactoringTickProvider() { |
| return CLEAN_UP_REFACTORING_TICK_PROVIDER; |
| } |
| } |