1 11 package org.eclipse.jdt.internal.corext.refactoring.code; 12 13 import java.util.ArrayList ; 14 import java.util.Collection ; 15 import java.util.HashMap ; 16 import java.util.Iterator ; 17 import java.util.List ; 18 import java.util.Map ; 19 import java.util.StringTokenizer ; 20 21 import org.eclipse.text.edits.MultiTextEdit; 22 import org.eclipse.text.edits.TextEditGroup; 23 24 import org.eclipse.core.runtime.Assert; 25 import org.eclipse.core.runtime.CoreException; 26 import org.eclipse.core.runtime.IProgressMonitor; 27 import org.eclipse.core.runtime.IStatus; 28 import org.eclipse.core.runtime.NullProgressMonitor; 29 import org.eclipse.core.runtime.OperationCanceledException; 30 import org.eclipse.core.runtime.SubProgressMonitor; 31 32 import org.eclipse.ltk.core.refactoring.Change; 33 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 34 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 35 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; 36 37 import org.eclipse.jdt.core.ICompilationUnit; 38 import org.eclipse.jdt.core.IJavaElement; 39 import org.eclipse.jdt.core.IJavaProject; 40 import org.eclipse.jdt.core.IMethod; 41 import org.eclipse.jdt.core.IType; 42 import org.eclipse.jdt.core.JavaModelException; 43 import org.eclipse.jdt.core.dom.AST; 44 import org.eclipse.jdt.core.dom.ASTNode; 45 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 46 import org.eclipse.jdt.core.dom.Block; 47 import org.eclipse.jdt.core.dom.BodyDeclaration; 48 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 49 import org.eclipse.jdt.core.dom.CompilationUnit; 50 import org.eclipse.jdt.core.dom.ConstructorInvocation; 51 import org.eclipse.jdt.core.dom.Expression; 52 import org.eclipse.jdt.core.dom.ExpressionStatement; 53 import org.eclipse.jdt.core.dom.IMethodBinding; 54 import org.eclipse.jdt.core.dom.ITypeBinding; 55 import org.eclipse.jdt.core.dom.MethodDeclaration; 56 import org.eclipse.jdt.core.dom.MethodInvocation; 57 import org.eclipse.jdt.core.dom.Modifier; 58 import org.eclipse.jdt.core.dom.Name; 59 import org.eclipse.jdt.core.dom.ParameterizedType; 60 import org.eclipse.jdt.core.dom.ReturnStatement; 61 import org.eclipse.jdt.core.dom.SimpleName; 62 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 63 import org.eclipse.jdt.core.dom.StructuralPropertyDescriptor; 64 import org.eclipse.jdt.core.dom.SuperConstructorInvocation; 65 import org.eclipse.jdt.core.dom.Type; 66 import org.eclipse.jdt.core.dom.TypeParameter; 67 import org.eclipse.jdt.core.dom.VariableDeclaration; 68 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 69 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 70 import org.eclipse.jdt.core.refactoring.IJavaRefactorings; 71 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; 72 import org.eclipse.jdt.core.search.IJavaSearchConstants; 73 import org.eclipse.jdt.core.search.IJavaSearchScope; 74 import org.eclipse.jdt.core.search.SearchMatch; 75 import org.eclipse.jdt.core.search.SearchPattern; 76 77 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 78 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 79 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 80 import org.eclipse.jdt.internal.corext.dom.Bindings; 81 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; 82 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 83 import org.eclipse.jdt.internal.corext.refactoring.Checks; 84 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; 85 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor; 86 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; 87 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 88 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; 89 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; 90 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; 91 import org.eclipse.jdt.internal.corext.refactoring.changes.CompilationUnitChange; 92 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; 93 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationStateChange; 94 import org.eclipse.jdt.internal.corext.refactoring.typeconstraints.ASTCreator; 95 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; 96 import org.eclipse.jdt.internal.corext.util.JdtFlags; 97 import org.eclipse.jdt.internal.corext.util.Messages; 98 import org.eclipse.jdt.internal.corext.util.SearchUtils; 99 100 import org.eclipse.jdt.ui.JavaElementLabels; 101 102 import org.eclipse.jdt.internal.ui.JavaUIStatus; 103 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 104 105 110 public class IntroduceFactoryRefactoring extends ScriptableRefactoring { 111 112 private static final String ATTRIBUTE_PROTECT= "protect"; 114 118 private ICompilationUnit fCUHandle; 119 120 124 private CompilationUnit fCU; 125 126 130 private ICompilationUnit fFactoryUnitHandle; 131 132 138 private int fSelectionStart; 139 140 146 private int fSelectionLength; 147 148 151 private ASTNode fSelectedNode; 152 153 156 private IMethodBinding fCtorBinding; 157 158 162 private AbstractTypeDeclaration fCtorOwningClass; 163 164 167 private String fNewMethodName= null; 168 169 173 private SearchResultGroup[] fAllCallsTo; 174 175 178 private AbstractTypeDeclaration fFactoryOwningClass; 179 180 183 private MethodDeclaration fFactoryMethod= null; 184 185 189 private String [] fFormalArgNames= null; 190 191 195 private ITypeBinding[] fArgTypes; 196 197 200 private boolean fCtorIsVarArgs; 201 202 206 private boolean fProtectConstructor= true; 207 208 213 private ImportRewrite fImportRewriter; 214 215 219 private boolean fCallSitesInBinaryUnits; 220 221 224 private CompilationUnit fFactoryCU; 225 226 230 private String fFactoryClassName; 231 232 private int fConstructorVisibility= Modifier.PRIVATE; 233 234 241 public IntroduceFactoryRefactoring(ICompilationUnit cu, int selectionStart, int selectionLength) { 242 Assert.isTrue(selectionStart >= 0); 243 Assert.isTrue(selectionLength >= 0); 244 fSelectionStart= selectionStart; 245 fSelectionLength= selectionLength; 246 fCUHandle= cu; 247 if (cu != null) 248 initialize(); 249 } 250 251 private void initialize() { 252 fCU= ASTCreator.createAST(fCUHandle, null); 253 } 254 255 264 private ASTNode getTargetNode(ICompilationUnit unit, int offset, int length) { 265 ASTNode node= ASTNodes.getNormalizedNode(NodeFinder.perform(fCU, offset, length)); 266 if (node.getNodeType() == ASTNode.CLASS_INSTANCE_CREATION) 267 return node; 268 if (node.getNodeType() == ASTNode.METHOD_DECLARATION && ((MethodDeclaration)node).isConstructor()) 269 return node; 270 StructuralPropertyDescriptor location= node.getLocationInParent(); 272 ASTNode parent= node.getParent(); 273 if (location == ClassInstanceCreation.TYPE_PROPERTY) { 274 return parent; 275 } else if (location == MethodDeclaration.NAME_PROPERTY && ((MethodDeclaration)parent).isConstructor()) { 276 return parent; 277 } 278 return null; 279 } 280 281 288 private RefactoringStatus checkSelection(IProgressMonitor pm) throws JavaModelException { 289 try { 290 pm.beginTask(RefactoringCoreMessages.IntroduceFactory_examiningSelection, 2); 291 292 fSelectedNode= getTargetNode(fCUHandle, fSelectionStart, fSelectionLength); 293 294 if (fSelectedNode == null) 295 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_notAConstructorInvocation); 296 297 if (fSelectedNode instanceof ClassInstanceCreation) { 300 ClassInstanceCreation classInstanceCreation= (ClassInstanceCreation)fSelectedNode; 301 fCtorBinding= classInstanceCreation.resolveConstructorBinding(); 302 } else if (fSelectedNode instanceof MethodDeclaration) { 303 MethodDeclaration methodDeclaration= (MethodDeclaration)fSelectedNode; 304 fCtorBinding= methodDeclaration.resolveBinding(); 305 } 306 307 if (fCtorBinding == null) 308 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_unableToResolveConstructorBinding); 309 310 fCtorBinding= fCtorBinding.getMethodDeclaration(); 313 314 if (fNewMethodName == null) 315 fNewMethodName= "create" + fCtorBinding.getName(); 317 pm.worked(1); 318 319 if (fCtorBinding.getDeclaringClass().isNested()) 321 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_unsupportedNestedTypes); 322 323 ITypeBinding ctorType= fCtorBinding.getDeclaringClass(); 324 IType ctorOwningType= (IType) ctorType.getJavaElement(); 325 326 if (ctorOwningType.isBinary()) 327 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_constructorInBinaryClass); 329 if (ctorOwningType.isEnum()) 330 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_constructorInEnum); 332 333 fFactoryUnitHandle= ctorOwningType.getCompilationUnit(); 335 fFactoryCU= getASTFor(fFactoryUnitHandle); 336 337 Name ctorOwnerName= (Name) NodeFinder.perform(fFactoryCU, ctorOwningType.getNameRange()); 338 339 fCtorOwningClass= (AbstractTypeDeclaration) ASTNodes.getParent(ctorOwnerName, AbstractTypeDeclaration.class); 340 fFactoryOwningClass= fCtorOwningClass; 341 342 pm.worked(1); 343 344 return new RefactoringStatus(); 345 } finally { 346 pm.done(); 347 } 348 } 349 350 353 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { 354 try { 355 pm.beginTask(RefactoringCoreMessages.IntroduceFactory_checkingActivation, 1); 356 357 if (!fCUHandle.isStructureKnown()) 358 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_syntaxError); 359 360 return checkSelection(new SubProgressMonitor(pm, 1)); 361 } finally { 362 pm.done(); 363 } 364 } 365 366 373 private ICompilationUnit[] collectAffectedUnits(SearchResultGroup[] searchHits) { 374 Collection result= new ArrayList (); 375 boolean hitInFactoryClass= false; 376 377 for(int i=0; i < searchHits.length; i++) { 378 SearchResultGroup rg= searchHits[i]; 379 ICompilationUnit icu= rg.getCompilationUnit(); 380 381 result.add(icu); 382 if (icu.equals(fFactoryUnitHandle)) 383 hitInFactoryClass= true; 384 } 385 if (!hitInFactoryClass) 386 result.add(fFactoryUnitHandle); 387 return (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]); 388 } 389 390 394 private SearchPattern createSearchPattern(IMethod ctor, IMethodBinding methodBinding) { 395 Assert.isNotNull(methodBinding, 396 RefactoringCoreMessages.IntroduceFactory_noBindingForSelectedConstructor); 397 398 if (ctor != null) 399 return SearchPattern.createPattern(ctor, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE); 400 else { StringBuffer buf= new StringBuffer (); 403 404 buf.append(methodBinding.getDeclaringClass().getQualifiedName()) 405 .append("("); for(int i=0; i < fArgTypes.length; i++) { 407 if (i != 0) 408 buf.append(","); buf.append(fArgTypes[i].getQualifiedName()); 410 } 411 buf.append(")"); return SearchPattern.createPattern(buf.toString(), IJavaSearchConstants.CONSTRUCTOR, 413 IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE); 414 } 415 } 416 417 private IJavaSearchScope createSearchScope(IMethod ctor, IMethodBinding binding) throws JavaModelException { 418 if (ctor != null) { 419 return RefactoringScopeFactory.create(ctor); 420 } else { 421 ITypeBinding type= Bindings.getTopLevelType(binding.getDeclaringClass()); 422 return RefactoringScopeFactory.create(type.getJavaElement()); 423 } 424 } 425 426 431 private SearchResultGroup[] excludeBinaryUnits(SearchResultGroup[] groups) { 432 Collection result= new ArrayList (); 433 434 for (int i = 0; i < groups.length; i++) { 435 SearchResultGroup rg= groups[i]; 436 ICompilationUnit unit= rg.getCompilationUnit(); 437 438 if (unit != null) result.add(rg); 440 else 441 fCallSitesInBinaryUnits= true; 442 } 443 return (SearchResultGroup[]) result.toArray(new SearchResultGroup[result.size()]); 444 } 445 446 455 private SearchResultGroup[] searchForCallsTo(IMethodBinding methodBinding, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { 456 IMethod method= (IMethod) methodBinding.getJavaElement(); 457 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(createSearchPattern(method, methodBinding)); 458 engine.setFiltering(true, true); 459 engine.setScope(createSearchScope(method, methodBinding)); 460 engine.setStatus(status); 461 engine.searchPattern(new SubProgressMonitor(pm, 1)); 462 return (SearchResultGroup[]) engine.getResults(); 463 } 464 465 477 private SearchResultGroup[] findAllCallsTo(IMethodBinding ctorBinding, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { 478 SearchResultGroup[] groups= excludeBinaryUnits(searchForCallsTo(ctorBinding, pm, status)); 479 480 return groups; 481 } 482 483 private IType findNonPrimaryType(String fullyQualifiedName, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { 484 SearchPattern p= SearchPattern.createPattern(fullyQualifiedName, IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE); 485 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(p); 486 487 engine.setFiltering(true, true); 488 engine.setScope(RefactoringScopeFactory.create(fCtorBinding.getJavaElement().getJavaProject())); 489 engine.setStatus(status); 490 engine.searchPattern(new SubProgressMonitor(pm, 1)); 491 492 SearchResultGroup[] groups= (SearchResultGroup[]) engine.getResults(); 493 494 if (groups.length != 0) { 495 for(int i= 0; i < groups.length; i++) { 496 SearchMatch[] matches= groups[i].getSearchResults(); 497 for(int j= 0; j < matches.length; j++) { 498 if (matches[j].getAccuracy() == SearchMatch.A_ACCURATE) 499 return (IType) matches[j].getElement(); 500 } 501 } 502 } 503 return null; 504 } 505 506 509 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { 510 try { 511 pm.beginTask(RefactoringCoreMessages.IntroduceFactory_checking_preconditions, 1); 512 RefactoringStatus result= new RefactoringStatus(); 513 514 if (fFactoryClassName != null) 515 result.merge(setFactoryClass(fFactoryClassName)); 516 if (result.hasFatalError()) 517 return result; 518 fArgTypes= fCtorBinding.getParameterTypes(); 519 fCtorIsVarArgs= fCtorBinding.isVarargs(); 520 fAllCallsTo= findAllCallsTo(fCtorBinding, pm, result); 521 fFormalArgNames= findCtorArgNames(); 522 523 ICompilationUnit[] affectedFiles= collectAffectedUnits(fAllCallsTo); 524 result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(affectedFiles), getValidationContext())); 525 526 if (fCallSitesInBinaryUnits) 527 result.merge(RefactoringStatus.createWarningStatus(RefactoringCoreMessages.IntroduceFactory_callSitesInBinaryClass)); 528 529 return result; 530 } finally { 531 pm.done(); 532 } 533 } 534 535 540 private String [] findCtorArgNames() { 541 int numArgs= fCtorBinding.getParameterTypes().length; 542 String [] names= new String [numArgs]; 543 544 CompilationUnit ctorUnit= (CompilationUnit) ASTNodes.getParent(fCtorOwningClass, CompilationUnit.class); 545 MethodDeclaration ctorDecl= (MethodDeclaration) ctorUnit.findDeclaringNode(fCtorBinding.getKey()); 546 547 if (ctorDecl != null) { 548 List formalArgs= ctorDecl.parameters(); 549 int i= 0; 550 551 for(Iterator iter= formalArgs.iterator(); iter.hasNext(); i++) { 552 SingleVariableDeclaration svd= (SingleVariableDeclaration) iter.next(); 553 554 names[i]= svd.getName().getIdentifier(); 555 } 556 return names; 557 } 558 559 for(int i=0; i < numArgs; i++) 561 names[i]= "arg" + (i+1); 563 return names; 564 } 565 566 573 private MethodDeclaration createFactoryMethod(AST ast, IMethodBinding ctorBinding, ASTRewrite unitRewriter) { 574 MethodDeclaration newMethod= ast.newMethodDeclaration(); 575 SimpleName newMethodName= ast.newSimpleName(fNewMethodName); 576 ClassInstanceCreation newCtorCall= ast.newClassInstanceCreation(); 577 ReturnStatement ret= ast.newReturnStatement(); 578 Block body= ast.newBlock(); 579 List stmts= body.statements(); 580 String retTypeName= ctorBinding.getName(); 581 582 createFactoryMethodSignature(ast, newMethod); 583 584 newMethod.setName(newMethodName); 585 newMethod.setBody(body); 586 587 ITypeBinding[] ctorOwnerTypeParameters= fCtorBinding.getDeclaringClass().getTypeParameters(); 588 589 setMethodReturnType(newMethod, retTypeName, ctorOwnerTypeParameters, ast); 590 591 newMethod.modifiers().addAll(ASTNodeFactory.newModifiers(ast, Modifier.STATIC | Modifier.PUBLIC)); 592 593 setCtorTypeArguments(newCtorCall, retTypeName, ctorOwnerTypeParameters, ast); 594 595 createFactoryMethodConstructorArgs(ast, newCtorCall); 596 597 ret.setExpression(newCtorCall); 598 stmts.add(ret); 599 600 return newMethod; 601 } 602 603 612 private void setCtorTypeArguments(ClassInstanceCreation newCtorCall, String ctorTypeName, ITypeBinding[] ctorOwnerTypeParameters, AST ast) { 613 if (ctorOwnerTypeParameters.length == 0) newCtorCall.setType(ASTNodeFactory.newType(ast, ctorTypeName)); 615 else { 616 Type baseType= ast.newSimpleType(ast.newSimpleName(ctorTypeName)); 617 ParameterizedType newInstantiatedType= ast.newParameterizedType(baseType); 618 List newInstTypeArgs= newInstantiatedType.typeArguments(); 619 620 for(int i= 0; i < ctorOwnerTypeParameters.length; i++) { 621 Type typeArg= ASTNodeFactory.newType(ast, ctorOwnerTypeParameters[i].getName()); 622 623 newInstTypeArgs.add(typeArg); 624 } 625 newCtorCall.setType(newInstantiatedType); 626 } 627 } 628 629 640 private void setMethodReturnType(MethodDeclaration newMethod, String retTypeName, ITypeBinding[] ctorOwnerTypeParameters, AST ast) { 641 if (ctorOwnerTypeParameters.length == 0) 642 newMethod.setReturnType2(ast.newSimpleType(ast.newSimpleName(retTypeName))); 643 else { 644 Type baseType= ast.newSimpleType(ast.newSimpleName(retTypeName)); 645 ParameterizedType newRetType= ast.newParameterizedType(baseType); 646 List newRetTypeArgs= newRetType.typeArguments(); 647 648 for(int i= 0; i < ctorOwnerTypeParameters.length; i++) { 649 Type retTypeArg= ASTNodeFactory.newType(ast, ctorOwnerTypeParameters[i].getName()); 650 651 newRetTypeArgs.add(retTypeArg); 652 } 653 newMethod.setReturnType2(newRetType); 654 } 655 } 656 657 668 private void createFactoryMethodSignature(AST ast, MethodDeclaration newMethod) { 669 List argDecls= newMethod.parameters(); 670 671 for(int i=0; i < fArgTypes.length; i++) { 672 SingleVariableDeclaration argDecl= ast.newSingleVariableDeclaration(); 673 Type argType; 674 675 if (i == (fArgTypes.length - 1) && fCtorIsVarArgs) { 676 argType= typeNodeForTypeBinding(fArgTypes[i].getElementType(), 679 fArgTypes[i].getDimensions()-1, ast); 680 argDecl.setVarargs(true); 681 } else 682 argType= typeNodeForTypeBinding(fArgTypes[i], 0, ast); 683 684 argDecl.setName(ast.newSimpleName(fFormalArgNames[i])); 685 argDecl.setType(argType); 686 argDecls.add(argDecl); 687 } 688 689 ITypeBinding[] ctorExcepts= fCtorBinding.getExceptionTypes(); 690 List exceptions= newMethod.thrownExceptions(); 691 692 for(int i=0; i < ctorExcepts.length; i++) { 693 String excName= fImportRewriter.addImport(ctorExcepts[i]); 694 695 exceptions.add(ASTNodeFactory.newName(ast, excName)); 696 } 697 698 copyTypeParameters(ast, newMethod); 699 } 700 701 718 private void copyTypeParameters(AST ast, MethodDeclaration newMethod) { 719 ITypeBinding[] ctorOwnerTypeParms= fCtorBinding.getDeclaringClass().getTypeParameters(); 720 List factoryMethodTypeParms= newMethod.typeParameters(); 721 for(int i= 0; i < ctorOwnerTypeParms.length; i++) { 722 TypeParameter newParm= ast.newTypeParameter(); 723 ITypeBinding[] parmTypeBounds= ctorOwnerTypeParms[i].getTypeBounds(); 724 List newParmBounds= newParm.typeBounds(); 725 726 newParm.setName(ast.newSimpleName(ctorOwnerTypeParms[i].getName())); 727 for(int b=0; b < parmTypeBounds.length; b++) { 728 if (parmTypeBounds[b].isClass() && parmTypeBounds[b].getSuperclass() == null) 729 continue; 730 731 Type newBound= fImportRewriter.addImport(parmTypeBounds[b], ast); 732 733 newParmBounds.add(newBound); 734 } 735 factoryMethodTypeParms.add(newParm); 736 } 737 } 738 739 746 private Type typeNodeForTypeBinding(ITypeBinding argType, int extraDims, AST ast) { 747 if (extraDims > 0) { 748 return ast.newArrayType(typeNodeForTypeBinding(argType, 0, ast), extraDims); 749 750 } else if (argType.isArray()) { 751 Type elementType= typeNodeForTypeBinding(argType.getElementType(), extraDims, ast); 752 return ast.newArrayType(elementType, argType.getDimensions()); 753 754 } else { 755 return fImportRewriter.addImport(argType, ast); 756 } 757 } 758 759 767 private void createFactoryMethodConstructorArgs(AST ast, ClassInstanceCreation newCtorCall) { 768 List argList= newCtorCall.arguments(); 769 770 for(int i=0; i < fArgTypes.length; i++) { 771 ASTNode ctorArg= ast.newSimpleName(fFormalArgNames[i]); 772 773 argList.add(ctorArg); 774 } 775 } 776 777 785 private MethodInvocation createFactoryMethodCall(AST ast, ClassInstanceCreation ctorCall, 786 ASTRewrite unitRewriter, TextEditGroup gd) { 787 MethodInvocation factoryMethodCall= ast.newMethodInvocation(); 788 789 List actualFactoryArgs= factoryMethodCall.arguments(); 790 List actualCtorArgs= ctorCall.arguments(); 791 792 AbstractTypeDeclaration callOwner= (AbstractTypeDeclaration) ASTNodes.getParent(ctorCall, AbstractTypeDeclaration.class); 795 ITypeBinding callOwnerBinding= callOwner.resolveBinding(); 796 797 if (callOwnerBinding == null || 798 !Bindings.equals(callOwner.resolveBinding(), fFactoryOwningClass.resolveBinding())) { 799 String qualifier= fImportRewriter.addImport(fFactoryOwningClass.resolveBinding()); 800 factoryMethodCall.setExpression(ASTNodeFactory.newName(ast, qualifier)); 801 } 802 803 factoryMethodCall.setName(ast.newSimpleName(fNewMethodName)); 804 805 for(int i=0; i < actualCtorArgs.size(); i++) { 806 Expression actualCtorArg= (Expression) actualCtorArgs.get(i); 807 ASTNode movedArg= unitRewriter.createMoveTarget(actualCtorArg); 808 809 actualFactoryArgs.add(movedArg); 810 } 814 815 unitRewriter.replace(ctorCall, factoryMethodCall, gd); 816 817 return factoryMethodCall; 818 } 819 820 825 private boolean isConstructorUnit(ICompilationUnit unit) { 826 return unit.equals(ASTCreator.getCu(fCtorOwningClass)); 827 } 828 829 835 private boolean shouldProtectConstructor() { 836 return fProtectConstructor && fCtorOwningClass != null; 837 } 838 839 843 private boolean protectConstructor(CompilationUnit unitAST, ASTRewrite unitRewriter, TextEditGroup declGD) { 844 MethodDeclaration constructor= (MethodDeclaration) unitAST.findDeclaringNode(fCtorBinding.getKey()); 845 846 if (constructor == null || (JdtFlags.getVisibilityCode(constructor)) == fConstructorVisibility) 848 return false; 849 ModifierRewrite.create(unitRewriter, constructor).setVisibility(fConstructorVisibility, declGD); 850 return true; 851 } 852 853 861 private boolean addAllChangesFor(SearchResultGroup rg, ICompilationUnit unitHandle, CompilationUnitChange unitChange) throws CoreException { 862 Assert.isTrue(rg == null || rg.getCompilationUnit() == unitHandle); 864 CompilationUnit unit= getASTFor(unitHandle); 865 ASTRewrite unitRewriter= ASTRewrite.create(unit.getAST()); 866 MultiTextEdit root= new MultiTextEdit(); 867 boolean someChange= false; 868 869 unitChange.setEdit(root); 870 fImportRewriter= StubUtility.createImportRewrite(unit, true); 871 872 if (unitHandle.equals(fFactoryUnitHandle)) { 874 TextEditGroup factoryGD= new TextEditGroup(RefactoringCoreMessages.IntroduceFactory_addFactoryMethod); 875 876 createFactoryChange(unitRewriter, unit, factoryGD); 877 unitChange.addTextEditGroup(factoryGD); 878 someChange= true; 879 } 880 881 if (rg != null) 883 if (replaceConstructorCalls(rg, unit, unitRewriter, unitChange)) 884 someChange= true; 885 886 if (shouldProtectConstructor() && isConstructorUnit(unitHandle)) { 888 TextEditGroup declGD= new TextEditGroup(RefactoringCoreMessages.IntroduceFactory_protectConstructor); 889 890 if (protectConstructor(unit, unitRewriter, declGD)) { 891 unitChange.addTextEditGroup(declGD); 892 someChange= true; 893 } 894 } 895 896 if (someChange) { 897 root.addChild(unitRewriter.rewriteAST()); 898 root.addChild(fImportRewriter.rewriteImports(null)); 899 } 900 901 return someChange; 902 } 903 904 910 private CompilationUnit getASTFor(ICompilationUnit unitHandle) { 911 if (unitHandle.equals(fCUHandle)) { if (fCU == null) { 913 fCU= ASTCreator.createAST(unitHandle, null); 914 if (fCU.equals(fFactoryUnitHandle)) fFactoryCU= fCU; } 917 return fCU; 918 } else if (unitHandle.equals(fFactoryUnitHandle)) { if (fFactoryCU == null) 920 fFactoryCU= ASTCreator.createAST(unitHandle, null); 921 return fFactoryCU; 922 } else 923 return ASTCreator.createAST(unitHandle, null); 924 } 925 926 936 private boolean replaceConstructorCalls(SearchResultGroup rg, CompilationUnit unit, 937 ASTRewrite unitRewriter, CompilationUnitChange unitChange) 938 throws CoreException { 939 Assert.isTrue(ASTCreator.getCu(unit).equals(rg.getCompilationUnit())); 940 SearchMatch[] hits= rg.getSearchResults(); 941 AST ctorCallAST= unit.getAST(); 942 boolean someCallPatched= false; 943 944 for(int i=0; i < hits.length; i++) { 945 ClassInstanceCreation creation= getCtorCallAt(hits[i].getOffset(), hits[i].getLength(), unit); 946 947 if (creation != null) { 948 TextEditGroup gd= new TextEditGroup(RefactoringCoreMessages.IntroduceFactory_replaceCalls); 949 950 createFactoryMethodCall(ctorCallAST, creation, unitRewriter, gd); 951 unitChange.addTextEditGroup(gd); 952 someCallPatched= true; 953 } 954 } 955 return someCallPatched; 956 } 957 958 967 private ClassInstanceCreation getCtorCallAt(int start, int length, CompilationUnit unitAST) throws CoreException { 968 ICompilationUnit unitHandle= ASTCreator.getCu(unitAST); 969 ASTNode node= NodeFinder.perform(unitAST, start, length); 970 971 if (node == null) 972 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, 973 Messages.format(RefactoringCoreMessages.IntroduceFactory_noASTNodeForConstructorSearchHit, 974 new Object [] { Integer.toString(start), Integer.toString(start + length), 975 unitHandle.getSource().substring(start, start + length), 976 unitHandle.getElementName() }), 977 null)); 978 979 if (node instanceof ClassInstanceCreation) { 980 return (ClassInstanceCreation) node; 981 } else if (node instanceof VariableDeclaration) { 982 Expression init= ((VariableDeclaration) node).getInitializer(); 983 984 if (init instanceof ClassInstanceCreation) { 985 return (ClassInstanceCreation) init; 986 } else if (init != null) 987 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, 988 Messages.format(RefactoringCoreMessages.IntroduceFactory_unexpectedInitializerNodeType, 989 new Object [] { init.toString(), unitHandle.getElementName() }), 990 null)); 991 else 992 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, 993 Messages.format(RefactoringCoreMessages.IntroduceFactory_noConstructorCallNodeInsideFoundVarbleDecl, 994 new Object [] { node.toString() }), 995 null)); 996 } else if (node instanceof ConstructorInvocation) { 997 return null; 1000 } else if (node instanceof SuperConstructorInvocation) { 1001 fConstructorVisibility= Modifier.PROTECTED; 1004 return null; 1005 } else if (node instanceof ExpressionStatement) { 1006 Expression expr= ((ExpressionStatement) node).getExpression(); 1007 1008 if (expr instanceof ClassInstanceCreation) 1009 return (ClassInstanceCreation) expr; 1010 else 1011 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, 1012 Messages.format(RefactoringCoreMessages.IntroduceFactory_unexpectedASTNodeTypeForConstructorSearchHit, 1013 new Object [] { expr.toString(), unitHandle.getElementName() }), 1014 null)); 1015 } else if (node instanceof SimpleName && (node.getParent() instanceof MethodDeclaration || node.getParent() instanceof AbstractTypeDeclaration)) { 1016 fConstructorVisibility= Modifier.PROTECTED; 1020 return null; 1021 } else 1022 throw new CoreException(JavaUIStatus.createError(IStatus.ERROR, 1023 Messages.format(RefactoringCoreMessages.IntroduceFactory_unexpectedASTNodeTypeForConstructorSearchHit, 1024 new Object [] { node.getClass().getName() + "('" + node.toString() + "')", unitHandle.getElementName() }), null)); 1026 } 1027 1028 1036 private void createFactoryChange(ASTRewrite unitRewriter, CompilationUnit unit, TextEditGroup gd) { 1037 AST ast= unit.getAST(); 1040 1041 fFactoryMethod= createFactoryMethod(ast, fCtorBinding, unitRewriter); 1042 1043 AbstractTypeDeclaration factoryOwner= (AbstractTypeDeclaration) unit.findDeclaringNode(fFactoryOwningClass.resolveBinding().getKey()); 1044 fImportRewriter.addImport(fCtorOwningClass.resolveBinding()); 1045 1046 int idx= ASTNodes.getInsertionIndex(fFactoryMethod, factoryOwner.bodyDeclarations()); 1047 1048 if (idx < 0) idx= 0; unitRewriter.getListRewrite(factoryOwner, factoryOwner.getBodyDeclarationsProperty()).insertAt(fFactoryMethod, idx, gd); 1050 } 1051 1052 public Change createChange(IProgressMonitor pm) throws CoreException { 1053 try { 1054 pm.beginTask(RefactoringCoreMessages.IntroduceFactory_createChanges, fAllCallsTo.length); 1055 final ITypeBinding binding= fFactoryOwningClass.resolveBinding(); 1056 final Map arguments= new HashMap (); 1057 String project= null; 1058 IJavaProject javaProject= fCUHandle.getJavaProject(); 1059 if (javaProject != null) 1060 project= javaProject.getElementName(); 1061 int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE; 1062 if (binding.isNested() && !binding.isMember()) 1063 flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; 1064 final String description= Messages.format(RefactoringCoreMessages.IntroduceFactoryRefactoring_descriptor_description_short, fCtorOwningClass.getName()); 1065 final String header= Messages.format(RefactoringCoreMessages.IntroduceFactory_descriptor_description, new String [] { fNewMethodName, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED), BindingLabelProvider.getBindingLabel(fCtorBinding, JavaElementLabels.ALL_FULLY_QUALIFIED)}); 1066 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); 1067 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceFactoryRefactoring_original_pattern, BindingLabelProvider.getBindingLabel(fCtorBinding, JavaElementLabels.ALL_FULLY_QUALIFIED))); 1068 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceFactoryRefactoring_factory_pattern, fNewMethodName)); 1069 comment.addSetting(Messages.format(RefactoringCoreMessages.IntroduceFactoryRefactoring_owner_pattern, BindingLabelProvider.getBindingLabel(binding, JavaElementLabels.ALL_FULLY_QUALIFIED))); 1070 if (fProtectConstructor) 1071 comment.addSetting(RefactoringCoreMessages.IntroduceFactoryRefactoring_declare_private); 1072 final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.INTRODUCE_FACTORY, project, description, comment.asString(), arguments, flags); 1073 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCUHandle)); 1074 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_NAME, fNewMethodName); 1075 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + 1, descriptor.elementToHandle(binding.getJavaElement())); 1076 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION, new Integer (fSelectionStart).toString() + " " + new Integer (fSelectionLength).toString()); arguments.put(ATTRIBUTE_PROTECT, Boolean.valueOf(fProtectConstructor).toString()); 1078 final DynamicValidationStateChange result= new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.IntroduceFactory_name); 1079 boolean hitInFactoryClass= false; 1080 boolean hitInCtorClass= false; 1081 for (int i= 0; i < fAllCallsTo.length; i++) { 1082 SearchResultGroup rg= fAllCallsTo[i]; 1083 ICompilationUnit unitHandle= rg.getCompilationUnit(); 1084 CompilationUnitChange cuChange= new CompilationUnitChange(getName(), unitHandle); 1085 1086 if (addAllChangesFor(rg, unitHandle, cuChange)) 1087 result.add(cuChange); 1088 1089 if (unitHandle.equals(fFactoryUnitHandle)) 1090 hitInFactoryClass= true; 1091 if (unitHandle.equals(ASTCreator.getCu(fCtorOwningClass))) 1092 hitInCtorClass= true; 1093 1094 pm.worked(1); 1095 if (pm.isCanceled()) 1096 throw new OperationCanceledException(); 1097 } 1098 if (!hitInFactoryClass) { CompilationUnitChange cuChange= new CompilationUnitChange(getName(), fFactoryUnitHandle); 1100 addAllChangesFor(null, fFactoryUnitHandle, cuChange); 1101 result.add(cuChange); 1102 } 1103 if (!hitInCtorClass && !fFactoryUnitHandle.equals(ASTCreator.getCu(fCtorOwningClass))) { CompilationUnitChange cuChange= new CompilationUnitChange(getName(), ASTCreator.getCu(fCtorOwningClass)); 1105 addAllChangesFor(null, ASTCreator.getCu(fCtorOwningClass), cuChange); 1106 result.add(cuChange); 1107 } 1108 return result; 1109 } finally { 1110 pm.done(); 1111 } 1112 } 1113 1114 1117 public String getName() { 1118 return RefactoringCoreMessages.IntroduceFactory_name; 1119 } 1120 1121 1124 public String getNewMethodName() { 1125 return fNewMethodName; 1126 } 1127 1128 1134 public RefactoringStatus setNewMethodName(String newMethodName) { 1135 Assert.isNotNull(newMethodName); 1136 fNewMethodName = newMethodName; 1137 1138 RefactoringStatus stat= Checks.checkMethodName(newMethodName); 1139 1140 stat.merge(isUniqueMethodName(newMethodName)); 1141 1142 return stat; 1143 } 1144 1145 1153 private RefactoringStatus isUniqueMethodName(String methodName) { 1154 boolean conflict= hasMethod(fFactoryOwningClass, methodName); 1155 1156 return conflict ? RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceFactory_duplicateMethodName + methodName) : new RefactoringStatus(); 1157 } 1158 1159 1165 private boolean hasMethod(AbstractTypeDeclaration type, String name) { 1166 List decls= type.bodyDeclarations(); 1167 1168 for (Iterator iter = decls.iterator(); iter.hasNext();) { 1169 BodyDeclaration decl = (BodyDeclaration) iter.next(); 1170 if (decl instanceof MethodDeclaration) { 1171 if (((MethodDeclaration) decl).getName().getIdentifier().equals(name)) 1172 return true; 1173 } 1174 } 1175 return false; 1176 } 1177 1178 1181 public boolean canProtectConstructor() { 1182 return !fCtorBinding.isSynthetic() && fFactoryCU.findDeclaringNode(fCtorBinding.getKey()) != null; 1183 } 1184 1185 1190 public void setProtectConstructor(boolean protectConstructor) { 1191 fProtectConstructor = protectConstructor; 1192 } 1193 1194 1197 public IJavaProject getProject() { 1198 return fCUHandle.getJavaProject(); 1199 } 1200 1201 1205 public RefactoringStatus setFactoryClass(String fullyQualifiedTypeName) { 1206 IType factoryType; 1207 1208 try { 1209 factoryType= findFactoryClass(fullyQualifiedTypeName); 1210 if (factoryType == null) 1211 return RefactoringStatus.createErrorStatus(Messages.format(RefactoringCoreMessages.IntroduceFactory_noSuchClass, fullyQualifiedTypeName)); 1212 1213 if (factoryType.isAnnotation()) 1214 return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceFactory_cantPutFactoryMethodOnAnnotation); 1215 if (factoryType.isInterface()) 1216 return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceFactory_cantPutFactoryMethodOnInterface); 1217 } catch (JavaModelException e) { 1218 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.IntroduceFactory_cantCheckForInterface); 1219 } 1220 1221 ICompilationUnit factoryUnitHandle= factoryType.getCompilationUnit(); 1222 1223 if (factoryType.isBinary()) 1224 return RefactoringStatus.createErrorStatus(RefactoringCoreMessages.IntroduceFactory_cantPutFactoryInBinaryClass); 1225 else { 1226 try { 1227 if (!fFactoryUnitHandle.equals(factoryUnitHandle)) { 1228 fFactoryCU= getASTFor(factoryUnitHandle); 1229 fFactoryUnitHandle= factoryUnitHandle; 1230 } 1231 fFactoryOwningClass= (AbstractTypeDeclaration) ASTNodes.getParent(NodeFinder.perform(fFactoryCU, factoryType.getNameRange()), AbstractTypeDeclaration.class); 1232 1233 String factoryPkg= factoryType.getPackageFragment().getElementName(); 1234 String ctorPkg= fCtorOwningClass.resolveBinding().getPackage().getName(); 1235 1236 if (!factoryPkg.equals(ctorPkg)) 1237 fConstructorVisibility= Modifier.PUBLIC; 1238 else if (fFactoryOwningClass != fCtorOwningClass) 1239 fConstructorVisibility= 0; 1241 1242 if (fFactoryOwningClass != fCtorOwningClass) 1243 fConstructorVisibility= 0; 1245 } catch (JavaModelException e) { 1246 return RefactoringStatus.createFatalErrorStatus(e.getMessage()); 1247 } 1248 return new RefactoringStatus(); 1249 } 1250 } 1251 1252 1258 private IType findFactoryClass(String fullyQualifiedTypeName) throws JavaModelException { 1259 IType factoryType= getProject().findType(fullyQualifiedTypeName); 1260 if (factoryType == null) factoryType= findNonPrimaryType(fullyQualifiedTypeName, new NullProgressMonitor(), new RefactoringStatus()); 1262 return factoryType; 1263 } 1264 1265 1269 public String getFactoryClassName() { 1270 return fFactoryOwningClass.resolveBinding().getQualifiedName(); 1271 } 1272 1273 public RefactoringStatus initialize(final RefactoringArguments arguments) { 1274 if (arguments instanceof JavaRefactoringArguments) { 1275 final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; 1276 final String selection= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_SELECTION); 1277 if (selection != null) { 1278 int offset= -1; 1279 int length= -1; 1280 final StringTokenizer tokenizer= new StringTokenizer (selection); 1281 if (tokenizer.hasMoreTokens()) 1282 offset= Integer.valueOf(tokenizer.nextToken()).intValue(); 1283 if (tokenizer.hasMoreTokens()) 1284 length= Integer.valueOf(tokenizer.nextToken()).intValue(); 1285 if (offset >= 0 && length >= 0) { 1286 fSelectionStart= offset; 1287 fSelectionLength= length; 1288 } else 1289 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_illegal_argument, new Object [] { selection, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION})); 1290 } else 1291 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_SELECTION)); 1292 String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT); 1293 if (handle != null) { 1294 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 1295 if (element == null || !element.exists() || element.getElementType() != IJavaElement.COMPILATION_UNIT) 1296 return createInputFatalStatus(element, IJavaRefactorings.INTRODUCE_FACTORY); 1297 else { 1298 fCUHandle= (ICompilationUnit) element; 1299 initialize(); 1300 } 1301 } else 1302 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT)); 1303 handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + 1); 1304 if (handle != null) { 1305 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 1306 if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE) 1307 return createInputFatalStatus(element, IJavaRefactorings.INTRODUCE_FACTORY); 1308 else { 1309 final IType type= (IType) element; 1310 fFactoryClassName= type.getFullyQualifiedName(); 1311 } 1312 } else 1313 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT)); 1314 final String name= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_NAME); 1315 if (name != null && !"".equals(name)) fNewMethodName= name; 1317 else 1318 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_NAME)); 1319 final String protect= extended.getAttribute(ATTRIBUTE_PROTECT); 1320 if (protect != null) { 1321 fProtectConstructor= Boolean.valueOf(protect).booleanValue(); 1322 } else 1323 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_PROTECT)); 1324 } else 1325 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); 1326 return new RefactoringStatus(); 1327 } 1328} 1329 | Popular Tags |