| /******************************************************************************* |
| * 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.refactoring.structure; |
| |
| import java.util.ArrayList; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.eclipse.text.edits.MultiTextEdit; |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| |
| import org.eclipse.ltk.core.refactoring.CategorizedTextEditGroup; |
| import org.eclipse.ltk.core.refactoring.GroupCategorySet; |
| |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.WorkingCopyOwner; |
| import org.eclipse.jdt.core.dom.AST; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; |
| |
| import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; |
| import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| |
| /** |
| * A {@link CompilationUnitRewrite} holds all data structures that are typically |
| * required for non-trivial refactorings. All getters are initialized lazily to |
| * avoid lengthy processing in |
| * {@link org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org.eclipse.core.runtime.IProgressMonitor)}. |
| * <p> |
| * Bindings are resolved by default, but can be disabled with <code>setResolveBindings(false)</code>. |
| * </p> |
| */ |
| public class CompilationUnitRewrite { |
| //TODO: add RefactoringStatus fStatus;? |
| private ICompilationUnit fCu; |
| private List/*<TextEditGroup>*/ fTextEditGroups= new ArrayList(); |
| |
| private CompilationUnit fRoot; // lazily initialized |
| private ASTRewrite fRewrite; // lazily initialized |
| private ImportRewrite fImportRewrite; // lazily initialized |
| private ImportRemover fImportRemover; // lazily initialized |
| private boolean fResolveBindings= true; |
| private boolean fStatementsRecovery= false; |
| private final WorkingCopyOwner fOwner; |
| private IDocument fRememberContent= null; |
| |
| public CompilationUnitRewrite(ICompilationUnit cu) { |
| this(null, cu, null); |
| } |
| |
| public CompilationUnitRewrite(WorkingCopyOwner owner, ICompilationUnit cu) { |
| this(owner, cu, null); |
| } |
| |
| public CompilationUnitRewrite(ICompilationUnit cu, CompilationUnit root) { |
| this(null, cu, root); |
| } |
| |
| public CompilationUnitRewrite(WorkingCopyOwner owner, ICompilationUnit cu, CompilationUnit root) { |
| fOwner= owner; |
| fCu= cu; |
| fRoot= root; |
| } |
| |
| public void rememberContent() { |
| fRememberContent= new Document(); |
| } |
| |
| |
| /** |
| * Requests that the compiler should provide binding information for the AST |
| * nodes it creates. To be effective, this method must be called before any |
| * of {@link #getRoot()},{@link #getASTRewrite()}, |
| * {@link #getImportRemover()}. This method has no effect if the target object |
| * has been created with {@link #CompilationUnitRewrite(ICompilationUnit, CompilationUnit)}. |
| * <p> |
| * Defaults to <b><code>true</code></b> (do resolve bindings). |
| * </p> |
| * |
| * @param resolve |
| * <code>true</code> if bindings are wanted, and |
| * <code>false</code> if bindings are not of interest |
| * @see org.eclipse.jdt.core.dom.ASTParser#setResolveBindings(boolean) |
| * Note: The default value (<code>true</code>) differs from the one of |
| * the corresponding method in ASTParser. |
| */ |
| public void setResolveBindings(boolean resolve) { |
| fResolveBindings= resolve; |
| } |
| |
| /** |
| * Requests that the compiler should perform statements recovery. |
| * To be effective, this method must be called before any |
| * of {@link #getRoot()},{@link #getASTRewrite()}, |
| * {@link #getImportRemover()}. This method has no effect if the target object |
| * has been created with {@link #CompilationUnitRewrite(ICompilationUnit, CompilationUnit)}. |
| * <p> |
| * Defaults to <b><code>false</code></b> (do not perform statements recovery). |
| * </p> |
| * |
| * @param statementsRecovery whether statements recovery should be performed |
| * @see org.eclipse.jdt.core.dom.ASTParser#setStatementsRecovery(boolean) |
| */ |
| public void setStatementsRecovery(boolean statementsRecovery) { |
| fStatementsRecovery= statementsRecovery; |
| } |
| |
| public void clearASTRewrite() { |
| fRewrite= null; |
| fTextEditGroups= new ArrayList(); |
| } |
| |
| public void clearImportRewrites() { |
| fImportRewrite= null; |
| } |
| |
| public void clearASTAndImportRewrites() { |
| clearASTRewrite(); |
| fImportRewrite= null; |
| } |
| |
| public CategorizedTextEditGroup createCategorizedGroupDescription(String name, GroupCategorySet set) { |
| CategorizedTextEditGroup result= new CategorizedTextEditGroup(name, set); |
| fTextEditGroups.add(result); |
| return result; |
| } |
| |
| public TextEditGroup createGroupDescription(String name) { |
| TextEditGroup result= new TextEditGroup(name); |
| fTextEditGroups.add(result); |
| return result; |
| } |
| |
| |
| public CompilationUnitChange createChange() throws CoreException { |
| return createChange(true, null); |
| } |
| |
| /** |
| * Creates a compilation unit change based on the events recorded by this compilation unit rewrite. |
| * @param generateGroups <code>true</code> to generate text edit groups, <code>false</code> otherwise |
| * @param monitor the progress monitor or <code>null</code> |
| * @return a {@link CompilationUnitChange}, or <code>null</code> for an empty change |
| * @throws CoreException when text buffer acquisition or import rewrite text edit creation fails |
| * @throws IllegalArgumentException when the AST rewrite encounters problems |
| */ |
| public CompilationUnitChange createChange(boolean generateGroups, IProgressMonitor monitor) throws CoreException { |
| CompilationUnitChange cuChange= new CompilationUnitChange(fCu.getElementName(), fCu); |
| MultiTextEdit multiEdit= new MultiTextEdit(); |
| cuChange.setEdit(multiEdit); |
| return attachChange(cuChange, generateGroups, monitor); |
| } |
| |
| /** |
| * Attaches the changes of this compilation unit rewrite to the given CU Change. The given |
| * change <b>must</b> either have no root edit, or a MultiTextEdit as a root edit. |
| * The edits in the given change <b>must not</b> overlap with the changes of |
| * this compilation unit. |
| * |
| * @param cuChange existing CompilationUnitChange with a MultiTextEdit root or no root at all. |
| * @param generateGroups <code>true</code> to generate text edit groups, <code>false</code> otherwise |
| * @param monitor the progress monitor or <code>null</code> |
| * @return a change combining the changes of this rewrite and the given rewrite. |
| * @throws CoreException |
| */ |
| public CompilationUnitChange attachChange(CompilationUnitChange cuChange, boolean generateGroups, IProgressMonitor monitor) throws CoreException { |
| try { |
| boolean needsAstRewrite= fRewrite != null; // TODO: do we need something like ASTRewrite#hasChanges() here? |
| boolean needsImportRemoval= fImportRemover != null && fImportRemover.hasRemovedNodes(); |
| boolean needsImportRewrite= fImportRewrite != null && fImportRewrite.hasRecordedChanges() || needsImportRemoval; |
| if (!needsAstRewrite && !needsImportRemoval && !needsImportRewrite) |
| return null; |
| |
| MultiTextEdit multiEdit= (MultiTextEdit) cuChange.getEdit(); |
| if (multiEdit == null) { |
| multiEdit= new MultiTextEdit(); |
| cuChange.setEdit(multiEdit); |
| } |
| |
| if (needsAstRewrite) { |
| TextEdit rewriteEdit; |
| if (fRememberContent != null) { |
| rewriteEdit= fRewrite.rewriteAST(fRememberContent, fCu.getJavaProject().getOptions(true)); |
| } else { |
| rewriteEdit= fRewrite.rewriteAST(); |
| } |
| if (!isEmptyEdit(rewriteEdit)) { |
| multiEdit.addChild(rewriteEdit); |
| for (Iterator iter= fTextEditGroups.iterator(); iter.hasNext();) { |
| TextEditGroup group= (TextEditGroup) iter.next(); |
| if (generateGroups) |
| cuChange.addTextEditGroup(group); |
| } |
| } |
| } |
| if (needsImportRemoval) { |
| fImportRemover.applyRemoves(getImportRewrite()); |
| } |
| if (needsImportRewrite) { |
| TextEdit importsEdit= fImportRewrite.rewriteImports(monitor); |
| if (!isEmptyEdit(importsEdit)) { |
| multiEdit.addChild(importsEdit); |
| String importUpdateName= RefactoringCoreMessages.ASTData_update_imports; |
| cuChange.addTextEditGroup(new TextEditGroup(importUpdateName, importsEdit)); |
| } |
| } else { |
| |
| } |
| if (isEmptyEdit(multiEdit)) |
| return null; |
| return cuChange; |
| } finally { |
| if (monitor != null) |
| monitor.done(); |
| } |
| } |
| |
| private static boolean isEmptyEdit(TextEdit edit) { |
| return edit.getClass() == MultiTextEdit.class && ! edit.hasChildren(); |
| } |
| |
| public ICompilationUnit getCu() { |
| return fCu; |
| } |
| |
| public CompilationUnit getRoot() { |
| if (fRoot == null) |
| fRoot= new RefactoringASTParser(AST.JLS3).parse(fCu, fOwner, fResolveBindings, fStatementsRecovery, null); |
| return fRoot; |
| } |
| |
| public AST getAST() { |
| return getRoot().getAST(); |
| } |
| |
| public ASTRewrite getASTRewrite() { |
| if (fRewrite == null) { |
| fRewrite= ASTRewrite.create(getRoot().getAST()); |
| if (fRememberContent != null) { // wain until ast rewrite is accessed first |
| try { |
| fRememberContent.set(fCu.getSource()); |
| } catch (JavaModelException e) { |
| fRememberContent= null; |
| } |
| } |
| } |
| return fRewrite; |
| } |
| |
| public ImportRewrite getImportRewrite() { |
| if (fImportRewrite == null) { |
| // lazily initialized to avoid lengthy processing in checkInitialConditions(..) |
| try { |
| if (fRoot == null) { |
| fImportRewrite= StubUtility.createImportRewrite(fCu, true); |
| } else { |
| fImportRewrite= StubUtility.createImportRewrite(getRoot(), true); |
| } |
| } catch (CoreException e) { |
| JavaPlugin.log(e); |
| throw new IllegalStateException(e.getMessage()); // like ASTParser#createAST(..) does |
| } |
| } |
| return fImportRewrite; |
| |
| } |
| |
| public ImportRemover getImportRemover() { |
| if (fImportRemover == null) { |
| fImportRemover= new ImportRemover(fCu.getJavaProject(), getRoot()); |
| } |
| return fImportRemover; |
| } |
| } |