]> git.uio.no Git - ifi-stolz-refaktor.git/blame - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/refactorings/ExtractTempWithAssertsRefactoring.java
now also works with blockless constructs (if, for, etc)
[ifi-stolz-refaktor.git] / software / no.uio.ifi.refaktor / src / no / uio / ifi / refaktor / refactorings / ExtractTempWithAssertsRefactoring.java
CommitLineData
f9bf275d
AE
1package no.uio.ifi.refaktor.refactorings;
2
3import java.util.ArrayList;
4import java.util.Arrays;
5import java.util.Collection;
6import java.util.Collections;
7import java.util.Comparator;
8import java.util.HashMap;
9import java.util.HashSet;
10import java.util.Iterator;
11import java.util.List;
12import java.util.Map;
13import java.util.StringTokenizer;
14
15import org.eclipse.core.runtime.Assert;
16import org.eclipse.core.runtime.CoreException;
17import org.eclipse.core.runtime.IProgressMonitor;
18import org.eclipse.core.runtime.NullProgressMonitor;
19import org.eclipse.core.runtime.SubProgressMonitor;
20
21import org.eclipse.text.edits.TextEditGroup;
22
23import org.eclipse.ltk.core.refactoring.Change;
24import org.eclipse.ltk.core.refactoring.Refactoring;
25import org.eclipse.ltk.core.refactoring.RefactoringChangeDescriptor;
26import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
27import org.eclipse.ltk.core.refactoring.RefactoringStatus;
28import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry;
29
30import org.eclipse.jdt.core.ICompilationUnit;
31import org.eclipse.jdt.core.IJavaElement;
32import org.eclipse.jdt.core.IJavaProject;
33import org.eclipse.jdt.core.JavaModelException;
34import org.eclipse.jdt.core.NamingConventions;
35import org.eclipse.jdt.core.SourceRange;
36import org.eclipse.jdt.core.compiler.IProblem;
37import org.eclipse.jdt.core.dom.AST;
38import org.eclipse.jdt.core.dom.ASTNode;
39import org.eclipse.jdt.core.dom.ASTVisitor;
40import org.eclipse.jdt.core.dom.Annotation;
41import org.eclipse.jdt.core.dom.ArrayInitializer;
42import org.eclipse.jdt.core.dom.AssertStatement;
43import org.eclipse.jdt.core.dom.Assignment;
44import org.eclipse.jdt.core.dom.Block;
45import org.eclipse.jdt.core.dom.BodyDeclaration;
46import org.eclipse.jdt.core.dom.CastExpression;
47import org.eclipse.jdt.core.dom.CatchClause;
48import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
49import org.eclipse.jdt.core.dom.ClassInstanceCreation;
50import org.eclipse.jdt.core.dom.CompilationUnit;
51import org.eclipse.jdt.core.dom.ConstructorInvocation;
52import org.eclipse.jdt.core.dom.DoStatement;
53import org.eclipse.jdt.core.dom.EnhancedForStatement;
54import org.eclipse.jdt.core.dom.Expression;
55import org.eclipse.jdt.core.dom.ExpressionStatement;
56import org.eclipse.jdt.core.dom.FieldAccess;
57import org.eclipse.jdt.core.dom.ForStatement;
58import org.eclipse.jdt.core.dom.IBinding;
59import org.eclipse.jdt.core.dom.IMethodBinding;
60import org.eclipse.jdt.core.dom.ITypeBinding;
61import org.eclipse.jdt.core.dom.IVariableBinding;
62import org.eclipse.jdt.core.dom.IfStatement;
63import org.eclipse.jdt.core.dom.InfixExpression;
64import org.eclipse.jdt.core.dom.Initializer;
65import org.eclipse.jdt.core.dom.LambdaExpression;
66import org.eclipse.jdt.core.dom.MethodDeclaration;
67import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
68import org.eclipse.jdt.core.dom.Name;
69import org.eclipse.jdt.core.dom.NullLiteral;
70import org.eclipse.jdt.core.dom.ParenthesizedExpression;
71import org.eclipse.jdt.core.dom.PostfixExpression;
72import org.eclipse.jdt.core.dom.PrefixExpression;
73import org.eclipse.jdt.core.dom.QualifiedName;
74import org.eclipse.jdt.core.dom.ReturnStatement;
75import org.eclipse.jdt.core.dom.SimpleName;
76import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
77import org.eclipse.jdt.core.dom.Statement;
78import org.eclipse.jdt.core.dom.StringLiteral;
79import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
80import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
81import org.eclipse.jdt.core.dom.SwitchCase;
82import org.eclipse.jdt.core.dom.SwitchStatement;
83import org.eclipse.jdt.core.dom.TryStatement;
84import org.eclipse.jdt.core.dom.Type;
85import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
86import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
87import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
88import org.eclipse.jdt.core.dom.WhileStatement;
89import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
90import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
91import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
92import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
93import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
94import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
95import org.eclipse.jdt.core.refactoring.descriptors.ExtractLocalDescriptor;
96
97import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
98import org.eclipse.jdt.internal.corext.Corext;
99import org.eclipse.jdt.internal.corext.SourceRangeFactory;
100import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
101import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
102import org.eclipse.jdt.internal.corext.dom.ASTNodes;
103import org.eclipse.jdt.internal.corext.dom.Bindings;
104import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
105import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
106import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment;
107import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
108import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
109import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup;
110import org.eclipse.jdt.internal.corext.refactoring.Checks;
111import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
112import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
113import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
114import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
115import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
116import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext;
117import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
118import org.eclipse.jdt.internal.corext.refactoring.code.CodeRefactoringUtil;
119import org.eclipse.jdt.internal.corext.refactoring.code.ExtractTempRefactoring;
120import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringAnalyzeUtil;
121import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
122import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer;
123import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
124import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
125import org.eclipse.jdt.internal.corext.util.Messages;
126
127import org.eclipse.jdt.ui.JavaElementLabels;
128
129import org.eclipse.jdt.internal.ui.JavaPlugin;
130import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
131import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
132import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
133import 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 */
142public 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;
8c911c28 359 private String fSelectedText;
f9bf275d
AE
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
8c911c28 370 * @param string
f9bf275d 371 */
8c911c28 372 public ExtractTempWithAssertsRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength, String selectedText) {
f9bf275d
AE
373 super(unit, selectionStart, selectionLength);
374 Assert.isTrue(selectionStart >= 0);
375 Assert.isTrue(selectionLength >= 0);
376 fSelectionStart= selectionStart;
377 fSelectionLength= selectionLength;
8c911c28 378 fSelectedText = selectedText;
f9bf275d
AE
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
8c911c28
AE
409// public ExtractTempWithAssertsRefactoring(JavaRefactoringArguments arguments, RefactoringStatus status) {
410// this((ICompilationUnit) null, 0, 0);
411// RefactoringStatus initializeStatus= initialize(arguments);
412// status.merge(initializeStatus);
413// }
f9bf275d
AE
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
8c911c28 436 /*
f4143a55 437 * Anna's code from here
8c911c28 438 */
1b3a0a09 439
92dc3046
AE
440 ASTNode exprstatement = fragment.getAssociatedNode();
441 while( !(exprstatement instanceof ExpressionStatement)){
442 exprstatement = exprstatement.getParent();
f4143a55 443 }
92dc3046 444
8c911c28 445
92dc3046
AE
446 ASTNode block = exprstatement.getParent();
447
448 while(! (block instanceof Block)){
449 block = block.getParent();
f4143a55
AE
450 exprstatement = exprstatement.getParent();
451 }
1b3a0a09 452
92dc3046 453
f4143a55 454 ListRewrite lr = rewrite.getListRewrite(block, Block.STATEMENTS_PROPERTY);
1b3a0a09 455
f4143a55 456 lr.insertBefore(getAssertStatement(block.getAST()), exprstatement, null);
8c911c28
AE
457
458 /*
f4143a55 459 * End of Anna's code
8c911c28 460 */
f4143a55 461
1b3a0a09
AE
462 fragment.replace(rewrite, tempName, description);
463
f9bf275d
AE
464 if (fLinkedProposalModel != null)
465 fLinkedProposalModel.getPositionGroup(KEY_NAME, true).addPosition(rewrite.track(tempName), false);
466 }
467 }
468
f4143a55
AE
469 /**
470 *
471 * @param ast the AST the Statement will belong to
472 * @return the assert statement, belonging to the input AST, used to check if the code is broken
473 */
1b3a0a09 474 private Statement getAssertStatement(AST ast){
1b3a0a09
AE
475 AssertStatement assertStatement = ast.newAssertStatement();
476 InfixExpression infixExpression = ast.newInfixExpression();
477
478 infixExpression.setLeftOperand(ast.newSimpleName(fTempName));
479 infixExpression.setOperator(InfixExpression.Operator.EQUALS);
480
481 infixExpression.setRightOperand(ast.newName(fSelectedText));
482 assertStatement.setExpression(infixExpression);
483 StringLiteral stringLiteral = ast.newStringLiteral();
484 stringLiteral.setLiteralValue("The Move Method refactoring has broken the program due to aliasing issues!");
485 assertStatement.setMessage(stringLiteral);
486 return assertStatement;
487 }
f9bf275d
AE
488
489 private RefactoringStatus checkExpression() throws JavaModelException {
490 Expression selectedExpression= getSelectedExpression().getAssociatedExpression();
491 if (selectedExpression != null) {
492 final ASTNode parent= selectedExpression.getParent();
493 if (selectedExpression instanceof NullLiteral) {
494 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_null_literals);
495 } else if (selectedExpression instanceof ArrayInitializer) {
496 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_array_initializer);
497 } else if (selectedExpression instanceof Assignment) {
498 if (parent instanceof Expression && !(parent instanceof ParenthesizedExpression))
499 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_assignment);
500 else
501 return null;
502 } else if (selectedExpression instanceof SimpleName) {
503 if ((((SimpleName) selectedExpression)).isDeclaration())
504 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_names_in_declarations);
505 if (parent instanceof QualifiedName && selectedExpression.getLocationInParent() == QualifiedName.NAME_PROPERTY || parent instanceof FieldAccess && selectedExpression.getLocationInParent() == FieldAccess.NAME_PROPERTY)
506 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_select_expression);
507 } else if (selectedExpression instanceof VariableDeclarationExpression && parent instanceof TryStatement) {
508 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_resource_in_try_with_resources);
509 }
510 }
511
512 return null;
513 }
514
515 // !! Same as in ExtractConstantRefactoring
516 private RefactoringStatus checkExpressionFragmentIsRValue() throws JavaModelException {
517 switch (Checks.checkExpressionIsRValue(getSelectedExpression().getAssociatedExpression())) {
518 case Checks.NOT_RVALUE_MISC:
519 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractTempRefactoring_select_expression, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE, null);
520 case Checks.NOT_RVALUE_VOID:
521 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractTempRefactoring_no_void, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID, null);
522 case Checks.IS_RVALUE_GUESSED:
523 case Checks.IS_RVALUE:
524 return new RefactoringStatus();
525 default:
526 Assert.isTrue(false);
527 return null;
528 }
529 }
530
531 private ITypeBinding guessBindingForReference(Expression expression) {
532 ITypeBinding binding= expression.resolveTypeBinding();
533 if (binding == null) {
534 binding= ASTResolving.guessBindingForReference(expression);
535 }
536 return binding;
537 }
538
539 @Override
540 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException {
541 try {
542 pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 4);
543
544 fCURewrite= new CompilationUnitRewrite(fCu, fCompilationUnitNode);
545 fCURewrite.getASTRewrite().setTargetSourceRangeComputer(new NoCommentSourceRangeComputer());
546
547 doCreateChange(new SubProgressMonitor(pm, 2));
548
549 fChange= fCURewrite.createChange(RefactoringCoreMessages.ExtractTempRefactoring_change_name, true, new SubProgressMonitor(pm, 1));
550
551 RefactoringStatus result= new RefactoringStatus();
552 if (Arrays.asList(getExcludedVariableNames()).contains(fTempName))
553 result.addWarning(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable, BasicElementLabels.getJavaElementName(fTempName)));
554
555 result.merge(checkMatchingFragments());
556
557 fChange.setKeepPreviewEdits(true);
558
559 if (fCheckResultForCompileProblems) {
560 checkNewSource(new SubProgressMonitor(pm, 1), result);
561 }
562
563 return result;
564 } finally {
565 pm.done();
566 }
567 }
568
569 private final ExtractLocalDescriptor createRefactoringDescriptor() {
570 final Map<String, String> arguments= new HashMap<String, String>();
571 String project= null;
572 IJavaProject javaProject= fCu.getJavaProject();
573 if (javaProject != null)
574 project= javaProject.getElementName();
575 final String description= Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description_short, BasicElementLabels.getJavaElementName(fTempName));
576 final String expression= ASTNodes.asString(fSelectedExpression.getAssociatedExpression());
577 final String header= Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description, new String[] { BasicElementLabels.getJavaElementName(fTempName), BasicElementLabels.getJavaCodeString(expression)});
578 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header);
579 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_name_pattern, BasicElementLabels.getJavaElementName(fTempName)));
580 final BodyDeclaration decl= (BodyDeclaration) ASTNodes.getParent(fSelectedExpression.getAssociatedExpression(), BodyDeclaration.class);
581 if (decl instanceof MethodDeclaration) {
f9bf275d
AE
582 final IMethodBinding method= ((MethodDeclaration) decl).resolveBinding();
583 final String label= method != null ? BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED) : BasicElementLabels.getJavaElementName('{' + JavaElementLabels.ELLIPSIS_STRING + '}');
584 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_destination_pattern, label));
585 }
586 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_expression_pattern, BasicElementLabels.getJavaCodeString(expression)));
587 if (fReplaceAllOccurrences)
588 comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_replace_occurrences);
589 if (fDeclareFinal)
590 comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_declare_final);
591 final ExtractLocalDescriptor descriptor= RefactoringSignatureDescriptorFactory.createExtractLocalDescriptor(project, description, comment.asString(), arguments, RefactoringDescriptor.NONE);
592 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT, JavaRefactoringDescriptorUtil.elementToHandle(project, fCu));
593 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME, fTempName);
594 arguments.put(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION, new Integer(fSelectionStart).toString() + " " + new Integer(fSelectionLength).toString()); //$NON-NLS-1$
595 arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplaceAllOccurrences).toString());
596 arguments.put(ATTRIBUTE_FINAL, Boolean.valueOf(fDeclareFinal).toString());
597 return descriptor;
598 }
599
600 private void doCreateChange(IProgressMonitor pm) throws CoreException {
601 try {
602 pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 1);
603 try {
604 createTempDeclaration();
605 } catch (CoreException exception) {
606 JavaPlugin.log(exception);
607 }
608 addReplaceExpressionWithTemp();
609 } finally {
610 pm.done();
611 }
612 }
613
614 private void checkNewSource(SubProgressMonitor monitor, RefactoringStatus result) throws CoreException {
615 String newCuSource= fChange.getPreviewContent(new NullProgressMonitor());
616 CompilationUnit newCUNode= new RefactoringASTParser(ASTProvider.SHARED_AST_LEVEL).parse(newCuSource, fCu, true, true, monitor);
617 IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, fCompilationUnitNode);
618 for (int i= 0; i < newProblems.length; i++) {
619 IProblem problem= newProblems[i];
620 if (problem.isError())
621 result.addEntry(new RefactoringStatusEntry((problem.isError() ? RefactoringStatus.ERROR : RefactoringStatus.WARNING), problem.getMessage(), new JavaStringStatusContext(newCuSource, SourceRangeFactory.create(problem))));
622 }
623 }
624
625 @Override
626 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException {
627 try {
628 pm.beginTask("", 6); //$NON-NLS-1$
629
630 RefactoringStatus result= Checks.validateModifiesFiles(ResourceUtil.getFiles(new ICompilationUnit[] { fCu}), getValidationContext());
631 if (result.hasFatalError())
632 return result;
633
634 if (fCompilationUnitNode == null) {
635 fCompilationUnitNode= RefactoringASTParser.parseWithASTProvider(fCu, true, new SubProgressMonitor(pm, 3));
636 } else {
637 pm.worked(3);
638 }
639
640 result.merge(checkSelection(new SubProgressMonitor(pm, 3)));
641 if (!result.hasFatalError() && isLiteralNodeSelected())
642 fReplaceAllOccurrences= false;
643 return result;
644
645 } finally {
646 pm.done();
647 }
648 }
649
650 private RefactoringStatus checkMatchingFragments() throws JavaModelException {
651 RefactoringStatus result= new RefactoringStatus();
652 IASTFragment[] matchingFragments= getMatchingFragments();
653 for (int i= 0; i < matchingFragments.length; i++) {
654 ASTNode node= matchingFragments[i].getAssociatedNode();
655 if (isLeftValue(node) && !isReferringToLocalVariableFromFor((Expression) node)) {
656 String msg= RefactoringCoreMessages.ExtractTempRefactoring_assigned_to;
657 result.addWarning(msg, JavaStatusContext.create(fCu, node));
658 }
659 }
660 return result;
661 }
662
663 private RefactoringStatus checkSelection(IProgressMonitor pm) throws JavaModelException {
664 try {
665 pm.beginTask("", 8); //$NON-NLS-1$
666
667 IExpressionFragment selectedExpression= getSelectedExpression();
668
669 if (selectedExpression == null) {
670 String message= RefactoringCoreMessages.ExtractTempRefactoring_select_expression;
671 return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, fCompilationUnitNode, message);
672 }
673 pm.worked(1);
674
675 if (isUsedInExplicitConstructorCall())
676 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_explicit_constructor);
677 pm.worked(1);
678
679 ASTNode associatedNode= selectedExpression.getAssociatedNode();
680 if (getEnclosingBodyNode() == null || ASTNodes.getParent(associatedNode, Annotation.class) != null)
681 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_expr_in_method_or_initializer);
682 pm.worked(1);
683
684 if (associatedNode instanceof Name && associatedNode.getParent() instanceof ClassInstanceCreation && associatedNode.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY)
685 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_name_in_new);
686 pm.worked(1);
687
688 RefactoringStatus result= new RefactoringStatus();
689 result.merge(checkExpression());
690 if (result.hasFatalError())
691 return result;
692 pm.worked(1);
693
694 result.merge(checkExpressionFragmentIsRValue());
695 if (result.hasFatalError())
696 return result;
697 pm.worked(1);
698
699 if (isUsedInForInitializerOrUpdater(getSelectedExpression().getAssociatedExpression()))
700 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_for_initializer_updater);
701 pm.worked(1);
702
703 if (isReferringToLocalVariableFromFor(getSelectedExpression().getAssociatedExpression()))
704 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_refers_to_for_variable);
705 pm.worked(1);
706
707 return result;
708 } finally {
709 pm.done();
710 }
711 }
712
713 public RefactoringStatus checkTempName(String newName) {
714 RefactoringStatus status= Checks.checkTempName(newName, fCu);
715 if (Arrays.asList(getExcludedVariableNames()).contains(newName))
716 status.addWarning(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable, BasicElementLabels.getJavaElementName(newName)));
717 return status;
718 }
719
720 private void createAndInsertTempDeclaration() throws CoreException {
721 Expression initializer= getSelectedExpression().createCopyTarget(fCURewrite.getASTRewrite(), true);
722 VariableDeclarationStatement vds= createTempDeclaration(initializer);
723
724 IASTFragment[] replacableMatches= retainOnlyReplacableMatches(getMatchingFragments());
725 if (!fReplaceAllOccurrences
726 || replacableMatches.length == 0
727 || replacableMatches.length == 1 && replacableMatches[0].equals(getSelectedExpression().getAssociatedExpression())) {
728 insertAt(getSelectedExpression().getAssociatedNode(), vds);
729 return;
730 }
731
732 ASTNode[] firstReplaceNodeParents= getParents(getFirstReplacedExpression().getAssociatedNode());
733 ASTNode[] commonPath= findDeepestCommonSuperNodePathForReplacedNodes();
734 Assert.isTrue(commonPath.length <= firstReplaceNodeParents.length);
735
736 ASTNode deepestCommonParent= firstReplaceNodeParents[commonPath.length - 1];
737 if (deepestCommonParent instanceof Block)
738 insertAt(firstReplaceNodeParents[commonPath.length], vds);
739 else
740 insertAt(deepestCommonParent, vds);
741 }
742
743 private VariableDeclarationStatement createTempDeclaration(Expression initializer) throws CoreException {
744 AST ast= fCURewrite.getAST();
745
746 VariableDeclarationFragment vdf= ast.newVariableDeclarationFragment();
747 vdf.setName(ast.newSimpleName(fTempName));
748 vdf.setInitializer(initializer);
749
750 VariableDeclarationStatement vds= ast.newVariableDeclarationStatement(vdf);
751 if (fDeclareFinal) {
752 vds.modifiers().add(ast.newModifier(ModifierKeyword.FINAL_KEYWORD));
753 }
754 vds.setType(createTempType());
755
756 if (fLinkedProposalModel != null) {
757 ASTRewrite rewrite= fCURewrite.getASTRewrite();
758 LinkedProposalPositionGroup nameGroup= fLinkedProposalModel.getPositionGroup(KEY_NAME, true);
759 nameGroup.addPosition(rewrite.track(vdf.getName()), true);
760
761 String[] nameSuggestions= guessTempNames();
762 if (nameSuggestions.length > 0 && !nameSuggestions[0].equals(fTempName)) {
763 nameGroup.addProposal(fTempName, null, nameSuggestions.length + 1);
764 }
765 for (int i= 0; i < nameSuggestions.length; i++) {
766 nameGroup.addProposal(nameSuggestions[i], null, nameSuggestions.length - i);
767 }
768 }
769 return vds;
770 }
771
772 private void insertAt(ASTNode target, Statement declaration) {
773 ASTRewrite rewrite= fCURewrite.getASTRewrite();
774 TextEditGroup groupDescription= fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable);
775
776 ASTNode parent= target.getParent();
777 StructuralPropertyDescriptor locationInParent= target.getLocationInParent();
778 while (locationInParent != Block.STATEMENTS_PROPERTY && locationInParent != SwitchStatement.STATEMENTS_PROPERTY) {
779 if (locationInParent == IfStatement.THEN_STATEMENT_PROPERTY
780 || locationInParent == IfStatement.ELSE_STATEMENT_PROPERTY
781 || locationInParent == ForStatement.BODY_PROPERTY
782 || locationInParent == EnhancedForStatement.BODY_PROPERTY
783 || locationInParent == DoStatement.BODY_PROPERTY
784 || locationInParent == WhileStatement.BODY_PROPERTY) {
785 // create intermediate block if target was the body property of a control statement:
786 Block replacement= rewrite.getAST().newBlock();
787 ListRewrite replacementRewrite= rewrite.getListRewrite(replacement, Block.STATEMENTS_PROPERTY);
788 replacementRewrite.insertFirst(declaration, null);
789 replacementRewrite.insertLast(rewrite.createMoveTarget(target), null);
790 rewrite.replace(target, replacement, groupDescription);
791 return;
792 } else if (locationInParent == LambdaExpression.BODY_PROPERTY && ((LambdaExpression) parent).getBody() instanceof Expression) {
793 Block replacement= rewrite.getAST().newBlock();
794 ListRewrite replacementRewrite= rewrite.getListRewrite(replacement, Block.STATEMENTS_PROPERTY);
795 replacementRewrite.insertFirst(declaration, null);
796 ASTNode moveTarget= rewrite.createMoveTarget(target);
797 AST ast= rewrite.getAST();
798 if (Bindings.isVoidType(((LambdaExpression) parent).resolveMethodBinding().getReturnType())) {
799 ExpressionStatement expressionStatement= ast.newExpressionStatement((Expression) moveTarget);
800 moveTarget= expressionStatement;
801 } else {
802 ReturnStatement returnStatement= ast.newReturnStatement();
803 returnStatement.setExpression((Expression) moveTarget);
804 moveTarget= returnStatement;
805 }
806 replacementRewrite.insertLast(moveTarget, null);
807 rewrite.replace(target, replacement, groupDescription);
808 return;
809 }
810 target= parent;
811 parent= parent.getParent();
812 locationInParent= target.getLocationInParent();
813 }
814 ListRewrite listRewrite= rewrite.getListRewrite(parent, (ChildListPropertyDescriptor)locationInParent);
815 listRewrite.insertBefore(declaration, target, groupDescription);
816 }
817
818 @Override
819 public Change createChange(IProgressMonitor pm) throws CoreException {
820 try {
821 pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 1);
822
823 ExtractLocalDescriptor descriptor= createRefactoringDescriptor();
824 fChange.setDescriptor(new RefactoringChangeDescriptor(descriptor));
825 return fChange;
826 } finally {
827 pm.done();
828 }
829 }
830
831 private void createTempDeclaration() throws CoreException {
832 if (shouldReplaceSelectedExpressionWithTempDeclaration())
833 replaceSelectedExpressionWithTempDeclaration();
834 else
835 createAndInsertTempDeclaration();
836 }
837
838 public boolean declareFinal() {
839 return fDeclareFinal;
840 }
841
842 private ASTNode[] findDeepestCommonSuperNodePathForReplacedNodes() throws JavaModelException {
843 ASTNode[] matchNodes= getMatchNodes();
844
845 ASTNode[][] matchingNodesParents= new ASTNode[matchNodes.length][];
846 for (int i= 0; i < matchNodes.length; i++) {
847 matchingNodesParents[i]= getParents(matchNodes[i]);
848 }
849 List<Object> l= Arrays.asList(getLongestArrayPrefix(matchingNodesParents));
850 return l.toArray(new ASTNode[l.size()]);
851 }
852
853 private ASTNode getEnclosingBodyNode() throws JavaModelException {
854 ASTNode node= getSelectedExpression().getAssociatedNode();
855
856 // expression must be in a method, lambda or initializer body
857 // make sure it is not in method or parameter annotation
858 StructuralPropertyDescriptor location= null;
859 while (node != null && !(node instanceof BodyDeclaration)) {
860 location= node.getLocationInParent();
861 node= node.getParent();
862 if (node instanceof LambdaExpression) {
863 break;
864 }
865 }
866 if (location == MethodDeclaration.BODY_PROPERTY || location == Initializer.BODY_PROPERTY
867 || (location == LambdaExpression.BODY_PROPERTY && ((LambdaExpression) node).resolveMethodBinding() != null)) {
868 return (ASTNode) node.getStructuralProperty(location);
869 }
870 return null;
871 }
872
873 private String[] getExcludedVariableNames() {
874 if (fExcludedVariableNames == null) {
875 try {
876 IBinding[] bindings= new ScopeAnalyzer(fCompilationUnitNode).getDeclarationsInScope(getSelectedExpression().getStartPosition(), ScopeAnalyzer.VARIABLES
877 | ScopeAnalyzer.CHECK_VISIBILITY);
878 fExcludedVariableNames= new String[bindings.length];
879 for (int i= 0; i < bindings.length; i++) {
880 fExcludedVariableNames[i]= bindings[i].getName();
881 }
882 } catch (JavaModelException e) {
883 fExcludedVariableNames= new String[0];
884 }
885 }
886 return fExcludedVariableNames;
887 }
888
889 private IExpressionFragment getFirstReplacedExpression() throws JavaModelException {
890 if (!fReplaceAllOccurrences)
891 return getSelectedExpression();
892 IASTFragment[] nodesToReplace= retainOnlyReplacableMatches(getMatchingFragments());
893 if (nodesToReplace.length == 0)
894 return getSelectedExpression();
895 Comparator<IASTFragment> comparator= new Comparator<IASTFragment>() {
896
897 public int compare(IASTFragment o1, IASTFragment o2) {
898 return o1.getStartPosition() - o2.getStartPosition();
899 }
900 };
901 Arrays.sort(nodesToReplace, comparator);
902 return (IExpressionFragment) nodesToReplace[0];
903 }
904
905 private IASTFragment[] getMatchingFragments() throws JavaModelException {
906 if (fReplaceAllOccurrences) {
907 IASTFragment[] allMatches= ASTFragmentFactory.createFragmentForFullSubtree(getEnclosingBodyNode()).getSubFragmentsMatching(getSelectedExpression());
908 return allMatches;
909 } else
910 return new IASTFragment[] { getSelectedExpression()};
911 }
912
913 private ASTNode[] getMatchNodes() throws JavaModelException {
914 IASTFragment[] matches= retainOnlyReplacableMatches(getMatchingFragments());
915 ASTNode[] result= new ASTNode[matches.length];
916 for (int i= 0; i < matches.length; i++)
917 result[i]= matches[i].getAssociatedNode();
918 return result;
919 }
920
921 @Override
922 public String getName() {
923 return RefactoringCoreMessages.ExtractTempRefactoring_name;
924 }
925
926
927 private IExpressionFragment getSelectedExpression() throws JavaModelException {
928 if (fSelectedExpression != null)
929 return fSelectedExpression;
930 IASTFragment selectedFragment= ASTFragmentFactory.createFragmentForSourceRange(new SourceRange(fSelectionStart, fSelectionLength), fCompilationUnitNode, fCu);
931
932 if (selectedFragment instanceof IExpressionFragment && !Checks.isInsideJavadoc(selectedFragment.getAssociatedNode())) {
933 fSelectedExpression= (IExpressionFragment) selectedFragment;
934 } else if (selectedFragment != null) {
935 if (selectedFragment.getAssociatedNode() instanceof ExpressionStatement) {
936 ExpressionStatement exprStatement= (ExpressionStatement) selectedFragment.getAssociatedNode();
937 Expression expression= exprStatement.getExpression();
938 fSelectedExpression= (IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(expression);
939 } else if (selectedFragment.getAssociatedNode() instanceof Assignment) {
940 Assignment assignment= (Assignment) selectedFragment.getAssociatedNode();
941 fSelectedExpression= (IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(assignment);
942 }
943 }
944
945 if (fSelectedExpression != null && Checks.isEnumCase(fSelectedExpression.getAssociatedExpression().getParent())) {
946 fSelectedExpression= null;
947 }
948
949 return fSelectedExpression;
950 }
951
952 private Type createTempType() throws CoreException {
953 Expression expression= getSelectedExpression().getAssociatedExpression();
954
955 Type resultingType= null;
956 ITypeBinding typeBinding= expression.resolveTypeBinding();
957
958 ASTRewrite rewrite= fCURewrite.getASTRewrite();
959 AST ast= rewrite.getAST();
960
961 if (expression instanceof ClassInstanceCreation && (typeBinding == null || typeBinding.getTypeArguments().length == 0)) {
962 resultingType= (Type) rewrite.createCopyTarget(((ClassInstanceCreation) expression).getType());
963 } else if (expression instanceof CastExpression) {
964 resultingType= (Type) rewrite.createCopyTarget(((CastExpression) expression).getType());
965 } else {
966 if (typeBinding == null) {
967 typeBinding= ASTResolving.guessBindingForReference(expression);
968 }
969 if (typeBinding != null) {
970 typeBinding= Bindings.normalizeForDeclarationUse(typeBinding, ast);
971 ImportRewrite importRewrite= fCURewrite.getImportRewrite();
972 ImportRewriteContext context= new ContextSensitiveImportRewriteContext(expression, importRewrite);
973 resultingType= importRewrite.addImport(typeBinding, ast, context);
974 } else {
975 resultingType= ast.newSimpleType(ast.newSimpleName("Object")); //$NON-NLS-1$
976 }
977 }
978 if (fLinkedProposalModel != null) {
979 LinkedProposalPositionGroup typeGroup= fLinkedProposalModel.getPositionGroup(KEY_TYPE, true);
980 typeGroup.addPosition(rewrite.track(resultingType), false);
981 if (typeBinding != null) {
982 ITypeBinding[] relaxingTypes= ASTResolving.getNarrowingTypes(ast, typeBinding);
983 for (int i= 0; i < relaxingTypes.length; i++) {
984 typeGroup.addProposal(relaxingTypes[i], fCURewrite.getCu(), relaxingTypes.length - i);
985 }
986 }
987 }
988 return resultingType;
989 }
990
991 public String guessTempName() {
992 String[] proposals= guessTempNames();
993 if (proposals.length == 0)
994 return fTempName;
995 else
996 return proposals[0];
997 }
998
999 /**
1000 * @return proposed variable names (may be empty, but not null). The first proposal should be used as "best guess" (if it exists).
1001 */
1002 public String[] guessTempNames() {
1003 if (fGuessedTempNames == null) {
1004 try {
1005 Expression expression= getSelectedExpression().getAssociatedExpression();
1006 if (expression != null) {
1007 ITypeBinding binding= guessBindingForReference(expression);
1008 fGuessedTempNames= StubUtility.getVariableNameSuggestions(NamingConventions.VK_LOCAL, fCu.getJavaProject(), binding, expression, Arrays.asList(getExcludedVariableNames()));
1009 }
1010 } catch (JavaModelException e) {
1011 }
1012 if (fGuessedTempNames == null)
1013 fGuessedTempNames= new String[0];
1014 }
1015 return fGuessedTempNames;
1016 }
1017
1018 private boolean isLiteralNodeSelected() throws JavaModelException {
1019 IExpressionFragment fragment= getSelectedExpression();
1020 if (fragment == null)
1021 return false;
1022 Expression expression= fragment.getAssociatedExpression();
1023 if (expression == null)
1024 return false;
1025 switch (expression.getNodeType()) {
1026 case ASTNode.BOOLEAN_LITERAL:
1027 case ASTNode.CHARACTER_LITERAL:
1028 case ASTNode.NULL_LITERAL:
1029 case ASTNode.NUMBER_LITERAL:
1030 return true;
1031
1032 default:
1033 return false;
1034 }
1035 }
1036
1037 private boolean isUsedInExplicitConstructorCall() throws JavaModelException {
1038 Expression selectedExpression= getSelectedExpression().getAssociatedExpression();
1039 if (ASTNodes.getParent(selectedExpression, ConstructorInvocation.class) != null)
1040 return true;
1041 if (ASTNodes.getParent(selectedExpression, SuperConstructorInvocation.class) != null)
1042 return true;
1043 return false;
1044 }
1045
1046 public boolean replaceAllOccurrences() {
1047 return fReplaceAllOccurrences;
1048 }
1049
1050 private void replaceSelectedExpressionWithTempDeclaration() throws CoreException {
1051 ASTRewrite rewrite= fCURewrite.getASTRewrite();
1052 Expression selectedExpression= getSelectedExpression().getAssociatedExpression(); // whole expression selected
1053
1054 Expression initializer= (Expression) rewrite.createMoveTarget(selectedExpression);
1055 VariableDeclarationStatement tempDeclaration= createTempDeclaration(initializer);
1056 ASTNode replacement;
1057
1058 ASTNode parent= selectedExpression.getParent();
1059 boolean isParentLambda= parent instanceof LambdaExpression;
1060 AST ast= rewrite.getAST();
1061 if (isParentLambda) {
1062 Block blockBody= ast.newBlock();
1063 blockBody.statements().add(tempDeclaration);
1064 if (!Bindings.isVoidType(((LambdaExpression) parent).resolveMethodBinding().getReturnType())) {
1065 List<VariableDeclarationFragment> fragments= tempDeclaration.fragments();
1066 SimpleName varName= fragments.get(0).getName();
1067 ReturnStatement returnStatement= ast.newReturnStatement();
1068 returnStatement.setExpression(ast.newSimpleName(varName.getIdentifier()));
1069 blockBody.statements().add(returnStatement);
1070 }
1071 replacement= blockBody;
1072 } else if (ASTNodes.isControlStatementBody(parent.getLocationInParent())) {
1073 Block block= ast.newBlock();
1074 block.statements().add(tempDeclaration);
1075 replacement= block;
1076 } else {
1077 replacement= tempDeclaration;
1078 }
1079 ASTNode replacee= isParentLambda || !ASTNodes.hasSemicolon((ExpressionStatement) parent, fCu) ? selectedExpression : parent;
1080 rewrite.replace(replacee, replacement, fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable));
1081 }
1082
1083 public void setDeclareFinal(boolean declareFinal) {
1084 fDeclareFinal= declareFinal;
1085 }
1086
1087 public void setReplaceAllOccurrences(boolean replaceAllOccurrences) {
1088 fReplaceAllOccurrences= replaceAllOccurrences;
1089 }
1090
1091 public void setTempName(String newName) {
1092 fTempName= newName;
1093 }
1094
1095 private boolean shouldReplaceSelectedExpressionWithTempDeclaration() throws JavaModelException {
1096 IExpressionFragment selectedFragment= getSelectedExpression();
1097 IExpressionFragment firstExpression= getFirstReplacedExpression();
1098 if (firstExpression.getStartPosition() < selectedFragment.getStartPosition())
1099 return false;
1100 ASTNode associatedNode= selectedFragment.getAssociatedNode();
1101 return (associatedNode.getParent() instanceof ExpressionStatement || associatedNode.getParent() instanceof LambdaExpression)
1102 && selectedFragment.matches(ASTFragmentFactory.createFragmentForFullSubtree(associatedNode));
1103 }
1104
1105 private RefactoringStatus initialize(JavaRefactoringArguments arguments) {
1106 final String selection= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION);
1107 if (selection != null) {
1108 int offset= -1;
1109 int length= -1;
1110 final StringTokenizer tokenizer= new StringTokenizer(selection);
1111 if (tokenizer.hasMoreTokens())
1112 offset= Integer.valueOf(tokenizer.nextToken()).intValue();
1113 if (tokenizer.hasMoreTokens())
1114 length= Integer.valueOf(tokenizer.nextToken()).intValue();
1115 if (offset >= 0 && length >= 0) {
1116 fSelectionStart= offset;
1117 fSelectionLength= length;
1118 } else
1119 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object[] { selection, JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION}));
1120 } else
1121 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_SELECTION));
1122 final String handle= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1123 if (handle != null) {
1124 final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(arguments.getProject(), handle, false);
1125 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT)
1126 return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getName(), IJavaRefactorings.EXTRACT_LOCAL_VARIABLE);
1127 else
1128 fCu= (ICompilationUnit) element;
1129 } else
1130 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1131 final String name= arguments.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME);
1132 if (name != null && !"".equals(name)) //$NON-NLS-1$
1133 fTempName= name;
1134 else
1135 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_NAME));
1136 final String replace= arguments.getAttribute(ATTRIBUTE_REPLACE);
1137 if (replace != null) {
1138 fReplaceAllOccurrences= Boolean.valueOf(replace).booleanValue();
1139 } else
1140 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE));
1141 final String declareFinal= arguments.getAttribute(ATTRIBUTE_FINAL);
1142 if (declareFinal != null) {
1143 fDeclareFinal= Boolean.valueOf(declareFinal).booleanValue();
1144 } else
1145 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_FINAL));
1146 return new RefactoringStatus();
1147 }
1148
1149 public MethodDeclaration getMethodDeclaration(){
1150 return methodDeclaration;
1151 }
1152}