1 11 package org.eclipse.jdt.internal.corext.refactoring.code; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Collection ; 16 import java.util.Collections ; 17 import java.util.Comparator ; 18 import java.util.HashMap ; 19 import java.util.HashSet ; 20 import java.util.Iterator ; 21 import java.util.List ; 22 import java.util.Map ; 23 import java.util.StringTokenizer ; 24 25 import org.eclipse.text.edits.TextEditGroup; 26 27 import org.eclipse.core.runtime.Assert; 28 import org.eclipse.core.runtime.CoreException; 29 import org.eclipse.core.runtime.IProgressMonitor; 30 import org.eclipse.core.runtime.NullProgressMonitor; 31 import org.eclipse.core.runtime.SubProgressMonitor; 32 33 import org.eclipse.ltk.core.refactoring.Change; 34 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 35 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 36 import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; 37 import org.eclipse.ltk.core.refactoring.TextChange; 38 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; 39 40 import org.eclipse.jdt.core.ICompilationUnit; 41 import org.eclipse.jdt.core.IJavaElement; 42 import org.eclipse.jdt.core.IJavaProject; 43 import org.eclipse.jdt.core.JavaModelException; 44 import org.eclipse.jdt.core.compiler.IProblem; 45 import org.eclipse.jdt.core.dom.AST; 46 import org.eclipse.jdt.core.dom.ASTNode; 47 import org.eclipse.jdt.core.dom.ASTVisitor; 48 import org.eclipse.jdt.core.dom.ArrayInitializer; 49 import org.eclipse.jdt.core.dom.Assignment; 50 import org.eclipse.jdt.core.dom.Block; 51 import org.eclipse.jdt.core.dom.BodyDeclaration; 52 import org.eclipse.jdt.core.dom.CastExpression; 53 import org.eclipse.jdt.core.dom.CatchClause; 54 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 55 import org.eclipse.jdt.core.dom.CompilationUnit; 56 import org.eclipse.jdt.core.dom.ConstructorInvocation; 57 import org.eclipse.jdt.core.dom.DoStatement; 58 import org.eclipse.jdt.core.dom.EnhancedForStatement; 59 import org.eclipse.jdt.core.dom.Expression; 60 import org.eclipse.jdt.core.dom.ExpressionStatement; 61 import org.eclipse.jdt.core.dom.FieldAccess; 62 import org.eclipse.jdt.core.dom.ForStatement; 63 import org.eclipse.jdt.core.dom.IBinding; 64 import org.eclipse.jdt.core.dom.IMethodBinding; 65 import org.eclipse.jdt.core.dom.ITypeBinding; 66 import org.eclipse.jdt.core.dom.IVariableBinding; 67 import org.eclipse.jdt.core.dom.IfStatement; 68 import org.eclipse.jdt.core.dom.Initializer; 69 import org.eclipse.jdt.core.dom.MethodDeclaration; 70 import org.eclipse.jdt.core.dom.Name; 71 import org.eclipse.jdt.core.dom.NullLiteral; 72 import org.eclipse.jdt.core.dom.ParenthesizedExpression; 73 import org.eclipse.jdt.core.dom.PostfixExpression; 74 import org.eclipse.jdt.core.dom.PrefixExpression; 75 import org.eclipse.jdt.core.dom.QualifiedName; 76 import org.eclipse.jdt.core.dom.SimpleName; 77 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 78 import org.eclipse.jdt.core.dom.Statement; 79 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; 80 import org.eclipse.jdt.core.dom.SuperConstructorInvocation; 81 import org.eclipse.jdt.core.dom.SwitchCase; 82 import org.eclipse.jdt.core.dom.Type; 83 import org.eclipse.jdt.core.dom.VariableDeclarationExpression; 84 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 85 import org.eclipse.jdt.core.dom.VariableDeclarationStatement; 86 import org.eclipse.jdt.core.dom.WhileStatement; 87 import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; 88 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 89 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 90 import org.eclipse.jdt.core.refactoring.IJavaRefactorings; 91 92 import org.eclipse.jdt.internal.corext.Corext; 93 import org.eclipse.jdt.internal.corext.SourceRange; 94 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 95 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 96 import org.eclipse.jdt.internal.corext.dom.Bindings; 97 import org.eclipse.jdt.internal.corext.dom.ScopeAnalyzer; 98 import org.eclipse.jdt.internal.corext.dom.fragments.ASTFragmentFactory; 99 import org.eclipse.jdt.internal.corext.dom.fragments.IASTFragment; 100 import org.eclipse.jdt.internal.corext.dom.fragments.IExpressionFragment; 101 import org.eclipse.jdt.internal.corext.fix.LinkedProposalModel; 102 import org.eclipse.jdt.internal.corext.fix.LinkedProposalPositionGroup; 103 import org.eclipse.jdt.internal.corext.refactoring.Checks; 104 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor; 105 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; 106 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; 107 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 108 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 109 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStringStatusContext; 110 import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes; 111 import org.eclipse.jdt.internal.corext.refactoring.changes.RefactoringDescriptorChange; 112 import org.eclipse.jdt.internal.corext.refactoring.rename.RefactoringAnalyzeUtil; 113 import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite; 114 import org.eclipse.jdt.internal.corext.refactoring.util.NoCommentSourceRangeComputer; 115 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 116 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; 117 import org.eclipse.jdt.internal.corext.util.Messages; 118 119 import org.eclipse.jdt.ui.JavaElementLabels; 120 121 import org.eclipse.jdt.internal.ui.JavaPlugin; 122 import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; 123 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 124 125 128 public class ExtractTempRefactoring extends ScriptableRefactoring { 129 130 private static final String ATTRIBUTE_REPLACE= "replace"; private static final String ATTRIBUTE_FINAL= "final"; 133 private static final class ForStatementChecker extends ASTVisitor { 134 135 private final Collection fForInitializerVariables; 136 137 private boolean fReferringToForVariable= false; 138 139 public ForStatementChecker(Collection forInitializerVariables) { 140 Assert.isNotNull(forInitializerVariables); 141 fForInitializerVariables= forInitializerVariables; 142 } 143 144 public boolean isReferringToForVariable() { 145 return fReferringToForVariable; 146 } 147 148 public boolean visit(SimpleName node) { 149 IBinding binding= node.resolveBinding(); 150 if (binding != null && fForInitializerVariables.contains(binding)) { 151 fReferringToForVariable= true; 152 } 153 return false; 154 } 155 } 156 157 158 159 private static boolean allArraysEqual(Object [][] arrays, int position) { 160 Object element= arrays[0][position]; 161 for (int i= 0; i < arrays.length; i++) { 162 Object [] array= arrays[i]; 163 if (!element.equals(array[position])) 164 return false; 165 } 166 return true; 167 } 168 169 private static boolean canReplace(IASTFragment fragment) { 170 ASTNode node= fragment.getAssociatedNode(); 171 ASTNode parent= node.getParent(); 172 if (parent instanceof VariableDeclarationFragment) { 173 VariableDeclarationFragment vdf= (VariableDeclarationFragment) parent; 174 if (node.equals(vdf.getName())) 175 return false; 176 } 177 if (isMethodParameter(node)) 178 return false; 179 if (isThrowableInCatchBlock(node)) 180 return false; 181 if (parent instanceof ExpressionStatement) 182 return false; 183 if (isLeftValue(node)) 184 return false; 185 if (isReferringToLocalVariableFromFor((Expression) node)) 186 return false; 187 if (isUsedInForInitializerOrUpdater((Expression) node)) 188 return false; 189 if (parent instanceof SwitchCase) 190 return false; 191 return true; 192 } 193 194 private static Object [] getArrayPrefix(Object [] array, int prefixLength) { 195 Assert.isTrue(prefixLength <= array.length); 196 Assert.isTrue(prefixLength >= 0); 197 Object [] prefix= new Object [prefixLength]; 198 for (int i= 0; i < prefix.length; i++) { 199 prefix[i]= array[i]; 200 } 201 return prefix; 202 } 203 204 private static List getForInitializedVariables(VariableDeclarationExpression variableDeclarations) { 206 List forInitializerVariables= new ArrayList (1); 207 for (Iterator iter= variableDeclarations.fragments().iterator(); iter.hasNext();) { 208 VariableDeclarationFragment fragment= (VariableDeclarationFragment) iter.next(); 209 IVariableBinding binding= fragment.resolveBinding(); 210 if (binding != null) 211 forInitializerVariables.add(binding); 212 } 213 return forInitializerVariables; 214 } 215 216 private static Object [] getLongestArrayPrefix(Object [][] arrays) { 217 int length= -1; 218 if (arrays.length == 0) 219 return new Object [0]; 220 int minArrayLength= arrays[0].length; 221 for (int i= 1; i < arrays.length; i++) 222 minArrayLength= Math.min(minArrayLength, arrays[i].length); 223 224 for (int i= 0; i < minArrayLength; i++) { 225 if (!allArraysEqual(arrays, i)) 226 break; 227 length++; 228 } 229 if (length == -1) 230 return new Object [0]; 231 return getArrayPrefix(arrays[0], length + 1); 232 } 233 234 private static ASTNode[] getParents(ASTNode node) { 235 ASTNode current= node; 236 List parents= new ArrayList (); 237 do { 238 parents.add(current.getParent()); 239 current= current.getParent(); 240 } while (current.getParent() != null); 241 Collections.reverse(parents); 242 return (ASTNode[]) parents.toArray(new ASTNode[parents.size()]); 243 } 244 245 private static boolean isLeftValue(ASTNode node) { 246 ASTNode parent= node.getParent(); 247 if (parent instanceof Assignment) { 248 Assignment assignment= (Assignment) parent; 249 if (assignment.getLeftHandSide() == node) 250 return true; 251 } 252 if (parent instanceof PostfixExpression) 253 return true; 254 if (parent instanceof PrefixExpression) { 255 PrefixExpression.Operator op= ((PrefixExpression) parent).getOperator(); 256 if (op.equals(PrefixExpression.Operator.DECREMENT)) 257 return true; 258 if (op.equals(PrefixExpression.Operator.INCREMENT)) 259 return true; 260 return false; 261 } 262 return false; 263 } 264 265 private static boolean isMethodParameter(ASTNode node) { 266 return (node instanceof SimpleName) && (node.getParent() instanceof SingleVariableDeclaration) && (node.getParent().getParent() instanceof MethodDeclaration); 267 } 268 269 private static boolean isReferringToLocalVariableFromFor(Expression expression) { 270 ASTNode current= expression; 271 ASTNode parent= current.getParent(); 272 while (parent != null && !(parent instanceof BodyDeclaration)) { 273 if (parent instanceof ForStatement) { 274 ForStatement forStmt= (ForStatement) parent; 275 if (forStmt.initializers().contains(current) || forStmt.updaters().contains(current) || forStmt.getExpression() == current) { 276 List initializers= forStmt.initializers(); 277 if (initializers.size() == 1 && initializers.get(0) instanceof VariableDeclarationExpression) { 278 List forInitializerVariables= getForInitializedVariables((VariableDeclarationExpression) initializers.get(0)); 279 ForStatementChecker checker= new ForStatementChecker(forInitializerVariables); 280 expression.accept(checker); 281 if (checker.isReferringToForVariable()) 282 return true; 283 } 284 } 285 } 286 current= parent; 287 parent= current.getParent(); 288 } 289 return false; 290 } 291 292 private static boolean isThrowableInCatchBlock(ASTNode node) { 293 return (node instanceof SimpleName) && (node.getParent() instanceof SingleVariableDeclaration) && (node.getParent().getParent() instanceof CatchClause); 294 } 295 296 private static boolean isUsedInForInitializerOrUpdater(Expression expression) { 297 ASTNode parent= expression.getParent(); 298 if (parent instanceof ForStatement) { 299 ForStatement forStmt= (ForStatement) parent; 300 return forStmt.initializers().contains(expression) || forStmt.updaters().contains(expression); 301 } 302 return false; 303 } 304 305 private static IASTFragment[] retainOnlyReplacableMatches(IASTFragment[] allMatches) { 306 List result= new ArrayList (allMatches.length); 307 for (int i= 0; i < allMatches.length; i++) { 308 if (canReplace(allMatches[i])) 309 result.add(allMatches[i]); 310 } 311 return (IASTFragment[]) result.toArray(new IASTFragment[result.size()]); 312 } 313 314 private CompilationUnit fCompilationUnitNode; 315 316 private CompilationUnitRewrite fCURewrite; 317 318 private ICompilationUnit fCu; 319 320 private boolean fDeclareFinal; 321 322 private String [] fExcludedVariableNames; 323 324 private boolean fReplaceAllOccurrences; 325 326 private IExpressionFragment fSelectedExpression; 328 329 private int fSelectionLength; 330 331 private int fSelectionStart; 332 333 private String fTempName; 334 private String [] fGuessedTempNames; 335 336 private TextChange fChange; 337 338 private LinkedProposalModel fLinkedProposalModel; 339 340 private static final String KEY_NAME= "name"; private static final String KEY_TYPE= "type"; 343 344 350 public ExtractTempRefactoring(ICompilationUnit unit, int selectionStart, int selectionLength) { 351 Assert.isTrue(selectionStart >= 0); 352 Assert.isTrue(selectionLength >= 0); 353 fSelectionStart= selectionStart; 354 fSelectionLength= selectionLength; 355 fCu= unit; 356 fCompilationUnitNode= null; 357 358 fReplaceAllOccurrences= true; fDeclareFinal= false; fTempName= ""; 362 fLinkedProposalModel= null; 363 } 364 365 public ExtractTempRefactoring(CompilationUnit astRoot, int selectionStart, int selectionLength) { 366 Assert.isTrue(selectionStart >= 0); 367 Assert.isTrue(selectionLength >= 0); 368 Assert.isTrue(astRoot.getTypeRoot() instanceof ICompilationUnit); 369 370 fSelectionStart= selectionStart; 371 fSelectionLength= selectionLength; 372 fCu= (ICompilationUnit) astRoot.getTypeRoot(); 373 fCompilationUnitNode= astRoot; 374 375 fReplaceAllOccurrences= true; fDeclareFinal= false; fTempName= ""; 379 fLinkedProposalModel= null; 380 } 381 382 public void setLinkedProposalModel(LinkedProposalModel linkedProposalModel) { 383 fLinkedProposalModel= linkedProposalModel; 384 } 385 386 private void addReplaceExpressionWithTemp() throws JavaModelException { 387 IASTFragment[] fragmentsToReplace= retainOnlyReplacableMatches(getMatchingFragments()); 388 ASTRewrite rewrite= fCURewrite.getASTRewrite(); 390 HashSet seen= new HashSet (); 391 for (int i= 0; i < fragmentsToReplace.length; i++) { 392 IASTFragment fragment= fragmentsToReplace[i]; 393 if (! seen.add(fragment)) 394 continue; 395 SimpleName tempName= fCURewrite.getAST().newSimpleName(fTempName); 396 TextEditGroup description= fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_replace); 397 398 fragment.replace(rewrite, tempName, description); 399 if (fLinkedProposalModel != null) 400 fLinkedProposalModel.getPositionGroup(KEY_NAME, true).addPosition(rewrite.track(tempName), false); 401 } 402 } 403 404 private RefactoringStatus checkExpression() throws JavaModelException { 405 Expression selectedExpression= getSelectedExpression().getAssociatedExpression(); 406 if (selectedExpression != null) { 407 final ASTNode parent= selectedExpression.getParent(); 408 if (selectedExpression instanceof NullLiteral) { 409 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_null_literals); 410 } else if (selectedExpression instanceof ArrayInitializer) { 411 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_array_initializer); 412 } else if (selectedExpression instanceof Assignment) { 413 if (parent instanceof Expression && !(parent instanceof ParenthesizedExpression)) 414 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_assignment); 415 else 416 return null; 417 418 } else if (selectedExpression instanceof SimpleName) { 419 if ((((SimpleName) selectedExpression)).isDeclaration()) 420 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_names_in_declarations); 421 if (parent instanceof QualifiedName && selectedExpression.getLocationInParent() == QualifiedName.NAME_PROPERTY || parent instanceof FieldAccess && selectedExpression.getLocationInParent() == FieldAccess.NAME_PROPERTY) 422 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_select_expression); 423 } 424 } 425 426 return null; 427 } 428 429 private RefactoringStatus checkExpressionFragmentIsRValue() throws JavaModelException { 431 switch (Checks.checkExpressionIsRValue(getSelectedExpression().getAssociatedExpression())) { 432 case Checks.NOT_RVALUE_MISC: 433 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractTempRefactoring_select_expression, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE, null); 434 case Checks.NOT_RVALUE_VOID: 435 return RefactoringStatus.createStatus(RefactoringStatus.FATAL, RefactoringCoreMessages.ExtractTempRefactoring_no_void, null, Corext.getPluginId(), RefactoringStatusCodes.EXPRESSION_NOT_RVALUE_VOID, null); 436 case Checks.IS_RVALUE: 437 return new RefactoringStatus(); 438 default: 439 Assert.isTrue(false); 440 return null; 441 } 442 } 443 444 public TextChange createTextChange(IProgressMonitor pm) throws CoreException { 445 try { 446 pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 3); 447 448 fCURewrite= new CompilationUnitRewrite(fCu, fCompilationUnitNode); 449 fCURewrite.getASTRewrite().setTargetSourceRangeComputer(new NoCommentSourceRangeComputer()); 450 451 doCreateChange(new SubProgressMonitor(pm, 2)); 452 453 return fCURewrite.createChange(RefactoringCoreMessages.ExtractTempRefactoring_change_name, true, new SubProgressMonitor(pm, 1)); 454 } finally { 455 pm.done(); 456 } 457 } 458 459 460 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { 461 fChange= createTextChange(pm); 462 463 RefactoringStatus result= new RefactoringStatus(); 464 if (Arrays.asList(getExcludedVariableNames()).contains(fTempName)) 465 result.addWarning(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable, fTempName)); 466 467 result.merge(checkMatchingFragments()); 468 469 fChange.setKeepPreviewEdits(true); 470 checkNewSource(result); 471 472 return result; 473 } 474 475 private final JDTRefactoringDescriptor createRefactoringDescriptor() { 476 final Map arguments= new HashMap (); 477 String project= null; 478 IJavaProject javaProject= fCu.getJavaProject(); 479 if (javaProject != null) 480 project= javaProject.getElementName(); 481 final String description= Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description_short, fTempName); 482 final String expression= ASTNodes.asString(fSelectedExpression.getAssociatedExpression()); 483 final String header= Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_descriptor_description, new String [] { fTempName, expression}); 484 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); 485 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_name_pattern, fTempName)); 486 final BodyDeclaration decl= (BodyDeclaration) ASTNodes.getParent(fSelectedExpression.getAssociatedExpression(), BodyDeclaration.class); 487 if (decl instanceof MethodDeclaration) { 488 final IMethodBinding method= ((MethodDeclaration) decl).resolveBinding(); 489 final String label= method != null ? BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED) : '{' + JavaElementLabels.ELLIPSIS_STRING + '}'; 490 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_destination_pattern, label)); 491 } 492 comment.addSetting(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_expression_pattern, expression)); 493 if (fReplaceAllOccurrences) 494 comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_replace_occurrences); 495 if (fDeclareFinal) 496 comment.addSetting(RefactoringCoreMessages.ExtractTempRefactoring_declare_final); 497 final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.EXTRACT_LOCAL_VARIABLE, project, description, comment.asString(), arguments, RefactoringDescriptor.NONE); 498 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCu)); 499 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_NAME, fTempName); 500 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer (fSelectionStart).toString() + " " + new Integer (fSelectionLength).toString()); arguments.put(ATTRIBUTE_REPLACE, Boolean.valueOf(fReplaceAllOccurrences).toString()); 502 arguments.put(ATTRIBUTE_FINAL, Boolean.valueOf(fDeclareFinal).toString()); 503 return descriptor; 504 } 505 506 private void doCreateChange(IProgressMonitor pm) throws CoreException { 507 try { 508 pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 1); 509 try { 510 createTempDeclaration(); 511 } catch (CoreException exception) { 512 JavaPlugin.log(exception); 513 } 514 addReplaceExpressionWithTemp(); 515 } finally { 516 pm.done(); 517 } 518 } 519 520 private void checkNewSource(RefactoringStatus result) throws CoreException { 521 String newCuSource= fChange.getPreviewContent(new NullProgressMonitor()); 522 CompilationUnit newCUNode= new RefactoringASTParser(AST.JLS3).parse(newCuSource, fCu, true, true, null); 523 IProblem[] newProblems= RefactoringAnalyzeUtil.getIntroducedCompileProblems(newCUNode, fCompilationUnitNode); 524 for (int i= 0; i < newProblems.length; i++) { 525 IProblem problem= newProblems[i]; 526 if (problem.isError()) 527 result.addEntry(new RefactoringStatusEntry((problem.isError() ? RefactoringStatus.ERROR : RefactoringStatus.WARNING), problem.getMessage(), new JavaStringStatusContext(newCuSource, new SourceRange(problem)))); 528 } 529 } 530 531 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { 532 try { 533 pm.beginTask("", 6); 535 RefactoringStatus result= Checks.validateModifiesFiles(ResourceUtil.getFiles(new ICompilationUnit[] { fCu}), getValidationContext()); 536 if (result.hasFatalError()) 537 return result; 538 539 if (fCompilationUnitNode == null) { 540 fCompilationUnitNode= RefactoringASTParser.parseWithASTProvider(fCu, true, new SubProgressMonitor(pm, 3)); 541 } else { 542 pm.worked(3); 543 } 544 545 result.merge(checkSelection(new SubProgressMonitor(pm, 3))); 546 if (!result.hasFatalError() && isLiteralNodeSelected()) 547 fReplaceAllOccurrences= false; 548 return result; 549 550 } finally { 551 pm.done(); 552 } 553 } 554 555 private RefactoringStatus checkMatchingFragments() throws JavaModelException { 556 RefactoringStatus result= new RefactoringStatus(); 557 IASTFragment[] matchingFragments= getMatchingFragments(); 558 for (int i= 0; i < matchingFragments.length; i++) { 559 ASTNode node= matchingFragments[i].getAssociatedNode(); 560 if (isLeftValue(node) && !isReferringToLocalVariableFromFor((Expression) node)) { 561 String msg= RefactoringCoreMessages.ExtractTempRefactoring_assigned_to; 562 result.addWarning(msg, JavaStatusContext.create(fCu, node)); 563 } 564 } 565 return result; 566 } 567 568 private RefactoringStatus checkSelection(IProgressMonitor pm) throws JavaModelException { 569 try { 570 pm.beginTask("", 8); 572 IExpressionFragment selectedExpression= getSelectedExpression(); 573 574 if (selectedExpression == null) { 575 String message= RefactoringCoreMessages.ExtractTempRefactoring_select_expression; 576 return CodeRefactoringUtil.checkMethodSyntaxErrors(fSelectionStart, fSelectionLength, fCompilationUnitNode, message); 577 } 578 pm.worked(1); 579 580 if (isUsedInExplicitConstructorCall()) 581 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_explicit_constructor); 582 pm.worked(1); 583 584 if (getEnclosingBodyNode() == null) 585 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_expr_in_method_or_initializer); 586 pm.worked(1); 587 588 ASTNode associatedNode= selectedExpression.getAssociatedNode(); 589 if (associatedNode instanceof Name && associatedNode.getParent() instanceof ClassInstanceCreation && associatedNode.getLocationInParent() == ClassInstanceCreation.TYPE_PROPERTY) 590 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_name_in_new); 591 pm.worked(1); 592 593 RefactoringStatus result= new RefactoringStatus(); 594 result.merge(checkExpression()); 595 if (result.hasFatalError()) 596 return result; 597 pm.worked(1); 598 599 result.merge(checkExpressionFragmentIsRValue()); 600 if (result.hasFatalError()) 601 return result; 602 pm.worked(1); 603 604 if (isUsedInForInitializerOrUpdater(getSelectedExpression().getAssociatedExpression())) 605 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_for_initializer_updater); 606 pm.worked(1); 607 608 if (isReferringToLocalVariableFromFor(getSelectedExpression().getAssociatedExpression())) 609 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.ExtractTempRefactoring_refers_to_for_variable); 610 pm.worked(1); 611 612 return result; 613 } finally { 614 pm.done(); 615 } 616 } 617 618 public RefactoringStatus checkTempName(String newName) { 619 RefactoringStatus status= Checks.checkTempName(newName); 620 if (Arrays.asList(getExcludedVariableNames()).contains(newName)) 621 status.addWarning(Messages.format(RefactoringCoreMessages.ExtractTempRefactoring_another_variable, newName)); 622 return status; 623 } 624 625 private void createAndInsertTempDeclaration() throws CoreException { 626 Expression initializer= getSelectedExpression().createCopyTarget(fCURewrite.getASTRewrite()); 627 VariableDeclarationStatement vds= createTempDeclaration(initializer); 628 629 if ((!fReplaceAllOccurrences) || (retainOnlyReplacableMatches(getMatchingFragments()).length <= 1)) { 630 insertAt(getSelectedExpression().getAssociatedNode(), vds); 631 return; 632 } 633 634 ASTNode[] firstReplaceNodeParents= getParents(getFirstReplacedExpression().getAssociatedNode()); 635 ASTNode[] commonPath= findDeepestCommonSuperNodePathForReplacedNodes(); 636 Assert.isTrue(commonPath.length <= firstReplaceNodeParents.length); 637 638 ASTNode deepestCommonParent= firstReplaceNodeParents[commonPath.length - 1]; 639 if (deepestCommonParent instanceof Block) 640 insertAt(firstReplaceNodeParents[commonPath.length], vds); 641 else 642 insertAt(deepestCommonParent, vds); 643 } 644 645 private VariableDeclarationStatement createTempDeclaration(Expression initializer) throws CoreException { 646 AST ast= fCURewrite.getAST(); 647 648 VariableDeclarationFragment vdf= ast.newVariableDeclarationFragment(); 649 vdf.setName(ast.newSimpleName(fTempName)); 650 vdf.setInitializer(initializer); 651 652 VariableDeclarationStatement vds= ast.newVariableDeclarationStatement(vdf); 653 if (fDeclareFinal) { 654 vds.modifiers().add(ast.newModifier(ModifierKeyword.FINAL_KEYWORD)); 655 } 656 vds.setType(createTempType()); 657 658 if (fLinkedProposalModel != null) { 659 ASTRewrite rewrite= fCURewrite.getASTRewrite(); 660 LinkedProposalPositionGroup nameGroup= fLinkedProposalModel.getPositionGroup(KEY_NAME, true); 661 nameGroup.addPosition(rewrite.track(vdf.getName()), true); 662 663 String [] nameSuggestions= guessTempNames(); 664 if (nameSuggestions.length > 0 && !nameSuggestions[0].equals(fTempName)) { 665 nameGroup.addProposal(fTempName, null, nameSuggestions.length + 1); 666 } 667 for (int i= 0; i < nameSuggestions.length; i++) { 668 nameGroup.addProposal(nameSuggestions[i], null, nameSuggestions.length - i); 669 } 670 } 671 return vds; 672 } 673 674 private void insertAt(ASTNode target, Statement declaration) throws JavaModelException { 675 ASTRewrite rewrite= fCURewrite.getASTRewrite(); 676 TextEditGroup groupDescription= fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable); 677 678 ASTNode parent= target.getParent(); 679 while (! (parent instanceof Block)) { 680 StructuralPropertyDescriptor locationInParent= target.getLocationInParent(); 681 if (locationInParent == IfStatement.THEN_STATEMENT_PROPERTY 682 || locationInParent == IfStatement.ELSE_STATEMENT_PROPERTY 683 || locationInParent == ForStatement.BODY_PROPERTY 684 || locationInParent == EnhancedForStatement.BODY_PROPERTY 685 || locationInParent == DoStatement.BODY_PROPERTY 686 || locationInParent == WhileStatement.BODY_PROPERTY) { 687 Block replacement= rewrite.getAST().newBlock(); 688 ListRewrite replacementRewrite= rewrite.getListRewrite(replacement, Block.STATEMENTS_PROPERTY); 689 replacementRewrite.insertFirst(declaration, null); 690 replacementRewrite.insertLast(rewrite.createMoveTarget(target), null); 691 rewrite.replace(target, replacement, groupDescription); 692 return; 693 } 694 target= parent; 695 parent= parent.getParent(); 696 } 697 ListRewrite listRewrite= rewrite.getListRewrite(parent, Block.STATEMENTS_PROPERTY); 698 listRewrite.insertBefore(declaration, target, groupDescription); 699 } 700 701 public Change createChange(IProgressMonitor pm) throws CoreException { 702 try { 703 pm.beginTask(RefactoringCoreMessages.ExtractTempRefactoring_checking_preconditions, 1); 704 JDTRefactoringDescriptor descriptor= createRefactoringDescriptor(); 705 return new RefactoringDescriptorChange(descriptor, RefactoringCoreMessages.ExtractTempRefactoring_extract_temp, new Change[] { fChange}); 706 } finally { 707 pm.done(); 708 } 709 } 710 711 private void createTempDeclaration() throws CoreException { 712 if (shouldReplaceSelectedExpressionWithTempDeclaration()) 713 replaceSelectedExpressionWithTempDeclaration(); 714 else 715 createAndInsertTempDeclaration(); 716 } 717 718 public boolean declareFinal() { 719 return fDeclareFinal; 720 } 721 722 private ASTNode[] findDeepestCommonSuperNodePathForReplacedNodes() throws JavaModelException { 723 ASTNode[] matchNodes= getMatchNodes(); 724 725 ASTNode[][] matchingNodesParents= new ASTNode[matchNodes.length][]; 726 for (int i= 0; i < matchNodes.length; i++) { 727 matchingNodesParents[i]= getParents(matchNodes[i]); 728 } 729 List l= Arrays.asList(getLongestArrayPrefix(matchingNodesParents)); 730 return (ASTNode[]) l.toArray(new ASTNode[l.size()]); 731 } 732 733 private Block getEnclosingBodyNode() throws JavaModelException { 734 ASTNode node= getSelectedExpression().getAssociatedNode(); 735 do { 736 switch (node.getNodeType()) { 737 case ASTNode.METHOD_DECLARATION: 738 return ((MethodDeclaration) node).getBody(); 739 case ASTNode.INITIALIZER: 740 return ((Initializer) node).getBody(); 741 } 742 node= node.getParent(); 743 } while (node != null); 744 return null; 745 } 746 747 private String [] getExcludedVariableNames() { 748 if (fExcludedVariableNames == null) { 749 try { 750 IBinding[] bindings= new ScopeAnalyzer(fCompilationUnitNode).getDeclarationsInScope(getSelectedExpression().getStartPosition(), ScopeAnalyzer.VARIABLES); 751 fExcludedVariableNames= new String [bindings.length]; 752 for (int i= 0; i < bindings.length; i++) { 753 fExcludedVariableNames[i]= bindings[i].getName(); 754 } 755 } catch (JavaModelException e) { 756 fExcludedVariableNames= new String [0]; 757 } 758 } 759 return fExcludedVariableNames; 760 } 761 762 private IExpressionFragment getFirstReplacedExpression() throws JavaModelException { 763 if (!fReplaceAllOccurrences) 764 return getSelectedExpression(); 765 IASTFragment[] nodesToReplace= retainOnlyReplacableMatches(getMatchingFragments()); 766 if (nodesToReplace.length == 0) 767 return getSelectedExpression(); 768 Comparator comparator= new Comparator () { 769 770 public int compare(Object o1, Object o2) { 771 return ((IASTFragment) o1).getStartPosition() - ((IASTFragment) o2).getStartPosition(); 772 } 773 }; 774 Arrays.sort(nodesToReplace, comparator); 775 return (IExpressionFragment) nodesToReplace[0]; 776 } 777 778 private IASTFragment[] getMatchingFragments() throws JavaModelException { 779 if (fReplaceAllOccurrences) { 780 IASTFragment[] allMatches= ASTFragmentFactory.createFragmentForFullSubtree(getEnclosingBodyNode()).getSubFragmentsMatching(getSelectedExpression()); 781 return allMatches; 782 } else 783 return new IASTFragment[] { getSelectedExpression()}; 784 } 785 786 private ASTNode[] getMatchNodes() throws JavaModelException { 787 IASTFragment[] matches= retainOnlyReplacableMatches(getMatchingFragments()); 788 ASTNode[] result= new ASTNode[matches.length]; 789 for (int i= 0; i < matches.length; i++) 790 result[i]= matches[i].getAssociatedNode(); 791 return result; 792 } 793 794 public String getName() { 795 return RefactoringCoreMessages.ExtractTempRefactoring_name; 796 } 797 798 799 private IExpressionFragment getSelectedExpression() throws JavaModelException { 800 if (fSelectedExpression != null) 801 return fSelectedExpression; 802 IASTFragment selectedFragment= ASTFragmentFactory.createFragmentForSourceRange(new SourceRange(fSelectionStart, fSelectionLength), fCompilationUnitNode, fCu); 803 804 if (selectedFragment instanceof IExpressionFragment && !Checks.isInsideJavadoc(selectedFragment.getAssociatedNode())) { 805 fSelectedExpression= (IExpressionFragment) selectedFragment; 806 } else if (selectedFragment != null) { 807 if (selectedFragment.getAssociatedNode() instanceof ExpressionStatement) { 808 ExpressionStatement exprStatement= (ExpressionStatement) selectedFragment.getAssociatedNode(); 809 Expression expression= exprStatement.getExpression(); 810 fSelectedExpression= (IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(expression); 811 } else if (selectedFragment.getAssociatedNode() instanceof Assignment) { 812 Assignment assignment= (Assignment) selectedFragment.getAssociatedNode(); 813 fSelectedExpression= (IExpressionFragment) ASTFragmentFactory.createFragmentForFullSubtree(assignment); 814 } 815 } 816 817 if (fSelectedExpression != null && Checks.isEnumCase(fSelectedExpression.getAssociatedExpression().getParent())) { 818 fSelectedExpression= null; 819 } 820 821 return fSelectedExpression; 822 } 823 824 private Type createTempType() throws CoreException { 825 Expression expression= getSelectedExpression().getAssociatedExpression(); 826 827 Type resultingType= null; 828 ITypeBinding typeBinding= expression.resolveTypeBinding(); 829 830 ASTRewrite rewrite= fCURewrite.getASTRewrite(); 831 AST ast= rewrite.getAST(); 832 833 if (expression instanceof ClassInstanceCreation) { 834 resultingType= (Type) rewrite.createCopyTarget(((ClassInstanceCreation) expression).getType()); 835 } else if (expression instanceof CastExpression) { 836 resultingType= (Type) rewrite.createCopyTarget(((CastExpression) expression).getType()); 837 } else { 838 if (typeBinding == null) { 839 typeBinding= ASTResolving.guessBindingForReference(expression); 840 } 841 if (typeBinding != null) { 842 typeBinding= Bindings.normalizeForDeclarationUse(typeBinding, ast); 843 resultingType= fCURewrite.getImportRewrite().addImport(typeBinding, ast); 844 } else { 845 resultingType= ast.newSimpleType(ast.newSimpleName("Object")); } 847 } 848 if (fLinkedProposalModel != null) { 849 LinkedProposalPositionGroup typeGroup= fLinkedProposalModel.getPositionGroup(KEY_TYPE, true); 850 typeGroup.addPosition(rewrite.track(resultingType), false); 851 if (typeBinding != null) { 852 ITypeBinding[] relaxingTypes= ASTResolving.getNarrowingTypes(ast, typeBinding); 853 for (int i= 0; i < relaxingTypes.length; i++) { 854 typeGroup.addProposal(relaxingTypes[i], fCURewrite.getCu(), relaxingTypes.length - i); 855 } 856 } 857 } 858 return resultingType; 859 } 860 861 public String guessTempName() { 862 String [] proposals= guessTempNames(); 863 if (proposals.length == 0) 864 return fTempName; 865 else 866 return proposals[0]; 867 } 868 869 872 public String [] guessTempNames() { 873 if (fGuessedTempNames == null) { 874 try { 875 Expression expression= getSelectedExpression().getAssociatedExpression(); 876 if (expression != null) { 877 ITypeBinding binding= expression.resolveTypeBinding(); 878 fGuessedTempNames= StubUtility.getVariableNameSuggestions(StubUtility.LOCAL, fCu.getJavaProject(), binding, expression, Arrays.asList(getExcludedVariableNames())); 879 } 880 } catch (JavaModelException e) { 881 } 882 if (fGuessedTempNames == null) 883 fGuessedTempNames= new String [0]; 884 } 885 return fGuessedTempNames; 886 } 887 888 private boolean isLiteralNodeSelected() throws JavaModelException { 889 IExpressionFragment fragment= getSelectedExpression(); 890 if (fragment == null) 891 return false; 892 Expression expression= fragment.getAssociatedExpression(); 893 if (expression == null) 894 return false; 895 switch (expression.getNodeType()) { 896 case ASTNode.BOOLEAN_LITERAL: 897 case ASTNode.CHARACTER_LITERAL: 898 case ASTNode.NULL_LITERAL: 899 case ASTNode.NUMBER_LITERAL: 900 return true; 901 902 default: 903 return false; 904 } 905 } 906 907 private boolean isUsedInExplicitConstructorCall() throws JavaModelException { 908 Expression selectedExpression= getSelectedExpression().getAssociatedExpression(); 909 if (ASTNodes.getParent(selectedExpression, ConstructorInvocation.class) != null) 910 return true; 911 if (ASTNodes.getParent(selectedExpression, SuperConstructorInvocation.class) != null) 912 return true; 913 return false; 914 } 915 916 public boolean replaceAllOccurrences() { 917 return fReplaceAllOccurrences; 918 } 919 920 private void replaceSelectedExpressionWithTempDeclaration() throws CoreException { 921 ASTRewrite rewrite= fCURewrite.getASTRewrite(); 922 Expression selectedExpression= getSelectedExpression().getAssociatedExpression(); 924 Expression initializer= (Expression) rewrite.createMoveTarget(selectedExpression); 925 ASTNode replacement= createTempDeclaration(initializer); 927 ExpressionStatement parent= (ExpressionStatement) selectedExpression.getParent(); 928 if (ASTNodes.isControlStatementBody(parent.getLocationInParent())) { 929 Block block= rewrite.getAST().newBlock(); 930 block.statements().add(replacement); 931 replacement= block; 932 933 } 934 rewrite.replace(parent, replacement, fCURewrite.createGroupDescription(RefactoringCoreMessages.ExtractTempRefactoring_declare_local_variable)); 935 } 936 937 public void setDeclareFinal(boolean declareFinal) { 938 fDeclareFinal= declareFinal; 939 } 940 941 public void setReplaceAllOccurrences(boolean replaceAllOccurrences) { 942 fReplaceAllOccurrences= replaceAllOccurrences; 943 } 944 945 public void setTempName(String newName) { 946 fTempName= newName; 947 } 948 949 private boolean shouldReplaceSelectedExpressionWithTempDeclaration() throws JavaModelException { 950 IExpressionFragment selectedFragment= getSelectedExpression(); 951 return selectedFragment.getAssociatedNode().getParent() instanceof ExpressionStatement 952 && selectedFragment.matches(ASTFragmentFactory.createFragmentForFullSubtree(selectedFragment.getAssociatedNode())); 953 } 954 955 public RefactoringStatus initialize(final RefactoringArguments arguments) { 956 if (arguments instanceof JavaRefactoringArguments) { 957 final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; 958 final String selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION); 959 if (selection != null) { 960 int offset= -1; 961 int length= -1; 962 final StringTokenizer tokenizer= new StringTokenizer (selection); 963 if (tokenizer.hasMoreTokens()) 964 offset= Integer.valueOf(tokenizer.nextToken()).intValue(); 965 if (tokenizer.hasMoreTokens()) 966 length= Integer.valueOf(tokenizer.nextToken()).intValue(); 967 if (offset >= 0 && length >= 0) { 968 fSelectionStart= offset; 969 fSelectionLength= length; 970 } else 971 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object [] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION})); 972 } else 973 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION)); 974 final String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT); 975 if (handle != null) { 976 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 977 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT) 978 return createInputFatalStatus(element, IJavaRefactorings.EXTRACT_LOCAL_VARIABLE); 979 else 980 fCu= (ICompilationUnit) element; 981 } else 982 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT)); 983 final String name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME); 984 if (name != null && !"".equals(name)) fTempName= name; 986 else 987 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME)); 988 final String replace= extended.getAttribute(ATTRIBUTE_REPLACE); 989 if (replace != null) { 990 fReplaceAllOccurrences= Boolean.valueOf(replace).booleanValue(); 991 } else 992 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_REPLACE)); 993 final String declareFinal= extended.getAttribute(ATTRIBUTE_FINAL); 994 if (declareFinal != null) { 995 fDeclareFinal= Boolean.valueOf(declareFinal).booleanValue(); 996 } else 997 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_FINAL)); 998 } else 999 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); 1000 return new RefactoringStatus(); 1001 } 1002} 1003 | Popular Tags |