]> git.uio.no Git - ifi-stolz-refaktor.git/blob - case-study/jdt-after/core refactoring/org/eclipse/jdt/internal/corext/refactoring/surround/SurroundWithTryCatchRefactoring.java
Case Study: adding data and statistics
[ifi-stolz-refaktor.git] / case-study / jdt-after / core refactoring / org / eclipse / jdt / internal / corext / refactoring / surround / SurroundWithTryCatchRefactoring.java
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
7  *
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.corext.refactoring.surround;
12
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16
17 import org.eclipse.core.runtime.CoreException;
18 import org.eclipse.core.runtime.IProgressMonitor;
19 import org.eclipse.core.runtime.NullProgressMonitor;
20
21 import org.eclipse.text.edits.MultiTextEdit;
22 import org.eclipse.text.edits.TextEdit;
23 import org.eclipse.text.edits.TextEditGroup;
24
25 import org.eclipse.jface.text.ITextSelection;
26
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;
31
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;
57
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;
70
71 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
72
73 /**
74  * Surround a set of statements with a try/catch block or a try/multi-catch block.
75  *
76  * Special case:
77  *
78  * URL url= file.toURL();
79  *
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.
84  */
85 public class SurroundWithTryCatchRefactoring extends Refactoring {
86
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$
89
90         public Selection fSelection;
91         public SurroundWithTryCatchAnalyzer fAnalyzer;
92         private boolean fLeaveDirty;
93
94         public ICompilationUnit fCUnit;
95         CompilationUnit fRootNode;
96         public ASTRewrite fRewriter;
97         public ImportRewrite fImportRewrite;
98         public CodeScopeBuilder.Scope fScope;
99         private ASTNode[] fSelectedNodes;
100
101         public LinkedProposalModel fLinkedProposalModel;
102
103         final boolean fIsMultiCatch;
104
105         private SurroundWithTryCatchRefactoring(ICompilationUnit cu, Selection selection, boolean isMultiCatch) {
106                 fCUnit= cu;
107                 fSelection= selection;
108                 fIsMultiCatch= isMultiCatch;
109                 fLeaveDirty= false;
110         }
111
112         public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, ITextSelection selection) {
113                 return create(cu, selection, false);
114         }
115
116         public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, int offset, int length) {
117                 return create(cu, offset, length, false);
118         }
119
120         public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, ITextSelection selection, boolean isMultiCatch) {
121                 return new SurroundWithTryCatchRefactoring(cu, Selection.createFromStartLength(selection.getOffset(), selection.getLength()), isMultiCatch);
122         }
123
124         public static SurroundWithTryCatchRefactoring create(ICompilationUnit cu, int offset, int length, boolean isMultiCatch) {
125                 return new SurroundWithTryCatchRefactoring(cu, Selection.createFromStartLength(offset, length), isMultiCatch);
126         }
127
128         public LinkedProposalModel getLinkedProposalModel() {
129                 return fLinkedProposalModel;
130         }
131
132         public void setLeaveDirty(boolean leaveDirty) {
133                 fLeaveDirty= leaveDirty;
134         }
135
136         public boolean stopExecution() {
137                 if (fAnalyzer == null)
138                         return true;
139                 ITypeBinding[] exceptions= fAnalyzer.getExceptions();
140                 return exceptions == null || exceptions.length == 0;
141         }
142
143         /* non Java-doc
144          * @see IRefactoring#getName()
145          */
146         @Override
147         public String getName() {
148                 return RefactoringCoreMessages.SurroundWithTryCatchRefactoring_name;
149         }
150
151         public RefactoringStatus checkActivationBasics(CompilationUnit rootNode) throws CoreException {
152                 RefactoringStatus result= new RefactoringStatus();
153                 fRootNode= rootNode;
154
155                 fAnalyzer= new SurroundWithTryCatchAnalyzer(fCUnit, fSelection);
156                 fAnalyzer.generated_7479066886286290470(this, result);
157                 return result;
158         }
159
160         /*
161          * @see Refactoring#checkActivation(IProgressMonitor)
162          */
163         @Override
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);
167         }
168
169         /*
170          * @see Refactoring#checkInput(IProgressMonitor)
171          */
172         @Override
173         public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
174                 return Checks.validateModifiesFiles(
175                         ResourceUtil.getFiles(new ICompilationUnit[]{fCUnit}),
176                         getValidationContext());
177         }
178
179         /* non Java-doc
180          * @see IRefactoring#createChange(IProgressMonitor)
181          */
182         @Override
183         public Change createChange(IProgressMonitor pm) throws CoreException {
184                 final String NN= ""; //$NON-NLS-1$
185                 if (pm == null) pm= new NullProgressMonitor();
186                 pm.beginTask(NN, 2);
187                 try {
188                         final CompilationUnitChange result= new CompilationUnitChange(getName(), fCUnit);
189                         if (fLeaveDirty)
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);
197
198                         fLinkedProposalModel= new LinkedProposalModel();
199
200                         fSelection.generated_2065815249264639501(this);
201
202                         fSelectedNodes= fAnalyzer.getSelectedNodes();
203
204                         createTryCatchStatement(fCUnit.getBuffer(), fCUnit.findRecommendedLineSeparator());
205
206                         if (fImportRewrite.hasRecordedChanges()) {
207                                 TextEdit edit= fImportRewrite.rewriteImports(null);
208                                 root.addChild(edit);
209                                 result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {edit} ));
210                         }
211                         TextEdit change= fRewriter.rewriteAST();
212                         root.addChild(change);
213                         result.addTextEditGroup(new TextEditGroup(NN, new TextEdit[] {change} ));
214                         return result;
215                 } finally {
216                         pm.done();
217                 }
218         }
219
220         public AST getAST() {
221                 return fRootNode.getAST();
222         }
223
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);
229
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());
238
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);
244                                 if (st != null) {
245                                         catchClause.getBody().statements().add(st);
246                                 }
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);
249                         }
250                 } else {
251                         CatchClause catchClause= fLinkedProposalModel.generated_5253206075739856667(this, lineDelimiter, exceptions, context);
252                         tryStatement.catchClauses().add(catchClause);
253                 }
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)) {
261                                 AST ast= getAST();
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())) {
269                                                 iter.remove();
270                                         }
271                                 }
272                                 List<VariableDeclarationFragment> fragments= copy.fragments();
273                                 for (Iterator<VariableDeclarationFragment> iter= fragments.iterator(); iter.hasNext();) {
274                                         VariableDeclarationFragment fragment= iter.next();
275                                         fragment.setInitializer(null);
276                                 }
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()));
286                                 }
287                                 result.add(copy);
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));
300                                                 }
301                                         }
302                                         if (!newExpressionStatements.isEmpty()) {
303                                                 if (fSelectedNodes.length == 1) {
304                                                         expressionStatement= fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()]));
305                                                 } else {
306                                                         fRewriter.replace(
307                                                                 statement,
308                                                                 fRewriter.createGroupNode(newExpressionStatements.toArray(new ASTNode[newExpressionStatements.size()])),
309                                                                 null);
310                                                 }
311                                         } else {
312                                                 fRewriter.remove(statement, null);
313                                                 selectedNodeRemoved= true;
314                                         }
315                                 } else {
316                                         fRewriter.remove(statement, null);
317                                         selectedNodeRemoved= true;
318                                 }
319                         }
320                 }
321                 result.add(tryStatement);
322                 ASTNode replacementNode;
323                 if (result.size() == 1) {
324                         replacementNode= result.get(0);
325                 } else {
326                         replacementNode= fRewriter.createGroupNode(result.toArray(new ASTNode[result.size()]));
327                 }
328                 if (fSelectedNodes.length == 1) {
329                         if (expressionStatement != null) {
330                                 statements.insertLast(expressionStatement, null);
331                         } else {
332                                 if (!selectedNodeRemoved)
333                                         statements.insertLast(fRewriter.createMoveTarget(fSelectedNodes[0]), null);
334                         }
335                         fRewriter.replace(fSelectedNodes[0], replacementNode, null);
336                 } else {
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);
344                 }
345         }
346
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))
353                                 result.add(parent);
354                 }
355                 return result;
356
357         }
358
359         public Statement getCatchBody(String type, String name, String lineSeparator) throws CoreException {
360                 String s= StubUtility.getCatchBodyContent(fCUnit, type, name, fSelectedNodes[0], lineSeparator);
361                 if (s == null) {
362                         return null;
363                 } else {
364                         return (Statement)fRewriter.createStringPlaceholder(s, ASTNode.RETURN_STATEMENT);
365                 }
366         }
367 }