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