]> git.uio.no Git - ifi-stolz-refaktor.git/blame - software/no.uio.ifi.refaktor/src/no/uio/ifi/refaktor/refactorings/ExtractTempWithAssertsRefactoring.java
edited comment for clarity
[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;
a4f82448 20import org.eclipse.text.edits.MalformedTreeException;
f9bf275d
AE
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;
cd8d5a27 38import org.eclipse.jdt.core.dom.ASTMatcher;
f9bf275d
AE
39import org.eclipse.jdt.core.dom.ASTNode;
40import org.eclipse.jdt.core.dom.ASTVisitor;
41import org.eclipse.jdt.core.dom.Annotation;
42import org.eclipse.jdt.core.dom.ArrayInitializer;
43import org.eclipse.jdt.core.dom.AssertStatement;
44import org.eclipse.jdt.core.dom.Assignment;
45import org.eclipse.jdt.core.dom.Block;
46import org.eclipse.jdt.core.dom.BodyDeclaration;
47import org.eclipse.jdt.core.dom.CastExpression;
48import org.eclipse.jdt.core.dom.CatchClause;
49import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor;
50import org.eclipse.jdt.core.dom.ClassInstanceCreation;
51import org.eclipse.jdt.core.dom.CompilationUnit;
52import org.eclipse.jdt.core.dom.ConstructorInvocation;
53import org.eclipse.jdt.core.dom.DoStatement;
54import org.eclipse.jdt.core.dom.EnhancedForStatement;
55import org.eclipse.jdt.core.dom.Expression;
56import org.eclipse.jdt.core.dom.ExpressionStatement;
57import org.eclipse.jdt.core.dom.FieldAccess;
58import org.eclipse.jdt.core.dom.ForStatement;
59import org.eclipse.jdt.core.dom.IBinding;
60import org.eclipse.jdt.core.dom.IMethodBinding;
61import org.eclipse.jdt.core.dom.ITypeBinding;
62import org.eclipse.jdt.core.dom.IVariableBinding;
63import org.eclipse.jdt.core.dom.IfStatement;
64import org.eclipse.jdt.core.dom.InfixExpression;
65import org.eclipse.jdt.core.dom.Initializer;
66import org.eclipse.jdt.core.dom.LambdaExpression;
67import org.eclipse.jdt.core.dom.MethodDeclaration;
68import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
69import org.eclipse.jdt.core.dom.Name;
70import org.eclipse.jdt.core.dom.NullLiteral;
71import org.eclipse.jdt.core.dom.ParenthesizedExpression;
72import org.eclipse.jdt.core.dom.PostfixExpression;
73import org.eclipse.jdt.core.dom.PrefixExpression;
74import org.eclipse.jdt.core.dom.QualifiedName;
75import org.eclipse.jdt.core.dom.ReturnStatement;
76import org.eclipse.jdt.core.dom.SimpleName;
77import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
78import org.eclipse.jdt.core.dom.Statement;
79import org.eclipse.jdt.core.dom.StringLiteral;
80import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor;
81import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
82import org.eclipse.jdt.core.dom.SwitchCase;
83import org.eclipse.jdt.core.dom.SwitchStatement;
84import org.eclipse.jdt.core.dom.TryStatement;
85import org.eclipse.jdt.core.dom.Type;
86import org.eclipse.jdt.core.dom.VariableDeclarationExpression;
87import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
88import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
89import org.eclipse.jdt.core.dom.WhileStatement;
90import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
91import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
92import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext;
93import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
94import org.eclipse.jdt.core.refactoring.CompilationUnitChange;
95import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
96import org.eclipse.jdt.core.refactoring.descriptors.ExtractLocalDescriptor;
97
98import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory;
99import org.eclipse.jdt.internal.corext.Corext;
100import org.eclipse.jdt.internal.corext.SourceRangeFactory;
101import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext;
102import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
103import org.eclipse.jdt.internal.corext.dom.ASTNodes;
104import org.eclipse.jdt.internal.corext.dom.Bindings;
105import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer;
106import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory;
107import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment;
108import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment;
109import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel;
110import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup;
111import org.eclipse.jdt.internal.corext.refactoring.Checks;
112import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
113import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
114import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
115import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
116import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
117import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext;
118import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes;
119import org.eclipse.jdt.internal.corext.refactoring.code.CodeRefactoringUtil;
120import org.eclipse.jdt.internal.corext.refactoring.code.ExtractTempRefactoring;
121import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringAnalyzeUtil;
122import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
123import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer;
124import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser;
125import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
126import org.eclipse.jdt.internal.corext.util.Messages;
127
128import org.eclipse.jdt.ui.JavaElementLabels;
129
130import org.eclipse.jdt.internal.ui.JavaPlugin;
131import org.eclipse.jdt.internal.ui.javaeditor.ASTProvider;
132import org.eclipse.jdt.internal.ui.text.correction.ASTResolving;
133import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels;
134import 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 */
143public 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;
8c911c28 360 private String fSelectedText;
f9bf275d
AE
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
8c911c28 371 * @param string
f9bf275d 372 */
8c911c28 373 public ExtractTempWithAssertsRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength, String selectedText) {
f9bf275d
AE
374 super(unit, selectionStart, selectionLength);
375 Assert.isTrue(selectionStart >= 0);
376 Assert.isTrue(selectionLength >= 0);
377 fSelectionStart= selectionStart;
378 fSelectionLength= selectionLength;
8c911c28 379 fSelectedText = selectedText;
f9bf275d
AE
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
f9bf275d
AE
410 public void setCheckResultForCompileProblems(boolean checkResultForCompileProblems) {
411 fCheckResultForCompileProblems= checkResultForCompileProblems;
412 }
413
414
415 public void setLinkedProposalModel(LinkedProposalModel linkedProposalModel) {
416 fLinkedProposalModel= linkedProposalModel;
417 }
418
a4f82448 419 @SuppressWarnings("restriction")
f9bf275d
AE
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
8c911c28 432 /*
f4143a55 433 * Anna's code from here
8c911c28 434 */
fa08f511
AE
435 if(fragmentsToReplace.length>1){
436
437 ASTNode fullStatement = getStatementFromFragment(fragment);
438
439 Statement assertStatement = getAssertStatement(fCURewrite.getAST());
1b3a0a09 440
92dc3046 441
fa08f511
AE
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);
bdaf6c32 482
26d19d82 483
12636679 484 // The following code is currently not needed, but is kept in case it will be useful in the future
fa08f511
AE
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 }
8c911c28 498 /*
f4143a55 499 * End of Anna's code
8c911c28 500 */
fa08f511 501
1b3a0a09 502 fragment.replace(rewrite, tempName, description);
fa08f511
AE
503
504
f9bf275d
AE
505 if (fLinkedProposalModel != null)
506 fLinkedProposalModel.getPositionGroup(KEY_NAME, true).addPosition(rewrite.track(tempName), false);
507 }
508 }
bdaf6c32 509
fa08f511
AE
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
bdaf6c32 532 private boolean isFullStatement(ASTNode fullStatement) {
fa08f511
AE
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;
bdaf6c32 538 }
fa08f511 539
f4143a55
AE
540 /**
541 *
542 * @param ast the AST the Statement will belong to
a4f82448 543 * @return the assert statement, belonging to the input AST, asserting that the temp == selectedExpression
f4143a55 544 */
1b3a0a09 545 private Statement getAssertStatement(AST ast){
1b3a0a09
AE
546 AssertStatement assertStatement = ast.newAssertStatement();
547 InfixExpression infixExpression = ast.newInfixExpression();
fa08f511 548
1b3a0a09
AE
549 infixExpression.setLeftOperand(ast.newSimpleName(fTempName));
550 infixExpression.setOperator(InfixExpression.Operator.EQUALS);
fa08f511 551
1b3a0a09
AE
552 infixExpression.setRightOperand(ast.newName(fSelectedText));
553 assertStatement.setExpression(infixExpression);
554 StringLiteral stringLiteral = ast.newStringLiteral();
2cbef4f7 555 stringLiteral.setLiteralValue("The Extract Local refactoring has broken the program due to aliasing issues!");
1b3a0a09
AE
556 assertStatement.setMessage(stringLiteral);
557 return assertStatement;
558 }
f9bf275d
AE
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())) {
fa08f511
AE
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;
f9bf275d
AE
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));
fa08f511 621
f9bf275d
AE
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;
a4f82448
AE
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 {
f9bf275d
AE
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) {
f9bf275d
AE
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) {
fa08f511 854 if (isControlStatementBody(locationInParent)) {
f9bf275d
AE
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);
2cbef4f7 1001 int i=0;
f9bf275d
AE
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()) {
fa08f511
AE
1096 case ASTNode.BOOLEAN_LITERAL:
1097 case ASTNode.CHARACTER_LITERAL:
1098 case ASTNode.NULL_LITERAL:
1099 case ASTNode.NUMBER_LITERAL:
1100 return true;
f9bf275d 1101
fa08f511
AE
1102 default:
1103 return false;
f9bf275d
AE
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 }
fa08f511 1218
f9bf275d
AE
1219 public MethodDeclaration getMethodDeclaration(){
1220 return methodDeclaration;
1221 }
1222}