1 16 package org.eclipse.jdt.internal.corext.refactoring.sef; 17 18 import java.util.ArrayList ; 19 import java.util.HashMap ; 20 import java.util.Iterator ; 21 import java.util.List ; 22 import java.util.Map ; 23 24 import org.eclipse.text.edits.MultiTextEdit; 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.IStatus; 31 import org.eclipse.core.runtime.OperationCanceledException; 32 import org.eclipse.core.runtime.SubProgressMonitor; 33 34 import org.eclipse.core.resources.IFile; 35 36 import org.eclipse.ltk.core.refactoring.Change; 37 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 38 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 39 import org.eclipse.ltk.core.refactoring.TextChange; 40 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; 41 import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker; 42 43 import org.eclipse.jdt.core.Flags; 44 import org.eclipse.jdt.core.ICompilationUnit; 45 import org.eclipse.jdt.core.IField; 46 import org.eclipse.jdt.core.IJavaElement; 47 import org.eclipse.jdt.core.IJavaProject; 48 import org.eclipse.jdt.core.ISourceRange; 49 import org.eclipse.jdt.core.IType; 50 import org.eclipse.jdt.core.JavaConventions; 51 import org.eclipse.jdt.core.JavaCore; 52 import org.eclipse.jdt.core.JavaModelException; 53 import org.eclipse.jdt.core.NamingConventions; 54 import org.eclipse.jdt.core.compiler.IProblem; 55 import org.eclipse.jdt.core.dom.AST; 56 import org.eclipse.jdt.core.dom.ASTNode; 57 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 58 import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; 59 import org.eclipse.jdt.core.dom.Assignment; 60 import org.eclipse.jdt.core.dom.Block; 61 import org.eclipse.jdt.core.dom.BodyDeclaration; 62 import org.eclipse.jdt.core.dom.ChildListPropertyDescriptor; 63 import org.eclipse.jdt.core.dom.ClassInstanceCreation; 64 import org.eclipse.jdt.core.dom.CompilationUnit; 65 import org.eclipse.jdt.core.dom.Expression; 66 import org.eclipse.jdt.core.dom.FieldAccess; 67 import org.eclipse.jdt.core.dom.FieldDeclaration; 68 import org.eclipse.jdt.core.dom.IMethodBinding; 69 import org.eclipse.jdt.core.dom.ITypeBinding; 70 import org.eclipse.jdt.core.dom.IVariableBinding; 71 import org.eclipse.jdt.core.dom.Javadoc; 72 import org.eclipse.jdt.core.dom.Message; 73 import org.eclipse.jdt.core.dom.MethodDeclaration; 74 import org.eclipse.jdt.core.dom.Modifier; 75 import org.eclipse.jdt.core.dom.ReturnStatement; 76 import org.eclipse.jdt.core.dom.SingleVariableDeclaration; 77 import org.eclipse.jdt.core.dom.Type; 78 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 79 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 80 import org.eclipse.jdt.core.dom.rewrite.ImportRewrite; 81 import org.eclipse.jdt.core.dom.rewrite.ListRewrite; 82 import org.eclipse.jdt.core.refactoring.IJavaRefactorings; 83 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; 84 import org.eclipse.jdt.core.search.IJavaSearchConstants; 85 import org.eclipse.jdt.core.search.SearchPattern; 86 87 import org.eclipse.jdt.internal.corext.codemanipulation.GetterSetterUtil; 88 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 89 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 90 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 91 import org.eclipse.jdt.internal.corext.dom.Bindings; 92 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; 93 import org.eclipse.jdt.internal.corext.dom.NodeFinder; 94 import org.eclipse.jdt.internal.corext.refactoring.Checks; 95 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor; 96 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; 97 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; 98 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 99 import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; 100 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine; 101 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 102 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; 103 import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring; 104 import org.eclipse.jdt.internal.corext.refactoring.util.RefactoringASTParser; 105 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; 106 import org.eclipse.jdt.internal.corext.refactoring.util.TextChangeManager; 107 import org.eclipse.jdt.internal.corext.util.JdtFlags; 108 import org.eclipse.jdt.internal.corext.util.Messages; 109 110 import org.eclipse.jdt.ui.CodeGeneration; 111 import org.eclipse.jdt.ui.JavaElementLabels; 112 113 import org.eclipse.jdt.internal.ui.JavaPlugin; 114 import org.eclipse.jdt.internal.ui.viewsupport.BindingLabelProvider; 115 116 119 public class SelfEncapsulateFieldRefactoring extends ScriptableRefactoring { 120 121 private static final String ATTRIBUTE_VISIBILITY= "visibility"; private static final String ATTRIBUTE_GETTER= "getter"; private static final String ATTRIBUTE_SETTER= "setter"; private static final String ATTRIBUTE_INSERTION= "insertion"; private static final String ATTRIBUTE_COMMENTS= "comments"; private static final String ATTRIBUTE_DECLARING= "declaring"; 128 private IField fField; 129 private TextChangeManager fChangeManager; 130 131 private CompilationUnit fRoot; 132 private VariableDeclarationFragment fFieldDeclaration; 133 private ASTRewrite fRewriter; 134 private ImportRewrite fImportRewrite; 135 136 private int fVisibility= -1; 137 private String fGetterName; 138 private String fSetterName; 139 private String fArgName; 140 private boolean fSetterMustReturnValue; 141 private int fInsertionIndex; private boolean fEncapsulateDeclaringClass; 143 private boolean fGenerateJavadoc; 144 145 private List fUsedReadNames; 146 private List fUsedModifyNames; 147 private boolean fConsiderVisibility=true; 148 149 private static final String NO_NAME= ""; 151 156 public SelfEncapsulateFieldRefactoring(IField field) throws JavaModelException { 157 fEncapsulateDeclaringClass= true; 158 fChangeManager= new TextChangeManager(); 159 fField= field; 160 if (field != null) 161 initialize(field); 162 } 163 164 private void initialize(IField field) throws JavaModelException { 165 fGetterName= GetterSetterUtil.getGetterName(field, null); 166 fSetterName= GetterSetterUtil.getSetterName(field, null); 167 fArgName= NamingConventions.removePrefixAndSuffixForFieldName(field.getJavaProject(), field.getElementName(), field.getFlags()); 168 checkArgName(); 169 } 170 171 public IField getField() { 172 return fField; 173 } 174 175 public String getGetterName() { 176 return fGetterName; 177 } 178 179 public void setGetterName(String name) { 180 fGetterName= name; 181 Assert.isNotNull(fGetterName); 182 } 183 184 public String getSetterName() { 185 return fSetterName; 186 } 187 188 public void setSetterName(String name) { 189 fSetterName= name; 190 Assert.isNotNull(fSetterName); 191 } 192 193 public void setInsertionIndex(int index) { 194 fInsertionIndex= index; 195 } 196 197 public int getVisibility() { 198 return fVisibility; 199 } 200 201 public void setVisibility(int visibility) { 202 fVisibility= visibility; 203 } 204 205 public void setEncapsulateDeclaringClass(boolean encapsulateDeclaringClass) { 206 fEncapsulateDeclaringClass= encapsulateDeclaringClass; 207 } 208 209 public boolean getEncapsulateDeclaringClass() { 210 return fEncapsulateDeclaringClass; 211 } 212 213 public boolean getGenerateJavadoc() { 214 return fGenerateJavadoc; 215 } 216 217 public void setGenerateJavadoc(boolean value) { 218 fGenerateJavadoc= value; 219 } 220 221 223 public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { 224 if (fVisibility < 0) 225 fVisibility= (fField.getFlags() & (Flags.AccPublic | Flags.AccProtected | Flags.AccPrivate)); 226 RefactoringStatus result= new RefactoringStatus(); 227 result.merge(Checks.checkAvailability(fField)); 228 if (result.hasFatalError()) 229 return result; 230 fRoot= new RefactoringASTParser(AST.JLS3).parse(fField.getCompilationUnit(), true, pm); 231 ISourceRange sourceRange= fField.getNameRange(); 232 ASTNode node= NodeFinder.perform(fRoot, sourceRange.getOffset(), sourceRange.getLength()); 233 if (node == null) { 234 return mappingErrorFound(result, node); 235 } 236 fFieldDeclaration= (VariableDeclarationFragment)ASTNodes.getParent(node, VariableDeclarationFragment.class); 237 if (fFieldDeclaration == null) { 238 return mappingErrorFound(result, node); 239 } 240 if (fFieldDeclaration.resolveBinding() == null) { 241 if (!processCompilerError(result, node)) 242 result.addFatalError(RefactoringCoreMessages.SelfEncapsulateField_type_not_resolveable); 243 return result; 244 } 245 computeUsedNames(); 246 fRewriter= ASTRewrite.create(fRoot.getAST()); 247 return result; 248 } 249 250 private RefactoringStatus mappingErrorFound(RefactoringStatus result, ASTNode node) { 251 if (node != null && (node.getFlags() & ASTNode.MALFORMED) != 0 && processCompilerError(result, node)) 252 return result; 253 result.addFatalError(getMappingErrorMessage()); 254 return result; 255 } 256 257 private boolean processCompilerError(RefactoringStatus result, ASTNode node) { 258 Message[] messages= ASTNodes.getMessages(node, ASTNodes.INCLUDE_ALL_PARENTS); 259 if (messages.length == 0) 260 return false; 261 result.addFatalError(Messages.format( 262 RefactoringCoreMessages.SelfEncapsulateField_compiler_errors_field, 263 new String [] { fField.getElementName(), messages[0].getMessage()})); 264 return true; 265 } 266 267 private String getMappingErrorMessage() { 268 return Messages.format( 269 RefactoringCoreMessages.SelfEncapsulateField_cannot_analyze_selected_field, 270 new String [] {fField.getElementName()}); 271 } 272 273 275 public RefactoringStatus checkMethodNames() { 276 return checkMethodNames(isUsingLocalGetter(),isUsingLocalSetter()); 277 } 278 279 public RefactoringStatus checkMethodNames(boolean usingLocalGetter, boolean usingLocalSetter) { 280 RefactoringStatus result= new RefactoringStatus(); 281 IType declaringType= fField.getDeclaringType(); 282 checkName(result, fGetterName, fUsedReadNames, declaringType, usingLocalGetter, fField); 283 checkName(result, fSetterName, fUsedModifyNames, declaringType, usingLocalSetter, fField); 284 return result; 285 } 286 287 private static void checkName(RefactoringStatus status, String name, List usedNames, IType type, boolean reUseExistingField, IField field) { 288 if ("".equals(name)) { status.addFatalError(RefactoringCoreMessages.Checks_Choose_name); 290 return; 291 } 292 boolean isStatic=false; 293 try { 294 isStatic= Flags.isStatic(field.getFlags()); 295 } catch (JavaModelException e) { 296 } 297 status.merge(Checks.checkMethodName(name)); 298 for (Iterator iter= usedNames.iterator(); iter.hasNext(); ) { 299 IMethodBinding method= (IMethodBinding)iter.next(); 300 String selector= method.getName(); 301 if (selector.equals(name)) { 302 if (!reUseExistingField) { 303 status.addFatalError(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_method_exists, new String [] { BindingLabelProvider.getBindingLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED), type.getElementName() })); 304 } else { 305 boolean methodIsStatic= Modifier.isStatic(method.getModifiers()); 306 if (methodIsStatic && !isStatic) 307 status.addWarning(Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_static_method_but_nonstatic_field, new String [] { method.getName(), field.getElementName() })); 308 if (!methodIsStatic && isStatic) 309 status.addFatalError(Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_nonstatic_method_but_static_field, new String [] { method.getName(), field.getElementName() })); 310 return; 311 } 312 313 } 314 } 315 if (reUseExistingField) 316 status.addFatalError(Messages.format( 317 RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_methoddoesnotexist_status_fatalError, 318 new String [] {name, type.getElementName()})); 319 } 320 321 public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException { 322 RefactoringStatus result= new RefactoringStatus(); 323 fChangeManager.clear(); 324 pm.beginTask(NO_NAME, 12); 325 pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_checking_preconditions); 326 boolean usingLocalGetter=isUsingLocalGetter(); 327 boolean usingLocalSetter=isUsingLocalSetter(); 328 result.merge(checkMethodNames(usingLocalGetter,usingLocalSetter)); 329 pm.worked(1); 330 if (result.hasFatalError()) 331 return result; 332 pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_searching_for_cunits); 333 final SubProgressMonitor subPm= new SubProgressMonitor(pm, 5); 334 ICompilationUnit[] affectedCUs= RefactoringSearchEngine.findAffectedCompilationUnits( 335 SearchPattern.createPattern(fField, IJavaSearchConstants.REFERENCES), 336 RefactoringScopeFactory.create(fField, fConsiderVisibility), 337 subPm, 338 result, true); 339 340 checkInHierarchy(result, usingLocalGetter, usingLocalSetter); 341 if (result.hasFatalError()) 342 return result; 343 344 pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_analyzing); 345 IProgressMonitor sub= new SubProgressMonitor(pm, 5); 346 sub.beginTask(NO_NAME, affectedCUs.length); 347 IVariableBinding fieldIdentifier= fFieldDeclaration.resolveBinding(); 348 ITypeBinding declaringClass= 349 ((AbstractTypeDeclaration)ASTNodes.getParent(fFieldDeclaration, AbstractTypeDeclaration.class)).resolveBinding(); 350 List ownerDescriptions= new ArrayList (); 351 ICompilationUnit owner= fField.getCompilationUnit(); 352 fImportRewrite= StubUtility.createImportRewrite(fRoot, true); 353 354 for (int i= 0; i < affectedCUs.length; i++) { 355 ICompilationUnit unit= affectedCUs[i]; 356 sub.subTask(unit.getElementName()); 357 CompilationUnit root= null; 358 ASTRewrite rewriter= null; 359 ImportRewrite importRewrite; 360 List descriptions; 361 if (owner.equals(unit)) { 362 root= fRoot; 363 rewriter= fRewriter; 364 importRewrite= fImportRewrite; 365 descriptions= ownerDescriptions; 366 } else { 367 root= new RefactoringASTParser(AST.JLS3).parse(unit, true); 368 rewriter= ASTRewrite.create(root.getAST()); 369 descriptions= new ArrayList (); 370 importRewrite= StubUtility.createImportRewrite(root, true); 371 } 372 checkCompileErrors(result, root, unit); 373 AccessAnalyzer analyzer= new AccessAnalyzer(this, unit, fieldIdentifier, declaringClass, rewriter, importRewrite); 374 root.accept(analyzer); 375 result.merge(analyzer.getStatus()); 376 if (!fSetterMustReturnValue) 377 fSetterMustReturnValue= analyzer.getSetterMustReturnValue(); 378 if (result.hasFatalError()) { 379 fChangeManager.clear(); 380 return result; 381 } 382 descriptions.addAll(analyzer.getGroupDescriptions()); 383 if (!owner.equals(unit)) 384 createEdits(unit, rewriter, descriptions, importRewrite); 385 sub.worked(1); 386 if (pm.isCanceled()) 387 throw new OperationCanceledException(); 388 } 389 ownerDescriptions.addAll(addGetterSetterChanges(fRoot, fRewriter, owner.findRecommendedLineSeparator(),usingLocalSetter, usingLocalGetter)); 390 createEdits(owner, fRewriter, ownerDescriptions, fImportRewrite); 391 392 sub.done(); 393 IFile[] filesToBeModified= ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()); 394 result.merge(Checks.validateModifiesFiles(filesToBeModified, getValidationContext())); 395 if (result.hasFatalError()) 396 return result; 397 ResourceChangeChecker.checkFilesToBeChanged(filesToBeModified, new SubProgressMonitor(pm, 1)); 398 return result; 399 } 400 401 private void createEdits(ICompilationUnit unit, ASTRewrite rewriter, List groups, ImportRewrite importRewrite) throws CoreException { 402 TextChange change= fChangeManager.get(unit); 403 MultiTextEdit root= new MultiTextEdit(); 404 change.setEdit(root); 405 root.addChild(importRewrite.rewriteImports(null)); 406 root.addChild(rewriter.rewriteAST()); 407 for (Iterator iter= groups.iterator(); iter.hasNext();) { 408 change.addTextEditGroup((TextEditGroup)iter.next()); 409 } 410 } 411 412 public Change createChange(IProgressMonitor pm) throws CoreException { 413 final Map arguments= new HashMap (); 414 String project= null; 415 IJavaProject javaProject= fField.getJavaProject(); 416 if (javaProject != null) 417 project= javaProject.getElementName(); 418 int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE; 419 final IType declaring= fField.getDeclaringType(); 420 try { 421 if (declaring.isAnonymous() || declaring.isLocal()) 422 flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; 423 } catch (JavaModelException exception) { 424 JavaPlugin.log(exception); 425 } 426 final String description= Messages.format(RefactoringCoreMessages.SelfEncapsulateField_descriptor_description_short, fField.getElementName()); 427 final String header= Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_descriptor_description, new String [] { JavaElementLabels.getElementLabel(fField, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED)}); 428 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); 429 comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_original_pattern, JavaElementLabels.getElementLabel(fField, JavaElementLabels.ALL_FULLY_QUALIFIED))); 430 comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_getter_pattern, fGetterName)); 431 comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_setter_pattern, fSetterName)); 432 String visibility= JdtFlags.getVisibilityString(fVisibility); 433 if ("".equals(visibility)) visibility= RefactoringCoreMessages.SelfEncapsulateField_default_visibility; 435 comment.addSetting(Messages.format(RefactoringCoreMessages.SelfEncapsulateField_visibility_pattern, visibility)); 436 if (fEncapsulateDeclaringClass) 437 comment.addSetting(RefactoringCoreMessages.SelfEncapsulateField_use_accessors); 438 else 439 comment.addSetting(RefactoringCoreMessages.SelfEncapsulateField_do_not_use_accessors); 440 if (fGenerateJavadoc) 441 comment.addSetting(RefactoringCoreMessages.SelfEncapsulateField_generate_comments); 442 final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.ENCAPSULATE_FIELD, project, description, comment.asString(), arguments, flags); 443 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fField)); 444 arguments.put(ATTRIBUTE_VISIBILITY, new Integer (fVisibility).toString()); 445 arguments.put(ATTRIBUTE_INSERTION, new Integer (fInsertionIndex).toString()); 446 arguments.put(ATTRIBUTE_SETTER, fSetterName); 447 arguments.put(ATTRIBUTE_GETTER, fGetterName); 448 arguments.put(ATTRIBUTE_COMMENTS, Boolean.valueOf(fGenerateJavadoc).toString()); 449 arguments.put(ATTRIBUTE_DECLARING, Boolean.valueOf(fEncapsulateDeclaringClass).toString()); 450 final DynamicValidationRefactoringChange result= new DynamicValidationRefactoringChange(descriptor, getName()); 451 TextChange[] changes= fChangeManager.getAllChanges(); 452 pm.beginTask(NO_NAME, changes.length); 453 pm.setTaskName(RefactoringCoreMessages.SelfEncapsulateField_create_changes); 454 for (int i= 0; i < changes.length; i++) { 455 result.add(changes[i]); 456 pm.worked(1); 457 } 458 pm.done(); 459 return result; 460 } 461 462 public String getName() { 463 return RefactoringCoreMessages.SelfEncapsulateField_name; 464 } 465 466 468 private void checkCompileErrors(RefactoringStatus result, CompilationUnit root, ICompilationUnit element) { 469 IProblem[] messages= root.getProblems(); 470 for (int i= 0; i < messages.length; i++) { 471 IProblem problem= messages[i]; 472 if (!isIgnorableProblem(problem)) { 473 result.addError(Messages.format( 474 RefactoringCoreMessages.SelfEncapsulateField_compiler_errors_update, 475 element.getElementName()), JavaStatusContext.create(element)); 476 return; 477 } 478 } 479 } 480 481 private void checkInHierarchy(RefactoringStatus status, boolean usingLocalGetter, boolean usingLocalSetter) { 482 AbstractTypeDeclaration declaration= (AbstractTypeDeclaration)ASTNodes.getParent(fFieldDeclaration, AbstractTypeDeclaration.class); 483 ITypeBinding type= declaration.resolveBinding(); 484 if (type != null) { 485 ITypeBinding fieldType= fFieldDeclaration.resolveBinding().getType(); 486 checkMethodInHierarchy(type, fGetterName, fieldType, new ITypeBinding[0], status, usingLocalGetter); 487 checkMethodInHierarchy(type, fSetterName, fFieldDeclaration.getAST().resolveWellKnownType("void"), new ITypeBinding[] {fieldType}, status, usingLocalSetter); 489 } 490 } 491 492 public static void checkMethodInHierarchy(ITypeBinding type, String methodName, ITypeBinding returnType, ITypeBinding[] parameters, RefactoringStatus result, boolean reUseMethod) { 493 IMethodBinding method= Bindings.findMethodInHierarchy(type, methodName, parameters); 494 if (method != null) { 495 boolean returnTypeClash= false; 496 ITypeBinding methodReturnType= method.getReturnType(); 497 if (returnType != null && methodReturnType != null) { 498 String returnTypeKey= returnType.getKey(); 499 String methodReturnTypeKey= methodReturnType.getKey(); 500 if (returnTypeKey == null && methodReturnTypeKey == null) { 501 returnTypeClash= returnType != methodReturnType; 502 } else if (returnTypeKey != null && methodReturnTypeKey != null) { 503 returnTypeClash= !returnTypeKey.equals(methodReturnTypeKey); 504 } 505 } 506 ITypeBinding dc= method.getDeclaringClass(); 507 if (returnTypeClash) { 508 result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_returnTypeClash, 509 new Object [] {methodName, dc.getName()}), 510 JavaStatusContext.create(method)); 511 } else { 512 if (!reUseMethod) 513 result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_overrides, 514 new Object [] {methodName, dc.getName()}), 515 JavaStatusContext.create(method)); 516 } 517 } else { 518 if (reUseMethod){ 519 result.addError(Messages.format(RefactoringCoreMessages.SelfEncapsulateFieldRefactoring_nosuchmethod_status_fatalError, 520 new Object [] {methodName}), 521 JavaStatusContext.create(method)); 522 } 523 } 524 } 525 526 private void computeUsedNames() { 527 fUsedReadNames= new ArrayList (0); 528 fUsedModifyNames= new ArrayList (0); 529 IVariableBinding binding= fFieldDeclaration.resolveBinding(); 530 ITypeBinding type= binding.getType(); 531 IMethodBinding[] methods= binding.getDeclaringClass().getDeclaredMethods(); 532 for (int i= 0; i < methods.length; i++) { 533 IMethodBinding method= methods[i]; 534 ITypeBinding[] parameters= methods[i].getParameterTypes(); 535 if (parameters == null || parameters.length == 0) { 536 fUsedReadNames.add(method); 537 } else if (parameters.length == 1 && parameters[0] == type) { 538 fUsedModifyNames.add(method); 539 } 540 } 541 } 542 543 private List addGetterSetterChanges(CompilationUnit root, ASTRewrite rewriter, String lineDelimiter, boolean usingLocalSetter, boolean usingLocalGetter) throws CoreException { 544 List result= new ArrayList (2); 545 AST ast= root.getAST(); 546 FieldDeclaration decl= (FieldDeclaration)ASTNodes.getParent(fFieldDeclaration, ASTNode.FIELD_DECLARATION); 547 int position= 0; 548 int numberOfMethods= 0; 549 List members= ASTNodes.getBodyDeclarations(decl.getParent()); 550 for (Iterator iter= members.iterator(); iter.hasNext();) { 551 BodyDeclaration element= (BodyDeclaration)iter.next(); 552 if (element.getNodeType() == ASTNode.METHOD_DECLARATION) { 553 if (fInsertionIndex == -1) { 554 break; 555 } else if (fInsertionIndex == numberOfMethods) { 556 position++; 557 break; 558 } 559 numberOfMethods++; 560 } 561 position++; 562 } 563 TextEditGroup description; 564 ListRewrite rewrite= fRewriter.getListRewrite(decl.getParent(), getBodyDeclarationsProperty(decl.getParent())); 565 if (!JdtFlags.isFinal(fField) && !usingLocalSetter) { 566 description= new TextEditGroup(RefactoringCoreMessages.SelfEncapsulateField_add_setter); 567 result.add(description); 568 rewrite.insertAt(createSetterMethod(ast, rewriter, lineDelimiter), position++, description); 569 } 570 if (!usingLocalGetter){ 571 description= new TextEditGroup(RefactoringCoreMessages.SelfEncapsulateField_add_getter); 572 result.add(description); 573 rewrite.insertAt(createGetterMethod(ast, rewriter, lineDelimiter), position, description); 574 } 575 if (!JdtFlags.isPrivate(fField)) 576 result.add(makeDeclarationPrivate(rewriter, decl)); 577 return result; 578 } 579 580 private TextEditGroup makeDeclarationPrivate(ASTRewrite rewriter, FieldDeclaration decl) { 581 AST ast= rewriter.getAST(); 582 TextEditGroup description= new TextEditGroup(RefactoringCoreMessages.SelfEncapsulateField_change_visibility); 583 if (decl.fragments().size() > 1) { 584 rewriter.remove(fFieldDeclaration, description); 586 ChildListPropertyDescriptor descriptor= getBodyDeclarationsProperty(decl.getParent()); 587 VariableDeclarationFragment newField= (VariableDeclarationFragment) rewriter.createCopyTarget(fFieldDeclaration); 588 FieldDeclaration fieldDecl= ast.newFieldDeclaration(newField); 589 fieldDecl.setType((Type)rewriter.createCopyTarget(decl.getType())); 590 fieldDecl.modifiers().addAll(ASTNodeFactory.newModifiers(ast, Modifier.PRIVATE)); 591 rewriter.getListRewrite(decl.getParent(), descriptor).insertAfter(fieldDecl, decl, description); 592 } else { 593 ModifierRewrite.create(rewriter, decl).setVisibility(Modifier.PRIVATE, description); 594 } 595 return description; 596 } 597 598 private ChildListPropertyDescriptor getBodyDeclarationsProperty(ASTNode declaration) { 599 if (declaration instanceof AnonymousClassDeclaration) 600 return AnonymousClassDeclaration.BODY_DECLARATIONS_PROPERTY; 601 else if (declaration instanceof AbstractTypeDeclaration) 602 return ((AbstractTypeDeclaration) declaration).getBodyDeclarationsProperty(); 603 Assert.isTrue(false); 604 return null; 605 } 606 607 private MethodDeclaration createSetterMethod(AST ast, ASTRewrite rewriter, String lineDelimiter) throws CoreException { 608 FieldDeclaration field= (FieldDeclaration)ASTNodes.getParent(fFieldDeclaration, FieldDeclaration.class); 609 Type type= field.getType(); 610 MethodDeclaration result= ast.newMethodDeclaration(); 611 result.setName(ast.newSimpleName(fSetterName)); 612 result.modifiers().addAll(ASTNodeFactory.newModifiers(ast, createModifiers())); 613 if (fSetterMustReturnValue) { 614 result.setReturnType2((Type)rewriter.createCopyTarget(type)); 615 } 616 SingleVariableDeclaration param= ast.newSingleVariableDeclaration(); 617 result.parameters().add(param); 618 param.setName(ast.newSimpleName(fArgName)); 619 param.setType((Type)rewriter.createCopyTarget(type)); 620 621 Block block= ast.newBlock(); 622 result.setBody(block); 623 Assignment ass= ast.newAssignment(); 624 ass.setLeftHandSide(createFieldAccess(ast)); 625 ass.setRightHandSide(ast.newSimpleName(fArgName)); 626 if (fSetterMustReturnValue) { 627 ReturnStatement rs= ast.newReturnStatement(); 628 rs.setExpression(ass); 629 block.statements().add(rs); 630 } else { 631 block.statements().add(ast.newExpressionStatement(ass)); 632 } 633 634 if (fGenerateJavadoc) { 635 String string= CodeGeneration.getSetterComment( 636 fField.getCompilationUnit() , getTypeName(field.getParent()), fSetterName, 637 fField.getElementName(), ASTNodes.asString(type), fArgName, 638 NamingConventions.removePrefixAndSuffixForFieldName(fField.getJavaProject(), fField.getElementName(), fField.getFlags()), 639 lineDelimiter); 640 if (string != null) { 641 Javadoc javadoc= (Javadoc)fRewriter.createStringPlaceholder(string, ASTNode.JAVADOC); 642 result.setJavadoc(javadoc); 643 } 644 } 645 return result; 646 } 647 648 private MethodDeclaration createGetterMethod(AST ast, ASTRewrite rewriter, String lineDelimiter) throws CoreException { 649 FieldDeclaration field= (FieldDeclaration)ASTNodes.getParent(fFieldDeclaration, FieldDeclaration.class); 650 Type type= field.getType(); 651 MethodDeclaration result= ast.newMethodDeclaration(); 652 result.setName(ast.newSimpleName(fGetterName)); 653 result.modifiers().addAll(ASTNodeFactory.newModifiers(ast, createModifiers())); 654 result.setReturnType2((Type)rewriter.createCopyTarget(type)); 655 656 Block block= ast.newBlock(); 657 result.setBody(block); 658 ReturnStatement rs= ast.newReturnStatement(); 659 rs.setExpression(ast.newSimpleName(fField.getElementName())); 660 block.statements().add(rs); 661 if (fGenerateJavadoc) { 662 String string= CodeGeneration.getGetterComment( 663 fField.getCompilationUnit() , getTypeName(field.getParent()), fGetterName, 664 fField.getElementName(), ASTNodes.asString(type), 665 NamingConventions.removePrefixAndSuffixForFieldName(fField.getJavaProject(), fField.getElementName(), fField.getFlags()), 666 lineDelimiter); 667 if (string != null) { 668 Javadoc javadoc= (Javadoc)fRewriter.createStringPlaceholder(string, ASTNode.JAVADOC); 669 result.setJavadoc(javadoc); 670 } 671 } 672 return result; 673 } 674 675 private int createModifiers() throws JavaModelException { 676 int result= 0; 677 if (Flags.isPublic(fVisibility)) 678 result |= Modifier.PUBLIC; 679 else if (Flags.isProtected(fVisibility)) 680 result |= Modifier.PROTECTED; 681 else if (Flags.isPrivate(fVisibility)) 682 result |= Modifier.PRIVATE; 683 if (JdtFlags.isStatic(fField)) 684 result |= Modifier.STATIC; 685 return result; 686 } 687 688 private Expression createFieldAccess(AST ast) throws JavaModelException { 689 String fieldName= fField.getElementName(); 690 if (fArgName.equals(fieldName)) { 691 if (JdtFlags.isStatic(fField)) { 692 return ast.newQualifiedName( 693 ast.newSimpleName(fField.getDeclaringType().getElementName()), 694 ast.newSimpleName(fieldName)); 695 } else { 696 FieldAccess result= ast.newFieldAccess(); 697 result.setExpression(ast.newThisExpression()); 698 result.setName(ast.newSimpleName(fieldName)); 699 return result; 700 } 701 } else { 702 return ast.newSimpleName(fieldName); 703 } 704 } 705 706 private void checkArgName() { 707 String fieldName= fField.getElementName(); 708 boolean isStatic= true; 709 try { 710 isStatic= JdtFlags.isStatic(fField); 711 } catch(JavaModelException e) { 712 } 713 IJavaProject project= fField.getJavaProject(); 714 String sourceLevel= project.getOption(JavaCore.COMPILER_SOURCE, true); 715 String compliance= project.getOption(JavaCore.COMPILER_COMPLIANCE, true); 716 717 if ((isStatic && fArgName.equals(fieldName) && fieldName.equals(fField.getDeclaringType().getElementName())) 718 || JavaConventions.validateIdentifier(fArgName, sourceLevel, compliance).getSeverity() == IStatus.ERROR) 719 fArgName= "_" + fArgName; } 721 722 private String getTypeName(ASTNode type) { 723 if (type instanceof AbstractTypeDeclaration) { 724 return ((AbstractTypeDeclaration)type).getName().getIdentifier(); 725 } else if (type instanceof AnonymousClassDeclaration) { 726 ClassInstanceCreation node= (ClassInstanceCreation)ASTNodes.getParent(type, ClassInstanceCreation.class); 727 return ASTNodes.asString(node.getType()); 728 } 729 Assert.isTrue(false, "Should not happen"); return null; 731 } 732 733 public RefactoringStatus initialize(RefactoringArguments arguments) { 734 if (arguments instanceof JavaRefactoringArguments) { 735 final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; 736 final String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT); 737 if (handle != null) { 738 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 739 if (element == null || !element.exists() || element.getElementType() != IJavaElement.FIELD) 740 return createInputFatalStatus(element, IJavaRefactorings.ENCAPSULATE_FIELD); 741 else { 742 fField= (IField) element; 743 try { 744 initialize(fField); 745 } catch (JavaModelException exception) { 746 return createInputFatalStatus(element, IJavaRefactorings.ENCAPSULATE_FIELD); 747 } 748 } 749 } else 750 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JDTRefactoringDescriptor.ATTRIBUTE_INPUT)); 751 String name= extended.getAttribute(ATTRIBUTE_GETTER); 752 if (name != null && !"".equals(name)) fGetterName= name; 754 else 755 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_GETTER)); 756 name= extended.getAttribute(ATTRIBUTE_SETTER); 757 if (name != null && !"".equals(name)) fSetterName= name; 759 else 760 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_SETTER)); 761 final String encapsulate= extended.getAttribute(ATTRIBUTE_DECLARING); 762 if (encapsulate != null) { 763 fEncapsulateDeclaringClass= Boolean.valueOf(encapsulate).booleanValue(); 764 } else 765 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DECLARING)); 766 final String matches= extended.getAttribute(ATTRIBUTE_COMMENTS); 767 if (matches != null) { 768 fGenerateJavadoc= Boolean.valueOf(matches).booleanValue(); 769 } else 770 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_COMMENTS)); 771 final String visibility= extended.getAttribute(ATTRIBUTE_VISIBILITY); 772 if (visibility != null && !"".equals(visibility)) { int flag= 0; 774 try { 775 flag= Integer.parseInt(visibility); 776 } catch (NumberFormatException exception) { 777 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_VISIBILITY)); 778 } 779 fVisibility= flag; 780 } 781 final String insertion= extended.getAttribute(ATTRIBUTE_INSERTION); 782 if (insertion != null && !"".equals(insertion)) { int index= 0; 784 try { 785 index= Integer.parseInt(insertion); 786 } catch (NumberFormatException exception) { 787 return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_INSERTION)); 788 } 789 fInsertionIndex= index; 790 } 791 } else 792 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); 793 return new RefactoringStatus(); 794 } 795 796 public boolean isUsingLocalGetter() { 797 IType declaringType= fField.getDeclaringType(); 798 return checkName(fGetterName, fUsedReadNames, declaringType); 799 } 800 801 public boolean isUsingLocalSetter() { 802 IType declaringType= fField.getDeclaringType(); 803 return checkName(fSetterName, fUsedModifyNames, declaringType); 804 } 805 806 private static boolean checkName(String name, List usedNames, IType type) { 807 for (Iterator iter= usedNames.iterator(); iter.hasNext(); ) { 808 IMethodBinding method= (IMethodBinding)iter.next(); 809 String selector= method.getName(); 810 if (selector.equals(name)) { 811 return true; 812 } 813 } 814 return false; 815 } 816 817 private boolean isIgnorableProblem(IProblem problem) { 818 if (problem.getID() == IProblem.NotVisibleField) 819 return true; 820 return false; 821 } 822 823 public boolean isConsiderVisibility() { 824 return fConsiderVisibility; 825 } 826 827 public void setConsiderVisibility(boolean considerVisibility) { 828 fConsiderVisibility= considerVisibility; 829 } 830 831 832 } 833 | Popular Tags |