]> git.uio.no Git - ifi-stolz-refaktor.git/blob - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/refactorings/ExtractTempWithAssertsRefactoring.java
now works, getAssert as its own method
[ifi-stolz-refaktor.git] / software / no.uio.ifi.refaktor / src / no / uio / ifi / refaktor / refactorings / ExtractTempWithAssertsRefactoring.java
1 package no.uio.ifi.refaktor.refactorings;
2
3 import java.util.ArrayList;
4 import java.util.Arrays;
5 import java.util.Collection;
6 import java.util.Collections;
7 import java.util.Comparator;
8 import java.util.HashMap;
9 import java.util.HashSet;
10 import java.util.Iterator;
11 import java.util.List;
12 import java.util.Map;
13 import java.util.StringTokenizer;
14
15 import org.eclipse.core.runtime.Assert;
16 import org.eclipse.core.runtime.CoreException;
17 import org.eclipse.core.runtime.IProgressMonitor;
18 import org.eclipse.core.runtime.NullProgressMonitor;
19 import org.eclipse.core.runtime.SubProgressMonitor;
20
21 import org.eclipse.text.edits.TextEditGroup;
22
23 import org.eclipse.ltk.core.refactoring.Change;
24 import org.eclipse.ltk.core.refactoring.Refactoring;
25 import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
26 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
27 import org.eclipse.ltk.core.refactoring.RefactoringStatus;
28 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
29
30 import org.eclipse.jdt.core.ICompilationUnit;
31 import org.eclipse.jdt.core.IJavaElement;
32 import org.eclipse.jdt.core.IJavaProject;
33 import org.eclipse.jdt.core.JavaModelException;
34 import org.eclipse.jdt.core.NamingConventions;
35 import org.eclipse.jdt.core.SourceRange;
36 import org.eclipse.jdt.core.compiler.IProblem;
37 import org.eclipse.jdt.core.dom.AST;
38 import org.eclipse.jdt.core.dom.ASTNode;
39 import org.eclipse.jdt.core.dom.ASTVisitor;
40 import org.eclipse.jdt.core.dom.Annotation;
41 import org.eclipse.jdt.core.dom.ArrayInitializer;
42 import org.eclipse.jdt.core.dom.AssertStatement;
43 import org.eclipse.jdt.core.dom.Assignment;
44 import org.eclipse.jdt.core.dom.Block;
45 import org.eclipse.jdt.core.dom.BodyDeclaration;
46 import org.eclipse.jdt.core.dom.CastExpression;
47 import org.eclipse.jdt.core.dom.CatchClause;
48 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
49 import org.eclipse.jdt.core.dom.ClassInstanceCreation;
50 import org.eclipse.jdt.core.dom.CompilationUnit;
51 import org.eclipse.jdt.core.dom.ConstructorInvocation;
52 import org.eclipse.jdt.core.dom.DoStatement;
53 import org.eclipse.jdt.core.dom.EnhancedForStatement;
54 import org.eclipse.jdt.core.dom.Expression;
55 import org.eclipse.jdt.core.dom.ExpressionStatement;
56 import org.eclipse.jdt.core.dom.FieldAccess;
57 import org.eclipse.jdt.core.dom.ForStatement;
58 import org.eclipse.jdt.core.dom.IBinding;
59 import org.eclipse.jdt.core.dom.IMethodBinding;
60 import org.eclipse.jdt.core.dom.ITypeBinding;
61 import org.eclipse.jdt.core.dom.IVariableBinding;
62 import org.eclipse.jdt.core.dom.IfStatement;
63 import org.eclipse.jdt.core.dom.InfixExpression;
64 import org.eclipse.jdt.core.dom.Initializer;
65 import org.eclipse.jdt.core.dom.LambdaExpression;
66 import org.eclipse.jdt.core.dom.MethodDeclaration;
67 import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
68 import org.eclipse.jdt.core.dom.Name;
69 import org.eclipse.jdt.core.dom.NullLiteral;
70 import org.eclipse.jdt.core.dom.ParenthesizedExpression;
71 import org.eclipse.jdt.core.dom.PostfixExpression;
72 import org.eclipse.jdt.core.dom.PrefixExpression;
73 import org.eclipse.jdt.core.dom.QualifiedName;
74 import org.eclipse.jdt.core.dom.ReturnStatement;
75 import org.eclipse.jdt.core.dom.SimpleName;
76 import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
77 import org.eclipse.jdt.core.dom.Statement;
78 import org.eclipse.jdt.core.dom.StringLiteral;
79 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
80 import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
81 import org.eclipse.jdt.core.dom.SwitchCase;
82 import org.eclipse.jdt.core.dom.SwitchStatement;
83 import org.eclipse.jdt.core.dom.TryStatement;
84 import org.eclipse.jdt.core.dom.Type;
85 import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
86 import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
87 import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
88 import org.eclipse.jdt.core.dom.WhileStatement;
89 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
90 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
91 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
92 import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
93 import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
94 import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
95 import org.eclipse.jdt.core.refactoring.descriptors.ExtractLocalDescriptor;
96
97 import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
98 import org.eclipse.jdt.internal.corext.Corext;
99 import org.eclipse.jdt.internal.corext.SourceRangeFactory;
100 import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
101 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
102 import org.eclipse.jdt.internal.corext.dom.ASTNodes;
103 import org.eclipse.jdt.internal.corext.dom.Bindings;
104 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
105 import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
106 import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment;
107 import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
108 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
109 import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup;
110 import org.eclipse.jdt.internal.corext.refactoring.Checks;
111 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
112 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
113 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
114 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
115 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
116 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext;
117 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
118 import org.eclipse.jdt.internal.corext.refactoring.code.CodeRefactoringUtil;
119 import org.eclipse.jdt.internal.corext.refactoring.code.ExtractTempRefactoring;
120 import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringAnalyzeUtil;
121 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
122 import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer;
123 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
124 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
125 import org.eclipse.jdt.internal.corext.util.Messages;
126
127 import org.eclipse.jdt.ui.JavaElementLabels;
128
129 import org.eclipse.jdt.internal.ui.JavaPlugin;
130 import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
131 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
132 import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
133 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider;
134
135 /**
136  * Extract Local Variable (from selected expression inside method or initializer).
137  * 
138  * @author Anna Eilertsen
139  * 
140  * TODO: Copied from ExtractTemp, will replace unused code with super-calls
141  */
142 public class ExtractTempWithAssertsRefactoring extends ExtractTempRefactoring {
143
144         private static final String ATTRIBUTE_REPLACE= "replace"; //$NON-NLS-1$
145         private static final String ATTRIBUTE_FINAL= "final"; //$NON-NLS-1$
146
147         private static final class ForStatementChecker extends ASTVisitor {
148
149                 private final Collection<IVariableBinding> fForInitializerVariables;
150
151                 private boolean fReferringToForVariable= false;
152
153                 public ForStatementChecker(Collection<IVariableBinding> forInitializerVariables) {
154                         Assert.isNotNull(forInitializerVariables);
155                         fForInitializerVariables= forInitializerVariables;
156                 }
157
158                 public boolean isReferringToForVariable() {
159                         return fReferringToForVariable;
160                 }
161
162                 @Override
163                 public boolean visit(SimpleName node) {
164                         IBinding binding= node.resolveBinding();
165                         if (binding != null && fForInitializerVariables.contains(binding)) {
166                                 fReferringToForVariable= true;
167                         }
168                         return false;
169                 }
170         }
171
172
173
174         private static boolean allArraysEqual(Object[][] arrays, int position) {
175                 Object element= arrays[0][position];
176                 for (int i= 0; i < arrays.length; i++) {
177                         Object[] array= arrays[i];
178                         if (!element.equals(array[position]))
179                                 return false;
180                 }
181                 return true;
182         }
183
184         private static boolean canReplace(IASTFragment fragment) {
185                 ASTNode node= fragment.getAssociatedNode();
186                 ASTNode parent= node.getParent();
187                 if (parent instanceof VariableDeclarationFragment) {
188                         VariableDeclarationFragment vdf= (VariableDeclarationFragment) parent;
189                         if (node.equals(vdf.getName()))
190                                 return false;
191                 }
192                 if (isMethodParameter(node))
193                         return false;
194                 if (isThrowableInCatchBlock(node))
195                         return false;
196                 if (parent instanceof ExpressionStatement)
197                         return false;
198                 if (parent instanceof LambdaExpression)
199                         return false;
200                 if (isLeftValue(node))
201                         return false;
202                 if (isReferringToLocalVariableFromFor((Expression) node))
203                         return false;
204                 if (isUsedInForInitializerOrUpdater((Expression) node))
205                         return false;
206                 if (parent instanceof SwitchCase)
207                         return false;
208                 return true;
209         }
210
211         private static Object[] getArrayPrefix(Object[] array, int prefixLength) {
212                 Assert.isTrue(prefixLength <= array.length);
213                 Assert.isTrue(prefixLength >= 0);
214                 Object[] prefix= new Object[prefixLength];
215                 for (int i= 0; i < prefix.length; i++) {
216                         prefix[i]= array[i];
217                 }
218                 return prefix;
219         }
220
221         // return List<IVariableBinding>
222         private static List<IVariableBinding> getForInitializedVariables(VariableDeclarationExpression variableDeclarations) {
223                 List<IVariableBinding> forInitializerVariables= new ArrayList<IVariableBinding>(1);
224                 for (Iterator<VariableDeclarationFragment> iter= variableDeclarations.fragments().iterator(); iter.hasNext();) {
225                         VariableDeclarationFragment fragment= iter.next();
226                         IVariableBinding binding= fragment.resolveBinding();
227                         if (binding != null)
228                                 forInitializerVariables.add(binding);
229                 }
230                 return forInitializerVariables;
231         }
232
233         private static Object[] getLongestArrayPrefix(Object[][] arrays) {
234                 int length= -1;
235                 if (arrays.length == 0)
236                         return new Object[0];
237                 int minArrayLength= arrays[0].length;
238                 for (int i= 1; i < arrays.length; i++)
239                         minArrayLength= Math.min(minArrayLength, arrays[i].length);
240
241                 for (int i= 0; i < minArrayLength; i++) {
242                         if (!allArraysEqual(arrays, i))
243                                 break;
244                         length++;
245                 }
246                 if (length == -1)
247                         return new Object[0];
248                 return getArrayPrefix(arrays[0], length + 1);
249         }
250
251         private static ASTNode[] getParents(ASTNode node) {
252                 ASTNode current= node;
253                 List<ASTNode> parents= new ArrayList<ASTNode>();
254                 do {
255                         parents.add(current.getParent());
256                         current= current.getParent();
257                 } while (current.getParent() != null);
258                 Collections.reverse(parents);
259                 return parents.toArray(new ASTNode[parents.size()]);
260         }
261
262         private static boolean isLeftValue(ASTNode node) {
263                 ASTNode parent= node.getParent();
264                 if (parent instanceof Assignment) {
265                         Assignment assignment= (Assignment) parent;
266                         if (assignment.getLeftHandSide() == node)
267                                 return true;
268                 }
269                 if (parent instanceof PostfixExpression)
270                         return true;
271                 if (parent instanceof PrefixExpression) {
272                         PrefixExpression.Operator op= ((PrefixExpression) parent).getOperator();
273                         if (op.equals(PrefixExpression.Operator.DECREMENT))
274                                 return true;
275                         if (op.equals(PrefixExpression.Operator.INCREMENT))
276                                 return true;
277                         return false;
278                 }
279                 return false;
280         }
281
282         private static boolean isMethodParameter(ASTNode node) {
283                 return (node instanceof SimpleName) && (node.getParent() instanceof SingleVariableDeclaration) && (node.getParent().getParent() instanceof MethodDeclaration);
284         }
285
286         private static boolean isReferringToLocalVariableFromFor(Expression expression) {
287                 ASTNode current= expression;
288                 ASTNode parent= current.getParent();
289                 while (parent != null && !(parent instanceof BodyDeclaration)) {
290                         if (parent instanceof ForStatement) {
291                                 ForStatement forStmt= (ForStatement) parent;
292                                 if (forStmt.initializers().contains(current) || forStmt.updaters().contains(current) || forStmt.getExpression() == current) {
293                                         List<Expression> initializers= forStmt.initializers();
294                                         if (initializers.size() == 1 && initializers.get(0) instanceof VariableDeclarationExpression) {
295                                                 List<IVariableBinding> forInitializerVariables= getForInitializedVariables((VariableDeclarationExpression) initializers.get(0));
296                                                 ForStatementChecker checker= new ForStatementChecker(forInitializerVariables);
297                                                 expression.accept(checker);
298                                                 if (checker.isReferringToForVariable())
299                                                         return true;
300                                         }
301                                 }
302                         }
303                         current= parent;
304                         parent= current.getParent();
305                 }
306                 return false;
307         }
308
309         private static boolean isThrowableInCatchBlock(ASTNode node) {
310                 return (node instanceof SimpleName) && (node.getParent() instanceof SingleVariableDeclaration) && (node.getParent().getParent() instanceof CatchClause);
311         }
312
313         private static boolean isUsedInForInitializerOrUpdater(Expression expression) {
314                 ASTNode parent= expression.getParent();
315                 if (parent instanceof ForStatement) {
316                         ForStatement forStmt= (ForStatement) parent;
317                         return forStmt.initializers().contains(expression) || forStmt.updaters().contains(expression);
318                 }
319                 return false;
320         }
321
322         private static IASTFragment[] retainOnlyReplacableMatches(IASTFragment[] allMatches) {
323                 List<IASTFragment> result= new ArrayList<IASTFragment>(allMatches.length);
324                 for (int i= 0; i < allMatches.length; i++) {
325                         if (canReplace(allMatches[i]))
326                                 result.add(allMatches[i]);
327                 }
328                 return result.toArray(new IASTFragment[result.size()]);
329         }
330
331         private CompilationUnit fCompilationUnitNode;
332
333         private CompilationUnitRewrite fCURewrite;
334
335         private ICompilationUnit fCu;
336
337         private boolean fDeclareFinal;
338
339         private String[] fExcludedVariableNames;
340
341         private boolean fReplaceAllOccurrences;
342
343         // caches:
344         private IExpressionFragment fSelectedExpression;
345
346         private int fSelectionLength;
347
348         private int fSelectionStart;
349
350         private String fTempName;
351         private String[] fGuessedTempNames;
352
353         private boolean fCheckResultForCompileProblems;
354
355         private CompilationUnitChange fChange;
356
357         private LinkedProposalModel fLinkedProposalModel;
358         private MethodDeclaration methodDeclaration;
359         private String fSelectedText;
360
361         private static final String KEY_NAME= "name"; //$NON-NLS-1$
362         private static final String KEY_TYPE= "type"; //$NON-NLS-1$
363
364
365         /**
366          * Creates a new extract temp refactoring
367          * @param unit the compilation unit, or <code>null</code> if invoked by scripting
368          * @param selectionStart start of selection
369          * @param selectionLength length of selection
370          * @param string 
371          */
372         public ExtractTempWithAssertsRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength, String selectedText) {
373                 super(unit, selectionStart, selectionLength);
374                 Assert.isTrue(selectionStart >= 0);
375                 Assert.isTrue(selectionLength >= 0);
376                 fSelectionStart= selectionStart;
377                 fSelectionLength= selectionLength;
378                 fSelectedText = selectedText;
379                 fCu= unit;
380                 fCompilationUnitNode= null;
381
382                 fReplaceAllOccurrences= true; // default
383                 fDeclareFinal= false; // default
384                 fTempName= ""; //$NON-NLS-1$
385
386                 fLinkedProposalModel= null;
387                 fCheckResultForCompileProblems= true;
388         }
389
390         public ExtractTempWithAssertsRefactoring(CompilationUnit astRoot, int selectionStart, int selectionLength) {
391                 super(astRoot, selectionStart, selectionLength);
392                 Assert.isTrue(selectionStart >= 0);
393                 Assert.isTrue(selectionLength >= 0);
394                 Assert.isTrue(astRoot.getTypeRoot() instanceof ICompilationUnit);
395
396                 fSelectionStart= selectionStart;
397                 fSelectionLength= selectionLength;
398                 fCu= (ICompilationUnit) astRoot.getTypeRoot();
399                 fCompilationUnitNode= astRoot;
400
401                 fReplaceAllOccurrences= true; // default
402                 fDeclareFinal= false; // default
403                 fTempName= ""; //$NON-NLS-1$
404
405                 fLinkedProposalModel= null;
406                 fCheckResultForCompileProblems= true;
407         }
408
409 //    public ExtractTempWithAssertsRefactoring(JavaRefactoringArguments arguments, RefactoringStatus status) {
410 //              this((ICompilationUnit) null, 0, 0);
411 //              RefactoringStatus initializeStatus= initialize(arguments);
412 //              status.merge(initializeStatus);
413 //    }
414
415         public void setCheckResultForCompileProblems(boolean checkResultForCompileProblems) {
416                 fCheckResultForCompileProblems= checkResultForCompileProblems;
417         }
418
419
420         public void setLinkedProposalModel(LinkedProposalModel linkedProposalModel) {
421                 fLinkedProposalModel= linkedProposalModel;
422         }
423
424         private void addReplaceExpressionWithTemp() throws JavaModelException {
425                 IASTFragment[] fragmentsToReplace= retainOnlyReplacableMatches(getMatchingFragments());
426                 //TODO: should not have to prune duplicates here...
427                 ASTRewrite rewrite= fCURewrite.getASTRewrite();
428                 HashSet<IASTFragment> seen= new HashSet<IASTFragment>();
429                 for (int i= 0; i < fragmentsToReplace.length; i++) {
430                         IASTFragment fragment= fragmentsToReplace[i];
431                         if (! seen.add(fragment))
432                                 continue;
433                         SimpleName tempName= fCURewrite.getAST().newSimpleName(fTempName);
434                         TextEditGroup description= fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_replace);
435
436
437                 
438
439                         /*
440                          * Anna's hacky code from here
441                          */
442
443                         //TODO: some clever way of iterating over parents?
444                         ASTNode associatedNode = fragment.getAssociatedNode().getParent().getParent();
445                         
446                         //For debugging (do this with a while loop later)
447                         Object a1 = fragment.getAssociatedNode();
448                         Object a = fragment.getAssociatedNode().getClass();
449                         Object b1 = fragment.getAssociatedNode().getParent();
450                         Object b = fragment.getAssociatedNode().getParent().getClass();
451                         Object c1 = fragment.getAssociatedNode().getParent().getParent();
452                         Object c = fragment.getAssociatedNode().getParent().getParent().getClass();
453                         ASTNode d1 = fragment.getAssociatedNode().getParent().getParent();
454                         Object d = fragment.getAssociatedNode().getParent().getParent().getClass();
455                         ASTNode block1 = fragment.getAssociatedNode().getParent().getParent().getParent();
456                         Object blockClass = fragment.getAssociatedNode().getParent().getParent().getParent().getClass();
457
458                         
459                         AST ast = block1.getAST();
460                         
461                         ASTRewrite ASTRewriteStmt = ASTRewrite.create(ast);
462                         //ListRewrite lr = ASTRewriteStmt.getListRewrite(block1, Block.STATEMENTS_PROPERTY);
463                         ListRewrite lr = rewrite.getListRewrite(block1, Block.STATEMENTS_PROPERTY);
464                         List<ASTNode> ls = lr.getOriginalList();
465                         ASTNode first = ls.get(0);
466                         
467                         boolean check = first == d1;
468                         
469                         lr.insertBefore(getAssertStatement(ast), d1, null);
470                         
471                         //ASTRewriteStmt.rewriteAST(fCompilationUnitNode, null).apply(fCompilationUnitNode);
472                         
473                         /*
474                          * Eclipse code from here 
475                          */
476                         fragment.replace(rewrite, tempName, description);
477                         
478                         if (fLinkedProposalModel != null)
479                                 fLinkedProposalModel.getPositionGroup(KEY_NAME, true).addPosition(rewrite.track(tempName), false);
480                 }
481         }
482         
483         private Statement getAssertStatement(AST ast){
484                 //Make the assertion
485                 AssertStatement assertStatement = ast.newAssertStatement();
486                 InfixExpression infixExpression = ast.newInfixExpression();
487         
488                 infixExpression.setLeftOperand(ast.newSimpleName(fTempName));
489                 infixExpression.setOperator(InfixExpression.Operator.EQUALS);
490                 
491                 infixExpression.setRightOperand(ast.newName(fSelectedText)); 
492                 assertStatement.setExpression(infixExpression);
493                 StringLiteral stringLiteral = ast.newStringLiteral();
494                 stringLiteral.setLiteralValue("The Move Method refactoring has broken the program due to aliasing issues!");
495                 assertStatement.setMessage(stringLiteral);              
496                 return assertStatement;
497         }
498
499         private RefactoringStatus checkExpression() throws JavaModelException {
500                 Expression selectedExpression= getSelectedExpression().getAssociatedExpression();
501                 if (selectedExpression != null) {
502                         final ASTNode parent= selectedExpression.getParent();
503                         if (selectedExpression instanceof NullLiteral) {
504                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_null_literals);
505                         } else if (selectedExpression instanceof ArrayInitializer) {
506                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_array_initializer);
507                         } else if (selectedExpression instanceof Assignment) {
508                                 if (parent instanceof Expression && !(parent instanceof ParenthesizedExpression))
509                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_assignment);
510                                 else
511                                         return null;
512                         } else if (selectedExpression instanceof SimpleName) {
513                                 if ((((SimpleName) selectedExpression)).isDeclaration())
514                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_names_in_declarations);
515                                 if (parent instanceof QualifiedName && selectedExpression.getLocationInParent() == QualifiedName.NAME_PROPERTY || parent instanceof FieldAccess && selectedExpression.getLocationInParent() == FieldAccess.NAME_PROPERTY)
516                                         return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_select_expression);
517                         } else if (selectedExpression instanceof VariableDeclarationExpression && parent instanceof TryStatement) {
518                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_resource_in_try_with_resources);
519                         }
520                 }
521
522                 return null;
523         }
524
525         // !! Same as in ExtractConstantRefactoring
526         private RefactoringStatus checkExpressionFragmentIsRValue() throws JavaModelException {
527                 switch (Checks.checkExpressionIsRValue(getSelectedExpression().getAssociatedExpression())) {
528                         case Checks.NOT_RVALUE_MISC:
529                                 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractTempRefactoring_select_expression, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE, null);
530                         case Checks.NOT_RVALUE_VOID:
531                                 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractTempRefactoring_no_void, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID, null);
532                         case Checks.IS_RVALUE_GUESSED:
533                         case Checks.IS_RVALUE:
534                                 return new RefactoringStatus();
535                         default:
536                                 Assert.isTrue(false);
537                                 return null;
538                 }
539         }
540
541         private ITypeBinding guessBindingForReference(Expression expression) {
542                 ITypeBinding binding= expression.resolveTypeBinding();
543                 if (binding == null) {
544                         binding= ASTResolving.guessBindingForReference(expression);
545                 }
546                 return binding;
547         }
548
549         @Override
550         public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
551                 try {
552                         pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 4);
553
554                         fCURewrite= new CompilationUnitRewrite(fCu, fCompilationUnitNode);
555                         fCURewrite.getASTRewrite().setTargetSourceRangeComputer(new NoCommentSourceRangeComputer());
556
557                         doCreateChange(new SubProgressMonitor(pm, 2));
558
559                         fChange= fCURewrite.createChange(RefactoringCoreMessages.ExtractTempRefactoring_change_name, true, new SubProgressMonitor(pm, 1));
560
561                         RefactoringStatus result= new RefactoringStatus();
562                         if (Arrays.asList(getExcludedVariableNames()).contains(fTempName))
563                                 result.addWarning(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable, BasicElementLabels.getJavaElementName(fTempName)));
564
565                         result.merge(checkMatchingFragments());
566
567                         fChange.setKeepPreviewEdits(true);
568
569                         if (fCheckResultForCompileProblems) {
570                                 checkNewSource(new SubProgressMonitor(pm, 1), result);
571                         }
572
573                         return result;
574                 } finally {
575                         pm.done();
576                 }
577         }
578
579         private final ExtractLocalDescriptor createRefactoringDescriptor() {
580                 final Map<String, String> arguments= new HashMap<String, String>();
581                 String project= null;
582                 IJavaProject javaProject= fCu.getJavaProject();
583                 if (javaProject != null)
584                         project= javaProject.getElementName();
585                 final String description= Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description_short, BasicElementLabels.getJavaElementName(fTempName));
586                 final String expression= ASTNodes.asString(fSelectedExpression.getAssociatedExpression());
587                 final String header= Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description, new String[] { BasicElementLabels.getJavaElementName(fTempName), BasicElementLabels.getJavaCodeString(expression)});
588                 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
589                 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_name_pattern, BasicElementLabels.getJavaElementName(fTempName)));
590                 final BodyDeclaration decl= (BodyDeclaration) ASTNodes.getParent(fSelectedExpression.getAssociatedExpression(), BodyDeclaration.class);
591                 if (decl instanceof MethodDeclaration) {
592                         final IMethodBinding method= ((MethodDeclaration) decl).resolveBinding();
593                         final String label= method != null ? BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED) : BasicElementLabels.getJavaElementName('{' + JavaElementLabels.ELLIPSIS_STRING + '}');
594                         comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_destination_pattern, label));
595                 }
596                 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_expression_pattern, BasicElementLabels.getJavaCodeString(expression)));
597                 if (fReplaceAllOccurrences)
598                         comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_replace_occurrences);
599                 if (fDeclareFinal)
600                         comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_declare_final);
601                 final ExtractLocalDescriptor descriptor= RefactoringSignatureDescriptorFactory.createExtractLocalDescriptor(project, description, comment.asString(), arguments, RefactoringDescriptor.NONE);
602                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fCu));
603                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, fTempName);
604                 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION, new Integer(fSelectionStart).toString() + " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$
605                 arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplaceAllOccurrences).toString());
606                 arguments.put(ATTRIBUTE_FINAL, Boolean.valueOf(fDeclareFinal).toString());
607                 return descriptor;
608         }
609
610         private void doCreateChange(IProgressMonitor pm) throws CoreException {
611                 try {
612                         pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 1);
613                         try {
614                                 createTempDeclaration();
615                         } catch (CoreException exception) {
616                                 JavaPlugin.log(exception);
617                         }
618                         addReplaceExpressionWithTemp();
619                 } finally {
620                         pm.done();
621                 }
622         }
623
624         private void checkNewSource(SubProgressMonitor monitor, RefactoringStatus result) throws CoreException {
625                 String newCuSource= fChange.getPreviewContent(new NullProgressMonitor());
626                 CompilationUnit newCUNode= new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(newCuSource, fCu, true, true, monitor);
627                 IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, fCompilationUnitNode);
628                 for (int i= 0; i < newProblems.length; i++) {
629                         IProblem problem= newProblems[i];
630                         if (problem.isError())
631                                 result.addEntry(new RefactoringStatusEntry((problem.isError() ? RefactoringStatus.ERROR : RefactoringStatus.WARNING), problem.getMessage(), new JavaStringStatusContext(newCuSource, SourceRangeFactory.create(problem))));
632                 }
633         }
634
635         @Override
636         public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
637                 try {
638                         pm.beginTask("", 6); //$NON-NLS-1$
639
640                         RefactoringStatus result= Checks.validateModifiesFiles(ResourceUtil.getFiles(new ICompilationUnit[] { fCu}), getValidationContext());
641                         if (result.hasFatalError())
642                                 return result;
643
644                         if (fCompilationUnitNode == null) {
645                                 fCompilationUnitNode= RefactoringASTParser.parseWithASTProvider(fCu, true, new SubProgressMonitor(pm, 3));
646                         } else {
647                                 pm.worked(3);
648                         }
649
650                         result.merge(checkSelection(new SubProgressMonitor(pm, 3)));
651                         if (!result.hasFatalError() && isLiteralNodeSelected())
652                                 fReplaceAllOccurrences= false;
653                         return result;
654
655                 } finally {
656                         pm.done();
657                 }
658         }
659
660         private RefactoringStatus checkMatchingFragments() throws JavaModelException {
661                 RefactoringStatus result= new RefactoringStatus();
662                 IASTFragment[] matchingFragments= getMatchingFragments();
663                 for (int i= 0; i < matchingFragments.length; i++) {
664                         ASTNode node= matchingFragments[i].getAssociatedNode();
665                         if (isLeftValue(node) && !isReferringToLocalVariableFromFor((Expression) node)) {
666                                 String msg= RefactoringCoreMessages.ExtractTempRefactoring_assigned_to;
667                                 result.addWarning(msg, JavaStatusContext.create(fCu, node));
668                         }
669                 }
670                 return result;
671         }
672
673         private RefactoringStatus checkSelection(IProgressMonitor pm) throws JavaModelException {
674                 try {
675                         pm.beginTask("", 8); //$NON-NLS-1$
676
677                         IExpressionFragment selectedExpression= getSelectedExpression();
678
679                         if (selectedExpression == null) {
680                                 String message= RefactoringCoreMessages.ExtractTempRefactoring_select_expression;
681                                 return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, fCompilationUnitNode, message);
682                         }
683                         pm.worked(1);
684
685                         if (isUsedInExplicitConstructorCall())
686                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_explicit_constructor);
687                         pm.worked(1);
688
689                         ASTNode associatedNode= selectedExpression.getAssociatedNode();
690                         if (getEnclosingBodyNode() == null || ASTNodes.getParent(associatedNode, Annotation.class) != null)
691                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_expr_in_method_or_initializer);
692                         pm.worked(1);
693
694                         if (associatedNode instanceof Name && associatedNode.getParent() instanceof ClassInstanceCreation && associatedNode.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY)
695                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_name_in_new);
696                         pm.worked(1);
697
698                         RefactoringStatus result= new RefactoringStatus();
699                         result.merge(checkExpression());
700                         if (result.hasFatalError())
701                                 return result;
702                         pm.worked(1);
703
704                         result.merge(checkExpressionFragmentIsRValue());
705                         if (result.hasFatalError())
706                                 return result;
707                         pm.worked(1);
708
709                         if (isUsedInForInitializerOrUpdater(getSelectedExpression().getAssociatedExpression()))
710                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_for_initializer_updater);
711                         pm.worked(1);
712
713                         if (isReferringToLocalVariableFromFor(getSelectedExpression().getAssociatedExpression()))
714                                 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_refers_to_for_variable);
715                         pm.worked(1);
716
717                         return result;
718                 } finally {
719                         pm.done();
720                 }
721         }
722
723         public RefactoringStatus checkTempName(String newName) {
724                 RefactoringStatus status= Checks.checkTempName(newName, fCu);
725                 if (Arrays.asList(getExcludedVariableNames()).contains(newName))
726                         status.addWarning(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable, BasicElementLabels.getJavaElementName(newName)));
727                 return status;
728         }
729
730         private void createAndInsertTempDeclaration() throws CoreException {
731                 Expression initializer= getSelectedExpression().createCopyTarget(fCURewrite.getASTRewrite(), true);
732                 VariableDeclarationStatement vds= createTempDeclaration(initializer);
733
734                 IASTFragment[] replacableMatches= retainOnlyReplacableMatches(getMatchingFragments());
735                 if (!fReplaceAllOccurrences
736                                 || replacableMatches.length == 0
737                                 || replacableMatches.length == 1 && replacableMatches[0].equals(getSelectedExpression().getAssociatedExpression())) {
738                         insertAt(getSelectedExpression().getAssociatedNode(), vds);
739                         return;
740                 }
741
742                 ASTNode[] firstReplaceNodeParents= getParents(getFirstReplacedExpression().getAssociatedNode());
743                 ASTNode[] commonPath= findDeepestCommonSuperNodePathForReplacedNodes();
744                 Assert.isTrue(commonPath.length <= firstReplaceNodeParents.length);
745
746                 ASTNode deepestCommonParent= firstReplaceNodeParents[commonPath.length - 1];
747                 if (deepestCommonParent instanceof Block)
748                         insertAt(firstReplaceNodeParents[commonPath.length], vds);
749                 else
750                         insertAt(deepestCommonParent, vds);
751         }
752
753         private VariableDeclarationStatement createTempDeclaration(Expression initializer) throws CoreException {
754                 AST ast= fCURewrite.getAST();
755
756                 VariableDeclarationFragment vdf= ast.newVariableDeclarationFragment();
757                 vdf.setName(ast.newSimpleName(fTempName));
758                 vdf.setInitializer(initializer);
759
760                 VariableDeclarationStatement vds= ast.newVariableDeclarationStatement(vdf);
761                 if (fDeclareFinal) {
762                         vds.modifiers().add(ast.newModifier(ModifierKeyword.FINAL_KEYWORD));
763                 }
764                 vds.setType(createTempType());
765
766                 if (fLinkedProposalModel != null) {
767                         ASTRewrite rewrite= fCURewrite.getASTRewrite();
768                         LinkedProposalPositionGroup nameGroup= fLinkedProposalModel.getPositionGroup(KEY_NAME, true);
769                         nameGroup.addPosition(rewrite.track(vdf.getName()), true);
770
771                         String[] nameSuggestions= guessTempNames();
772                         if (nameSuggestions.length > 0 && !nameSuggestions[0].equals(fTempName)) {
773                                 nameGroup.addProposal(fTempName, null, nameSuggestions.length + 1);
774                         }
775                         for (int i= 0; i < nameSuggestions.length; i++) {
776                                 nameGroup.addProposal(nameSuggestions[i], null, nameSuggestions.length - i);
777                         }
778                 }
779                 return vds;
780         }
781
782         private void insertAt(ASTNode target, Statement declaration) {
783                 ASTRewrite rewrite= fCURewrite.getASTRewrite();
784                 TextEditGroup groupDescription= fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable);
785
786                 ASTNode parent= target.getParent();
787                 StructuralPropertyDescriptor locationInParent= target.getLocationInParent();
788                 while (locationInParent != Block.STATEMENTS_PROPERTY && locationInParent != SwitchStatement.STATEMENTS_PROPERTY) {
789                         if (locationInParent == IfStatement.THEN_STATEMENT_PROPERTY
790                                         || locationInParent == IfStatement.ELSE_STATEMENT_PROPERTY
791                                         || locationInParent == ForStatement.BODY_PROPERTY
792                                         || locationInParent == EnhancedForStatement.BODY_PROPERTY
793                                         || locationInParent == DoStatement.BODY_PROPERTY
794                                         || locationInParent == WhileStatement.BODY_PROPERTY) {
795                                 // create intermediate block if target was the body property of a control statement:
796                                 Block replacement= rewrite.getAST().newBlock();
797                                 ListRewrite replacementRewrite= rewrite.getListRewrite(replacement, Block.STATEMENTS_PROPERTY);
798                                 replacementRewrite.insertFirst(declaration, null);
799                                 replacementRewrite.insertLast(rewrite.createMoveTarget(target), null);
800                                 rewrite.replace(target, replacement, groupDescription);
801                                 return;
802                         } else if (locationInParent == LambdaExpression.BODY_PROPERTY && ((LambdaExpression) parent).getBody() instanceof Expression) {
803                                 Block replacement= rewrite.getAST().newBlock();
804                                 ListRewrite replacementRewrite= rewrite.getListRewrite(replacement, Block.STATEMENTS_PROPERTY);
805                                 replacementRewrite.insertFirst(declaration, null);
806                                 ASTNode moveTarget= rewrite.createMoveTarget(target);
807                                 AST ast= rewrite.getAST();
808                                 if (Bindings.isVoidType(((LambdaExpression) parent).resolveMethodBinding().getReturnType())) {
809                                         ExpressionStatement expressionStatement= ast.newExpressionStatement((Expression) moveTarget);
810                                         moveTarget= expressionStatement;
811                                 } else {
812                                         ReturnStatement returnStatement= ast.newReturnStatement();
813                                         returnStatement.setExpression((Expression) moveTarget);
814                                         moveTarget= returnStatement;
815                                 }
816                                 replacementRewrite.insertLast(moveTarget, null);
817                                 rewrite.replace(target, replacement, groupDescription);
818                                 return;
819                         }
820                         target= parent;
821                         parent= parent.getParent();
822                         locationInParent= target.getLocationInParent();
823                 }
824                 ListRewrite listRewrite= rewrite.getListRewrite(parent, (ChildListPropertyDescriptor)locationInParent);
825                 listRewrite.insertBefore(declaration, target, groupDescription);
826         }
827
828         @Override
829         public Change createChange(IProgressMonitor pm) throws CoreException {
830                 try {
831                         pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 1);
832
833                         ExtractLocalDescriptor descriptor= createRefactoringDescriptor();
834                         fChange.setDescriptor(new RefactoringChangeDescriptor(descriptor));
835                         return fChange;
836                 } finally {
837                         pm.done();
838                 }
839         }
840
841         private void createTempDeclaration() throws CoreException {
842                 if (shouldReplaceSelectedExpressionWithTempDeclaration())
843                         replaceSelectedExpressionWithTempDeclaration();
844                 else
845                         createAndInsertTempDeclaration();
846         }
847
848         public boolean declareFinal() {
849                 return fDeclareFinal;
850         }
851
852         private ASTNode[] findDeepestCommonSuperNodePathForReplacedNodes() throws JavaModelException {
853                 ASTNode[] matchNodes= getMatchNodes();
854
855                 ASTNode[][] matchingNodesParents= new ASTNode[matchNodes.length][];
856                 for (int i= 0; i < matchNodes.length; i++) {
857                         matchingNodesParents[i]= getParents(matchNodes[i]);
858                 }
859                 List<Object> l= Arrays.asList(getLongestArrayPrefix(matchingNodesParents));
860                 return l.toArray(new ASTNode[l.size()]);
861         }
862
863         private ASTNode getEnclosingBodyNode() throws JavaModelException {
864                 ASTNode node= getSelectedExpression().getAssociatedNode();
865
866                 // expression must be in a method, lambda or initializer body
867                 // make sure it is not in method or parameter annotation
868                 StructuralPropertyDescriptor location= null;
869                 while (node != null && !(node instanceof BodyDeclaration)) {
870                         location= node.getLocationInParent();
871                         node= node.getParent();
872                         if (node instanceof LambdaExpression) {
873                                 break;
874                         }
875                 }
876                 if (location == MethodDeclaration.BODY_PROPERTY || location == Initializer.BODY_PROPERTY
877                                 || (location == LambdaExpression.BODY_PROPERTY && ((LambdaExpression) node).resolveMethodBinding() != null)) {
878                         return (ASTNode) node.getStructuralProperty(location);
879                 }
880                 return null;
881         }
882
883         private String[] getExcludedVariableNames() {
884                 if (fExcludedVariableNames == null) {
885                         try {
886                                 IBinding[] bindings= new ScopeAnalyzer(fCompilationUnitNode).getDeclarationsInScope(getSelectedExpression().getStartPosition(), ScopeAnalyzer.VARIABLES
887                                                 | ScopeAnalyzer.CHECK_VISIBILITY);
888                                 fExcludedVariableNames= new String[bindings.length];
889                                 for (int i= 0; i < bindings.length; i++) {
890                                         fExcludedVariableNames[i]= bindings[i].getName();
891                                 }
892                         } catch (JavaModelException e) {
893                                 fExcludedVariableNames= new String[0];
894                         }
895                 }
896                 return fExcludedVariableNames;
897         }
898
899         private IExpressionFragment getFirstReplacedExpression() throws JavaModelException {
900                 if (!fReplaceAllOccurrences)
901                         return getSelectedExpression();
902                 IASTFragment[] nodesToReplace= retainOnlyReplacableMatches(getMatchingFragments());
903                 if (nodesToReplace.length == 0)
904                         return getSelectedExpression();
905                 Comparator<IASTFragment> comparator= new Comparator<IASTFragment>() {
906
907                         public int compare(IASTFragment o1, IASTFragment o2) {
908                                 return o1.getStartPosition() - o2.getStartPosition();
909                         }
910                 };
911                 Arrays.sort(nodesToReplace, comparator);
912                 return (IExpressionFragment) nodesToReplace[0];
913         }
914
915         private IASTFragment[] getMatchingFragments() throws JavaModelException {
916                 if (fReplaceAllOccurrences) {
917                         IASTFragment[] allMatches= ASTFragmentFactory.createFragmentForFullSubtree(getEnclosingBodyNode()).getSubFragmentsMatching(getSelectedExpression());
918                         return allMatches;
919                 } else
920                         return new IASTFragment[] { getSelectedExpression()};
921         }
922
923         private ASTNode[] getMatchNodes() throws JavaModelException {
924                 IASTFragment[] matches= retainOnlyReplacableMatches(getMatchingFragments());
925                 ASTNode[] result= new ASTNode[matches.length];
926                 for (int i= 0; i < matches.length; i++)
927                         result[i]= matches[i].getAssociatedNode();
928                 return result;
929         }
930
931         @Override
932         public String getName() {
933                 return RefactoringCoreMessages.ExtractTempRefactoring_name;
934         }
935
936
937         private IExpressionFragment getSelectedExpression() throws JavaModelException {
938                 if (fSelectedExpression != null)
939                         return fSelectedExpression;
940                 IASTFragment selectedFragment= ASTFragmentFactory.createFragmentForSourceRange(new SourceRange(fSelectionStart, fSelectionLength), fCompilationUnitNode, fCu);
941
942                 if (selectedFragment instanceof IExpressionFragment && !Checks.isInsideJavadoc(selectedFragment.getAssociatedNode())) {
943                         fSelectedExpression= (IExpressionFragment) selectedFragment;
944                 } else if (selectedFragment != null) {
945                         if (selectedFragment.getAssociatedNode() instanceof ExpressionStatement) {
946                                 ExpressionStatement exprStatement= (ExpressionStatement) selectedFragment.getAssociatedNode();
947                                 Expression expression= exprStatement.getExpression();
948                                 fSelectedExpression= (IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(expression);
949                         } else if (selectedFragment.getAssociatedNode() instanceof Assignment) {
950                                 Assignment assignment= (Assignment) selectedFragment.getAssociatedNode();
951                                 fSelectedExpression= (IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(assignment);
952                         }
953                 }
954
955                 if (fSelectedExpression != null && Checks.isEnumCase(fSelectedExpression.getAssociatedExpression().getParent())) {
956                         fSelectedExpression= null;
957                 }
958
959                 return fSelectedExpression;
960         }
961
962         private Type createTempType() throws CoreException {
963                 Expression expression= getSelectedExpression().getAssociatedExpression();
964
965                 Type resultingType= null;
966                 ITypeBinding typeBinding= expression.resolveTypeBinding();
967
968                 ASTRewrite rewrite= fCURewrite.getASTRewrite();
969                 AST ast= rewrite.getAST();
970
971                 if (expression instanceof ClassInstanceCreation && (typeBinding == null || typeBinding.getTypeArguments().length == 0)) {
972                         resultingType= (Type) rewrite.createCopyTarget(((ClassInstanceCreation) expression).getType());
973                 } else if (expression instanceof CastExpression) {
974                         resultingType= (Type) rewrite.createCopyTarget(((CastExpression) expression).getType());
975                 } else {
976                         if (typeBinding == null) {
977                                 typeBinding= ASTResolving.guessBindingForReference(expression);
978                         }
979                         if (typeBinding != null) {
980                                 typeBinding= Bindings.normalizeForDeclarationUse(typeBinding, ast);
981                                 ImportRewrite importRewrite= fCURewrite.getImportRewrite();
982                                 ImportRewriteContext context= new ContextSensitiveImportRewriteContext(expression, importRewrite);
983                                 resultingType= importRewrite.addImport(typeBinding, ast, context);
984                         } else {
985                                 resultingType= ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
986                         }
987                 }
988                 if (fLinkedProposalModel != null) {
989                         LinkedProposalPositionGroup typeGroup= fLinkedProposalModel.getPositionGroup(KEY_TYPE, true);
990                         typeGroup.addPosition(rewrite.track(resultingType), false);
991                         if (typeBinding != null) {
992                                 ITypeBinding[] relaxingTypes= ASTResolving.getNarrowingTypes(ast, typeBinding);
993                                 for (int i= 0; i < relaxingTypes.length; i++) {
994                                         typeGroup.addProposal(relaxingTypes[i], fCURewrite.getCu(), relaxingTypes.length - i);
995                                 }
996                         }
997                 }
998                 return resultingType;
999         }
1000
1001         public String guessTempName() {
1002                 String[] proposals= guessTempNames();
1003                 if (proposals.length == 0)
1004                         return fTempName;
1005                 else
1006                         return proposals[0];
1007         }
1008
1009         /**
1010          * @return proposed variable names (may be empty, but not null). The first proposal should be used as "best guess" (if it exists).
1011          */
1012         public String[] guessTempNames() {
1013                 if (fGuessedTempNames == null) {
1014                         try {
1015                                 Expression expression= getSelectedExpression().getAssociatedExpression();
1016                                 if (expression != null) {
1017                                         ITypeBinding binding= guessBindingForReference(expression);
1018                                         fGuessedTempNames= StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, fCu.getJavaProject(), binding, expression, Arrays.asList(getExcludedVariableNames()));
1019                                 }
1020                         } catch (JavaModelException e) {
1021                         }
1022                         if (fGuessedTempNames == null)
1023                                 fGuessedTempNames= new String[0];
1024                 }
1025                 return fGuessedTempNames;
1026         }
1027
1028         private boolean isLiteralNodeSelected() throws JavaModelException {
1029                 IExpressionFragment fragment= getSelectedExpression();
1030                 if (fragment == null)
1031                         return false;
1032                 Expression expression= fragment.getAssociatedExpression();
1033                 if (expression == null)
1034                         return false;
1035                 switch (expression.getNodeType()) {
1036                         case ASTNode.BOOLEAN_LITERAL:
1037                         case ASTNode.CHARACTER_LITERAL:
1038                         case ASTNode.NULL_LITERAL:
1039                         case ASTNode.NUMBER_LITERAL:
1040                                 return true;
1041
1042                         default:
1043                                 return false;
1044                 }
1045         }
1046
1047         private boolean isUsedInExplicitConstructorCall() throws JavaModelException {
1048                 Expression selectedExpression= getSelectedExpression().getAssociatedExpression();
1049                 if (ASTNodes.getParent(selectedExpression, ConstructorInvocation.class) != null)
1050                         return true;
1051                 if (ASTNodes.getParent(selectedExpression, SuperConstructorInvocation.class) != null)
1052                         return true;
1053                 return false;
1054         }
1055
1056         public boolean replaceAllOccurrences() {
1057                 return fReplaceAllOccurrences;
1058         }
1059
1060         private void replaceSelectedExpressionWithTempDeclaration() throws CoreException {
1061                 ASTRewrite rewrite= fCURewrite.getASTRewrite();
1062                 Expression selectedExpression= getSelectedExpression().getAssociatedExpression(); // whole expression selected
1063
1064                 Expression initializer= (Expression) rewrite.createMoveTarget(selectedExpression);
1065                 VariableDeclarationStatement tempDeclaration= createTempDeclaration(initializer);
1066                 ASTNode replacement;
1067
1068                 ASTNode parent= selectedExpression.getParent();
1069                 boolean isParentLambda= parent instanceof LambdaExpression;
1070                 AST ast= rewrite.getAST();
1071                 if (isParentLambda) {
1072                         Block blockBody= ast.newBlock();
1073                         blockBody.statements().add(tempDeclaration);
1074                         if (!Bindings.isVoidType(((LambdaExpression) parent).resolveMethodBinding().getReturnType())) {
1075                                 List<VariableDeclarationFragment> fragments= tempDeclaration.fragments();
1076                                 SimpleName varName= fragments.get(0).getName();
1077                                 ReturnStatement returnStatement= ast.newReturnStatement();
1078                                 returnStatement.setExpression(ast.newSimpleName(varName.getIdentifier()));
1079                                 blockBody.statements().add(returnStatement);
1080                         }
1081                         replacement= blockBody;
1082                 } else if (ASTNodes.isControlStatementBody(parent.getLocationInParent())) {
1083                         Block block= ast.newBlock();
1084                         block.statements().add(tempDeclaration);
1085                         replacement= block;
1086                 } else {
1087                         replacement= tempDeclaration;
1088                 }
1089                 ASTNode replacee= isParentLambda || !ASTNodes.hasSemicolon((ExpressionStatement) parent, fCu) ? selectedExpression : parent;
1090                 rewrite.replace(replacee, replacement, fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable));
1091         }
1092
1093         public void setDeclareFinal(boolean declareFinal) {
1094                 fDeclareFinal= declareFinal;
1095         }
1096
1097         public void setReplaceAllOccurrences(boolean replaceAllOccurrences) {
1098                 fReplaceAllOccurrences= replaceAllOccurrences;
1099         }
1100
1101         public void setTempName(String newName) {
1102                 fTempName= newName;
1103         }
1104
1105         private boolean shouldReplaceSelectedExpressionWithTempDeclaration() throws JavaModelException {
1106                 IExpressionFragment selectedFragment= getSelectedExpression();
1107                 IExpressionFragment firstExpression= getFirstReplacedExpression();
1108                 if (firstExpression.getStartPosition() < selectedFragment.getStartPosition())
1109                         return false;
1110                 ASTNode associatedNode= selectedFragment.getAssociatedNode();
1111                 return (associatedNode.getParent() instanceof ExpressionStatement || associatedNode.getParent() instanceof LambdaExpression)
1112                                 && selectedFragment.matches(ASTFragmentFactory.createFragmentForFullSubtree(associatedNode));
1113         }
1114
1115         private RefactoringStatus initialize(JavaRefactoringArguments arguments) {
1116                 final String selection= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION);
1117                 if (selection != null) {
1118                         int offset= -1;
1119                         int length= -1;
1120                         final StringTokenizer tokenizer= new StringTokenizer(selection);
1121                         if (tokenizer.hasMoreTokens())
1122                                 offset= Integer.valueOf(tokenizer.nextToken()).intValue();
1123                         if (tokenizer.hasMoreTokens())
1124                                 length= Integer.valueOf(tokenizer.nextToken()).intValue();
1125                         if (offset >= 0 && length >= 0) {
1126                                 fSelectionStart= offset;
1127                                 fSelectionLength= length;
1128                         } else
1129                                 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object[] { selection, JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION}));
1130                 } else
1131                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION));
1132                 final String handle= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1133                 if (handle != null) {
1134                         final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false);
1135                         if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT)
1136                                 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.EXTRACT_LOCAL_VARIABLE);
1137                         else
1138                                 fCu= (ICompilationUnit) element;
1139                 } else
1140                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1141                 final String name= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
1142                 if (name != null && !"".equals(name)) //$NON-NLS-1$
1143                         fTempName= name;
1144                 else
1145                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
1146                 final String replace= arguments.getAttribute(ATTRIBUTE_REPLACE);
1147                 if (replace != null) {
1148                         fReplaceAllOccurrences= Boolean.valueOf(replace).booleanValue();
1149                 } else
1150                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
1151                 final String declareFinal= arguments.getAttribute(ATTRIBUTE_FINAL);
1152                 if (declareFinal != null) {
1153                         fDeclareFinal= Boolean.valueOf(declareFinal).booleanValue();
1154                 } else
1155                         return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_FINAL));
1156                 return new RefactoringStatus();
1157         }
1158         
1159         public MethodDeclaration getMethodDeclaration(){
1160                 return methodDeclaration;
1161         }
1162 }