1 /*******************************************************************************
2 * Copyright (c) 2000, 2011 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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.surround;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
17 import org.eclipse.core.runtime.CoreException;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.NullProgressMonitor;
21 import org.eclipse.text.edits.MultiTextEdit;
22 import org.eclipse.text.edits.TextEdit;
23 import org.eclipse.text.edits.TextEditGroup;
25 import org.eclipse.jface.text.ITextSelection;
27 import org.eclipse.ltk.core.refactoring.Change;
28 import org.eclipse.ltk.core.refactoring.Refactoring;
29 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
30 import org.eclipse.ltk.core.refactoring.TextFileChange;
32 import org.eclipse.jdt.core.ICompilationUnit;
33 import org.eclipse.jdt.core.dom.AST;
34 import org.eclipse.jdt.core.dom.ASTNode;
35 import org.eclipse.jdt.core.dom.Assignment;
36 import org.eclipse.jdt.core.dom.Block;
37 import org.eclipse.jdt.core.dom.CatchClause;
38 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
39 import org.eclipse.jdt.core.dom.CompilationUnit;
40 import org.eclipse.jdt.core.dom.Expression;
41 import org.eclipse.jdt.core.dom.ExpressionStatement;
42 import org.eclipse.jdt.core.dom.IExtendedModifier;
43 import org.eclipse.jdt.core.dom.ITypeBinding;
44 import org.eclipse.jdt.core.dom.Modifier;
45 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
46 import org.eclipse.jdt.core.dom.Statement;
47 import org.eclipse.jdt.core.dom.TryStatement;
48 import org.eclipse.jdt.core.dom.Type;
49 import org.eclipse.jdt.core.dom.VariableDeclaration;
50 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
51 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
52 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
53 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
54 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
55 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
56 import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
58 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
59 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
60 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
61 import org.eclipse.jdt.internal.corext.dom.CodeScopeBuilder;
62 import org.eclipse.jdt.internal.corext.dom.Selection;
63 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
64 import org.eclipse.jdt.internal.corext.refactoring.Checks;
65 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
66 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
67 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
68 import org.eclipse.jdt.internal.corext.refactoring.util.SelectionAwareSourceRangeComputer;
69 import org.eclipse.jdt.internal.corext.util.Strings;
71 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
74 * Surround a set of statements with a try/catch block or a try/multi-catch block.
78 * URL url= file.toURL();
80 * In this case the variable declaration statement gets convert into a
81 * declaration without initializer. So the body of the try/catch block
82 * only consists of new assignments. In this case we can't move the
83 * selected nodes (e.g. the declaration) into the try block.
85 public class SurroundWithTryCatchRefactoring extends Refactoring {
87 public static final String GROUP_EXC_TYPE= "exc_type"; //$NON-NLS-1$
88 public static final String GROUP_EXC_NAME= "exc_name"; //$NON-NLS-1$
90 public Selection fSelection;
91 public SurroundWithTryCatchAnalyzer fAnalyzer;
92 private boolean fLeaveDirty;
94 public ICompilationUnit fCUnit;
95 CompilationUnit fRootNode;
96 public ASTRewrite fRewriter;
97 public ImportRewrite fImportRewrite;
98 public CodeScopeBuilder.Scope fScope;
99 private ASTNode[] fSelectedNodes;
101 public LinkedProposalModel fLinkedProposalModel;
103 final boolean fIsMultiCatch;
105 private SurroundWithTryCatchRefactoring(ICompilationUnit cu, Selection selection, boolean isMultiCatch) {
107 fSelection= selection;
108 fIsMultiCatch= isMultiCatch;
112 public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, ITextSelection selection) {
113 return create(cu, selection, false);
116 public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, int offset, int length) {
117 return create(cu, offset, length, false);
120 public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, ITextSelection selection, boolean isMultiCatch) {
121 return new SurroundWithTryCatchRefactoring(cu, Selection.createFromStartLength(selection.getOffset(), selection.getLength()), isMultiCatch);
124 public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, int offset, int length, boolean isMultiCatch) {
125 return new SurroundWithTryCatchRefactoring(cu, Selection.createFromStartLength(offset, length), isMultiCatch);
128 public LinkedProposalModel getLinkedProposalModel() {
129 return fLinkedProposalModel;
132 public void setLeaveDirty(boolean leaveDirty) {
133 fLeaveDirty= leaveDirty;
136 public boolean stopExecution() {
137 if (fAnalyzer == null)
139 ITypeBinding[] exceptions= fAnalyzer.getExceptions();
140 return exceptions == null || exceptions.length == 0;
144 * @see IRefactoring#getName()
147 public String getName() {
148 return RefactoringCoreMessages.SurroundWithTryCatchRefactoring_name;
151 public RefactoringStatus checkActivationBasics(CompilationUnit rootNode) throws CoreException {
152 RefactoringStatus result= new RefactoringStatus();
155 fAnalyzer= new SurroundWithTryCatchAnalyzer(fCUnit, fSelection);
156 fAnalyzer.generated_7479066886286290470(this, result);
161 * @see Refactoring#checkActivation(IProgressMonitor)
164 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
165 CompilationUnit rootNode= new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(fCUnit, true, pm);
166 return checkActivationBasics(rootNode);
170 * @see Refactoring#checkInput(IProgressMonitor)
173 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
174 return Checks.validateModifiesFiles(
175 ResourceUtil.getFiles(new ICompilationUnit[]{fCUnit}),
176 getValidationContext());
180 * @see IRefactoring#createChange(IProgressMonitor)
183 public Change createChange(IProgressMonitor pm) throws CoreException {
184 final String NN= ""; //$NON-NLS-1$
185 if (pm == null) pm= new NullProgressMonitor();
188 final CompilationUnitChange result= new CompilationUnitChange(getName(), fCUnit);
190 result.setSaveMode(TextFileChange.LEAVE_DIRTY);
191 MultiTextEdit root= new MultiTextEdit();
192 result.setEdit(root);
193 fRewriter= ASTRewrite.create(fAnalyzer.getEnclosingBodyDeclaration().getAST());
194 fRewriter.setTargetSourceRangeComputer(new SelectionAwareSourceRangeComputer(
195 fAnalyzer.getSelectedNodes(), fCUnit.getBuffer(), fSelection.getOffset(), fSelection.getLength()));
196 fImportRewrite= StubUtility.createImportRewrite(fRootNode, true);
198 fLinkedProposalModel= new LinkedProposalModel();
200 fSelection.generated_2065815249264639501(this);
202 fSelectedNodes= fAnalyzer.getSelectedNodes();
204 createTryCatchStatement(fCUnit.getBuffer(), fCUnit.findRecommendedLineSeparator());
206 if (fImportRewrite.hasRecordedChanges()) {
207 TextEdit edit= fImportRewrite.rewriteImports(null);
209 result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {edit} ));
211 TextEdit change= fRewriter.rewriteAST();
212 root.addChild(change);
213 result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {change} ));
220 public AST getAST() {
221 return fRootNode.getAST();
224 private void createTryCatchStatement(org.eclipse.jdt.core.IBuffer buffer, String lineDelimiter) throws CoreException {
225 List<Statement> result= new ArrayList<Statement>(1);
226 TryStatement tryStatement= getAST().newTryStatement();
227 ITypeBinding[] exceptions= fAnalyzer.getExceptions();
228 ImportRewriteContext context= new ContextSensitiveImportRewriteContext(fAnalyzer.getEnclosingBodyDeclaration(), fImportRewrite);
230 if (!fIsMultiCatch) {
231 for (int i= 0; i < exceptions.length; i++) {
232 ITypeBinding exception= exceptions[i];
233 String type= fImportRewrite.addImport(exception, context);
234 CatchClause catchClause= getAST().newCatchClause();
235 tryStatement.catchClauses().add(catchClause);
236 SingleVariableDeclaration decl= getAST().newSingleVariableDeclaration();
237 String varName= StubUtility.getExceptionVariableName(fCUnit.getJavaProject());
239 String name= fScope.createName(varName, false);
240 decl.setName(getAST().newSimpleName(name));
241 decl.setType(ASTNodeFactory.newType(getAST(), type));
242 catchClause.setException(decl);
243 Statement st= getCatchBody(type, name, lineDelimiter);
245 catchClause.getBody().statements().add(st);
247 fLinkedProposalModel.getPositionGroup(GROUP_EXC_TYPE + i, true).addPosition(fRewriter.track(decl.getType()), i == 0);
248 fLinkedProposalModel.getPositionGroup(GROUP_EXC_NAME + i, true).addPosition(fRewriter.track(decl.getName()), false);
251 CatchClause catchClause= fLinkedProposalModel.generated_5253206075739856667(this, lineDelimiter, exceptions, context);
252 tryStatement.catchClauses().add(catchClause);
254 List<ASTNode> variableDeclarations= getSpecialVariableDeclarationStatements();
255 ListRewrite statements= fRewriter.getListRewrite(tryStatement.getBody(), Block.STATEMENTS_PROPERTY);
256 boolean selectedNodeRemoved= false;
257 ASTNode expressionStatement= null;
258 for (int i= 0; i < fSelectedNodes.length; i++) {
259 ASTNode node= fSelectedNodes[i];
260 if (node instanceof VariableDeclarationStatement && variableDeclarations.contains(node)) {
262 VariableDeclarationStatement statement= (VariableDeclarationStatement)node;
263 // Create a copy and remove the initializer
264 VariableDeclarationStatement copy= (VariableDeclarationStatement)ASTNode.copySubtree(ast, statement);
265 List<IExtendedModifier> modifiers= copy.modifiers();
266 for (Iterator<IExtendedModifier> iter= modifiers.iterator(); iter.hasNext();) {
267 IExtendedModifier modifier= iter.next();
268 if (modifier.isModifier() && Modifier.isFinal(((Modifier)modifier).getKeyword().toFlagValue())) {
272 List<VariableDeclarationFragment> fragments= copy.fragments();
273 for (Iterator<VariableDeclarationFragment> iter= fragments.iterator(); iter.hasNext();) {
274 VariableDeclarationFragment fragment= iter.next();
275 fragment.setInitializer(null);
277 CompilationUnit root= (CompilationUnit)statement.getRoot();
278 int extendedStart= root.getExtendedStartPosition(statement);
279 // we have a leading comment and the comment is covered by the selection
280 if (extendedStart != statement.getStartPosition() && extendedStart >= fSelection.getOffset()) {
281 String commentToken= buffer.getText(extendedStart, statement.getStartPosition() - extendedStart);
282 commentToken= Strings.trimTrailingTabsAndSpaces(commentToken);
283 Type type= statement.getType();
284 String typeName= buffer.getText(type.getStartPosition(), type.getLength());
285 copy.setType((Type)fRewriter.createStringPlaceholder(commentToken + typeName, type.getNodeType()));
288 // convert the fragments into expression statements
289 fragments= statement.fragments();
290 if (!fragments.isEmpty()) {
291 List<ExpressionStatement> newExpressionStatements= new ArrayList<ExpressionStatement>();
292 for (Iterator<VariableDeclarationFragment> iter= fragments.iterator(); iter.hasNext();) {
293 VariableDeclarationFragment fragment= iter.next();
294 Expression initializer= fragment.getInitializer();
295 if (initializer != null) {
296 Assignment assignment= ast.newAssignment();
297 assignment.setLeftHandSide((Expression)fRewriter.createCopyTarget(fragment.getName()));
298 assignment.setRightHandSide((Expression)fRewriter.createCopyTarget(initializer));
299 newExpressionStatements.add(ast.newExpressionStatement(assignment));
302 if (!newExpressionStatements.isEmpty()) {
303 if (fSelectedNodes.length == 1) {
304 expressionStatement= fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()]));
308 fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])),
312 fRewriter.remove(statement, null);
313 selectedNodeRemoved= true;
316 fRewriter.remove(statement, null);
317 selectedNodeRemoved= true;
321 result.add(tryStatement);
322 ASTNode replacementNode;
323 if (result.size() == 1) {
324 replacementNode= result.get(0);
326 replacementNode= fRewriter.createGroupNode(result.toArray(new ASTNode[result.size()]));
328 if (fSelectedNodes.length == 1) {
329 if (expressionStatement != null) {
330 statements.insertLast(expressionStatement, null);
332 if (!selectedNodeRemoved)
333 statements.insertLast(fRewriter.createMoveTarget(fSelectedNodes[0]), null);
335 fRewriter.replace(fSelectedNodes[0], replacementNode, null);
337 ListRewrite source= fRewriter.getListRewrite(
338 fSelectedNodes[0].getParent(),
339 (ChildListPropertyDescriptor)fSelectedNodes[0].getLocationInParent());
340 ASTNode toMove= source.createMoveTarget(
341 fSelectedNodes[0], fSelectedNodes[fSelectedNodes.length - 1],
342 replacementNode, null);
343 statements.insertLast(toMove, null);
347 private List<ASTNode> getSpecialVariableDeclarationStatements() {
348 List<ASTNode> result= new ArrayList<ASTNode>(3);
349 VariableDeclaration[] locals= fAnalyzer.getAffectedLocals();
350 for (int i= 0; i < locals.length; i++) {
351 ASTNode parent= locals[i].getParent();
352 if (parent instanceof VariableDeclarationStatement && !result.contains(parent))
359 public Statement getCatchBody(String type, String name, String lineSeparator) throws CoreException {
360 String s= StubUtility.getCatchBodyContent(fCUnit, type, name, fSelectedNodes[0], lineSeparator);
364 return (Statement)fRewriter.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);