1 11 package org.eclipse.jdt.internal.corext.refactoring.structure; 12 13 import java.util.ArrayList ; 14 import java.util.Arrays ; 15 import java.util.Collection ; 16 import java.util.HashMap ; 17 import java.util.HashSet ; 18 import java.util.Iterator ; 19 import java.util.List ; 20 import java.util.Map ; 21 import java.util.Set ; 22 23 import org.eclipse.text.edits.MalformedTreeException; 24 import org.eclipse.text.edits.TextEdit; 25 26 import org.eclipse.core.runtime.Assert; 27 import org.eclipse.core.runtime.CoreException; 28 import org.eclipse.core.runtime.IProgressMonitor; 29 import org.eclipse.core.runtime.OperationCanceledException; 30 import org.eclipse.core.runtime.SubProgressMonitor; 31 32 import org.eclipse.jface.text.BadLocationException; 33 import org.eclipse.jface.text.Document; 34 import org.eclipse.jface.text.IDocument; 35 36 import org.eclipse.ltk.core.refactoring.Change; 37 import org.eclipse.ltk.core.refactoring.GroupCategory; 38 import org.eclipse.ltk.core.refactoring.GroupCategorySet; 39 import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; 40 import org.eclipse.ltk.core.refactoring.RefactoringStatus; 41 import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; 42 import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments; 43 44 import org.eclipse.jdt.core.Flags; 45 import org.eclipse.jdt.core.ICompilationUnit; 46 import org.eclipse.jdt.core.IField; 47 import org.eclipse.jdt.core.IJavaElement; 48 import org.eclipse.jdt.core.IJavaProject; 49 import org.eclipse.jdt.core.IMember; 50 import org.eclipse.jdt.core.IMethod; 51 import org.eclipse.jdt.core.IType; 52 import org.eclipse.jdt.core.ITypeHierarchy; 53 import org.eclipse.jdt.core.JavaModelException; 54 import org.eclipse.jdt.core.dom.AST; 55 import org.eclipse.jdt.core.dom.ASTNode; 56 import org.eclipse.jdt.core.dom.ASTRequestor; 57 import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; 58 import org.eclipse.jdt.core.dom.Block; 59 import org.eclipse.jdt.core.dom.CompilationUnit; 60 import org.eclipse.jdt.core.dom.Expression; 61 import org.eclipse.jdt.core.dom.FieldDeclaration; 62 import org.eclipse.jdt.core.dom.MarkerAnnotation; 63 import org.eclipse.jdt.core.dom.MethodDeclaration; 64 import org.eclipse.jdt.core.dom.Modifier; 65 import org.eclipse.jdt.core.dom.Type; 66 import org.eclipse.jdt.core.dom.VariableDeclarationFragment; 67 import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; 68 import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; 69 import org.eclipse.jdt.core.refactoring.IJavaRefactorings; 70 import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; 71 import org.eclipse.jdt.core.search.IJavaSearchConstants; 72 import org.eclipse.jdt.core.search.SearchEngine; 73 import org.eclipse.jdt.core.search.SearchMatch; 74 import org.eclipse.jdt.core.search.SearchPattern; 75 76 import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility; 77 import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory; 78 import org.eclipse.jdt.internal.corext.dom.ASTNodes; 79 import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; 80 import org.eclipse.jdt.internal.corext.refactoring.Checks; 81 import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; 82 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptor; 83 import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; 84 import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester; 85 import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; 86 import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; 87 import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; 88 import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; 89 import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; 90 import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring; 91 import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks; 92 import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil; 93 import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager; 94 import org.eclipse.jdt.internal.corext.util.JavaModelUtil; 95 import org.eclipse.jdt.internal.corext.util.JdtFlags; 96 import org.eclipse.jdt.internal.corext.util.Messages; 97 import org.eclipse.jdt.internal.corext.util.SearchUtils; 98 import org.eclipse.jdt.internal.corext.util.Strings; 99 100 import org.eclipse.jdt.ui.JavaElementLabels; 101 102 import org.eclipse.jdt.internal.ui.JavaPlugin; 103 import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; 104 105 110 public final class PushDownRefactoringProcessor extends HierarchyProcessor { 111 112 public static class MemberActionInfo implements IMemberActionInfo { 113 114 public static final int NO_ACTION= 2; 115 116 public static final int PUSH_ABSTRACT_ACTION= 1; 117 118 public static final int PUSH_DOWN_ACTION= 0; 119 120 private static void assertValidAction(IMember member, int action) { 121 if (member instanceof IMethod) 122 Assert.isTrue(action == PUSH_ABSTRACT_ACTION || action == NO_ACTION || action == PUSH_DOWN_ACTION); 123 else if (member instanceof IField) 124 Assert.isTrue(action == NO_ACTION || action == PUSH_DOWN_ACTION); 125 } 126 127 public static MemberActionInfo create(IMember member, int action) { 128 return new MemberActionInfo(member, action); 129 } 130 131 static IMember[] getMembers(MemberActionInfo[] infos) { 132 IMember[] result= new IMember[infos.length]; 133 for (int i= 0; i < result.length; i++) { 134 result[i]= infos[i].getMember(); 135 } 136 return result; 137 } 138 139 private int fAction; 140 141 private final IMember fMember; 142 143 private MemberActionInfo(IMember member, int action) { 144 assertValidAction(member, action); 145 Assert.isTrue(member instanceof IField || member instanceof IMethod); 146 fMember= member; 147 fAction= action; 148 } 149 150 boolean copyJavadocToCopiesInSubclasses() { 151 return isToBeDeletedFromDeclaringClass(); 152 } 153 154 public int getAction() { 155 return fAction; 156 } 157 158 public int[] getAvailableActions() { 159 if (isFieldInfo()) 160 return new int[] { PUSH_DOWN_ACTION, NO_ACTION }; 161 162 return new int[] { PUSH_DOWN_ACTION, PUSH_ABSTRACT_ACTION, NO_ACTION }; 163 } 164 165 public IMember getMember() { 166 return fMember; 167 } 168 169 int getNewModifiersForCopyInSubclass(int oldModifiers) throws JavaModelException { 170 if (isFieldInfo()) 171 return oldModifiers; 172 if (isToBeDeletedFromDeclaringClass()) 173 return oldModifiers; 174 int modifiers= oldModifiers; 175 if (isNewMethodToBeDeclaredAbstract()) { 176 if (!JdtFlags.isPublic(fMember)) 177 modifiers= Modifier.PROTECTED | JdtFlags.clearAccessModifiers(modifiers); 178 } 179 return modifiers; 180 } 181 182 int getNewModifiersForOriginal(int oldModifiers) throws JavaModelException { 183 if (isFieldInfo()) 184 return oldModifiers; 185 if (isToBeDeletedFromDeclaringClass()) 186 return oldModifiers; 187 int modifiers= oldModifiers; 188 if (isNewMethodToBeDeclaredAbstract()) { 189 modifiers= JdtFlags.clearFlag(Modifier.FINAL | Modifier.NATIVE, oldModifiers); 190 modifiers|= Modifier.ABSTRACT; 191 192 if (!JdtFlags.isPublic(fMember)) 193 modifiers= Modifier.PROTECTED | JdtFlags.clearAccessModifiers(modifiers); 194 } 195 return modifiers; 196 } 197 198 public boolean isActive() { 199 return getAction() != NO_ACTION; 200 } 201 202 public boolean isEditable() { 203 if (isFieldInfo()) 204 return false; 205 if (getAction() == MemberActionInfo.NO_ACTION) 206 return false; 207 return true; 208 } 209 210 boolean isFieldInfo() { 211 return fMember instanceof IField; 212 } 213 214 boolean isNewMethodToBeDeclaredAbstract() throws JavaModelException { 215 return !isFieldInfo() && !JdtFlags.isAbstract(fMember) && fAction == PUSH_ABSTRACT_ACTION; 216 } 217 218 boolean isToBeCreatedInSubclassesOfDeclaringClass() { 219 return fAction != NO_ACTION; 220 } 221 222 boolean isToBeDeletedFromDeclaringClass() { 223 return isToBePushedDown(); 224 } 225 226 public boolean isToBePushedDown() { 227 return fAction == PUSH_DOWN_ACTION; 228 } 229 230 public void setAction(int action) { 231 assertValidAction(fMember, action); 232 if (isFieldInfo()) 233 Assert.isTrue(action != PUSH_ABSTRACT_ACTION); 234 fAction= action; 235 } 236 237 } 238 239 private static final String ATTRIBUTE_ABSTRACT= "abstract"; 241 private static final String ATTRIBUTE_PUSH= "push"; 243 244 public static final String IDENTIFIER= "org.eclipse.jdt.ui.pushDownProcessor"; 246 247 private static final GroupCategorySet SET_PUSH_DOWN= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.pushDown", RefactoringCoreMessages.PushDownRefactoring_category_name, RefactoringCoreMessages.PushDownRefactoring_category_description)); 249 250 private static MemberActionInfo[] createInfosForAllPushableFieldsAndMethods(IType type) throws JavaModelException { 251 List result= new ArrayList (); 252 IMember[] pushableMembers= RefactoringAvailabilityTester.getPushDownMembers(type); 253 for (int i= 0; i < pushableMembers.length; i++) { 254 result.add(MemberActionInfo.create(pushableMembers[i], MemberActionInfo.NO_ACTION)); 255 } 256 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 257 } 258 259 private static IMember[] getAbstractMembers(IMember[] members) throws JavaModelException { 260 List result= new ArrayList (members.length); 261 for (int i= 0; i < members.length; i++) { 262 IMember member= members[i]; 263 if (JdtFlags.isAbstract(member)) 264 result.add(member); 265 } 266 return (IMember[]) result.toArray(new IMember[result.size()]); 267 } 268 269 private static CompilationUnitRewrite getCompilationUnitRewrite(final Map rewrites, final ICompilationUnit unit) { 270 Assert.isNotNull(rewrites); 271 Assert.isNotNull(unit); 272 CompilationUnitRewrite rewrite= (CompilationUnitRewrite) rewrites.get(unit); 273 if (rewrite == null) { 274 rewrite= new CompilationUnitRewrite(unit); 275 rewrites.put(unit, rewrite); 276 } 277 return rewrite; 278 } 279 280 private static IJavaElement[] getReferencingElementsFromSameClass(IMember member, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { 281 Assert.isNotNull(member); 282 final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); 283 engine.setFiltering(true, true); 284 engine.setScope(SearchEngine.createJavaSearchScope(new IJavaElement[] { member.getDeclaringType() })); 285 engine.setStatus(status); 286 engine.searchPattern(new SubProgressMonitor(pm, 1)); 287 SearchResultGroup[] groups= (SearchResultGroup[]) engine.getResults(); 288 Set result= new HashSet (3); 289 for (int i= 0; i < groups.length; i++) { 290 SearchResultGroup group= groups[i]; 291 SearchMatch[] results= group.getSearchResults(); 292 for (int j= 0; j < results.length; j++) { 293 SearchMatch searchResult= results[i]; 294 result.add(SearchUtils.getEnclosingJavaElement(searchResult)); 295 } 296 } 297 return (IJavaElement[]) result.toArray(new IJavaElement[result.size()]); 298 } 299 300 private ITypeHierarchy fCachedClassHierarchy; 301 302 private MemberActionInfo[] fMemberInfos; 303 304 311 public PushDownRefactoringProcessor(IMember[] members) { 312 super(members, null, false); 313 if (members != null) { 314 final IType type= RefactoringAvailabilityTester.getTopLevelType(members); 315 try { 316 if (type != null && RefactoringAvailabilityTester.getPushDownMembers(type).length != 0) { 317 fMembersToMove= new IMember[0]; 318 fCachedDeclaringType= type; 319 } 320 } catch (JavaModelException exception) { 321 JavaPlugin.log(exception); 322 } 323 } 324 } 325 326 private void addAllRequiredPushableMembers(List queue, IMember member, IProgressMonitor monitor) throws JavaModelException { 327 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, 2); 328 IProgressMonitor sub= new SubProgressMonitor(monitor, 1); 329 sub.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, 2); 330 IMethod[] requiredMethods= ReferenceFinderUtil.getMethodsReferencedIn(new IJavaElement[] { member }, new SubProgressMonitor(sub, 1)); 331 sub= new SubProgressMonitor(sub, 1); 332 sub.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, requiredMethods.length); 333 for (int index= 0; index < requiredMethods.length; index++) { 334 IMethod method= requiredMethods[index]; 335 if (!MethodChecks.isVirtual(method) && (method.getDeclaringType().equals(getDeclaringType()) && !queue.contains(method) && RefactoringAvailabilityTester.isPushDownAvailable(method))) 336 queue.add(method); 337 } 338 sub.done(); 339 IField[] requiredFields= ReferenceFinderUtil.getFieldsReferencedIn(new IJavaElement[] { member }, new SubProgressMonitor(monitor, 1)); 340 for (int index= 0; index < requiredFields.length; index++) { 341 IField field= requiredFields[index]; 342 if (field.getDeclaringType().equals(getDeclaringType()) && !queue.contains(field) && RefactoringAvailabilityTester.isPushDownAvailable(field)) 343 queue.add(field); 344 } 345 monitor.done(); 346 } 347 348 private RefactoringStatus checkAbstractMembersInDestinationClasses(IMember[] membersToPushDown, IType[] destinationClassesForAbstract) throws JavaModelException { 349 RefactoringStatus result= new RefactoringStatus(); 350 IMember[] abstractMembersToPushDown= getAbstractMembers(membersToPushDown); 351 for (int index= 0; index < destinationClassesForAbstract.length; index++) { 352 result.merge(MemberCheckUtil.checkMembersInDestinationType(abstractMembersToPushDown, destinationClassesForAbstract[index])); 353 } 354 return result; 355 } 356 357 private RefactoringStatus checkAccessedFields(IType[] subclasses, IProgressMonitor pm) throws JavaModelException { 358 RefactoringStatus result= new RefactoringStatus(); 359 IMember[] membersToPushDown= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()); 360 List pushedDownList= Arrays.asList(membersToPushDown); 361 IField[] accessedFields= ReferenceFinderUtil.getFieldsReferencedIn(membersToPushDown, pm); 362 for (int i= 0; i < subclasses.length; i++) { 363 IType targetClass= subclasses[i]; 364 ITypeHierarchy targetSupertypes= targetClass.newSupertypeHierarchy(null); 365 for (int j= 0; j < accessedFields.length; j++) { 366 IField field= accessedFields[j]; 367 boolean isAccessible= pushedDownList.contains(field) || canBeAccessedFrom(field, targetClass, targetSupertypes) || Flags.isEnum(field.getFlags()); 368 if (!isAccessible) { 369 String message= Messages.format(RefactoringCoreMessages.PushDownRefactoring_field_not_accessible, new String [] { JavaElementLabels.getTextLabel(field, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(targetClass, JavaElementLabels.ALL_FULLY_QUALIFIED) }); 370 result.addError(message, JavaStatusContext.create(field)); 371 } 372 } 373 } 374 pm.done(); 375 return result; 376 } 377 378 private RefactoringStatus checkAccessedMethods(IType[] subclasses, IProgressMonitor pm) throws JavaModelException { 379 RefactoringStatus result= new RefactoringStatus(); 380 IMember[] membersToPushDown= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()); 381 List pushedDownList= Arrays.asList(membersToPushDown); 382 IMethod[] accessedMethods= ReferenceFinderUtil.getMethodsReferencedIn(membersToPushDown, pm); 383 for (int index= 0; index < subclasses.length; index++) { 384 IType targetClass= subclasses[index]; 385 ITypeHierarchy targetSupertypes= targetClass.newSupertypeHierarchy(null); 386 for (int offset= 0; offset < accessedMethods.length; offset++) { 387 IMethod method= accessedMethods[offset]; 388 boolean isAccessible= pushedDownList.contains(method) || canBeAccessedFrom(method, targetClass, targetSupertypes); 389 if (!isAccessible) { 390 String message= Messages.format(RefactoringCoreMessages.PushDownRefactoring_method_not_accessible, new String [] { JavaElementLabels.getTextLabel(method, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(targetClass, JavaElementLabels.ALL_FULLY_QUALIFIED) }); 391 result.addError(message, JavaStatusContext.create(method)); 392 } 393 } 394 } 395 pm.done(); 396 return result; 397 } 398 399 private RefactoringStatus checkAccessedTypes(IType[] subclasses, IProgressMonitor pm) throws JavaModelException { 400 RefactoringStatus result= new RefactoringStatus(); 401 IType[] accessedTypes= getTypesReferencedInMovedMembers(pm); 402 for (int index= 0; index < subclasses.length; index++) { 403 IType targetClass= subclasses[index]; 404 ITypeHierarchy targetSupertypes= targetClass.newSupertypeHierarchy(null); 405 for (int offset= 0; offset < accessedTypes.length; offset++) { 406 IType type= accessedTypes[offset]; 407 if (!canBeAccessedFrom(type, targetClass, targetSupertypes)) { 408 String message= Messages.format(RefactoringCoreMessages.PushDownRefactoring_type_not_accessible, new String [] { JavaElementLabels.getTextLabel(type, JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getTextLabel(targetClass, JavaElementLabels.ALL_FULLY_QUALIFIED) }); 409 result.addError(message, JavaStatusContext.create(type)); 410 } 411 } 412 } 413 pm.done(); 414 return result; 415 } 416 417 private RefactoringStatus checkElementsAccessedByModifiedMembers(IProgressMonitor pm) throws JavaModelException { 418 RefactoringStatus result= new RefactoringStatus(); 419 pm.beginTask(RefactoringCoreMessages.PushDownRefactoring_check_references, 3); 420 IType[] subclasses= getAbstractDestinations(new SubProgressMonitor(pm, 1)); 421 result.merge(checkAccessedTypes(subclasses, new SubProgressMonitor(pm, 1))); 422 result.merge(checkAccessedFields(subclasses, new SubProgressMonitor(pm, 1))); 423 result.merge(checkAccessedMethods(subclasses, new SubProgressMonitor(pm, 1))); 424 pm.done(); 425 return result; 426 } 427 428 431 public RefactoringStatus checkFinalConditions(IProgressMonitor monitor, CheckConditionsContext context) throws CoreException, OperationCanceledException { 432 try { 433 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 5); 434 clearCaches(); 435 ICompilationUnit unit= getDeclaringType().getCompilationUnit(); 436 if (fLayer) 437 unit= unit.findWorkingCopy(fOwner); 438 resetWorkingCopies(unit); 439 final RefactoringStatus result= new RefactoringStatus(); 440 result.merge(checkMembersInDestinationClasses(new SubProgressMonitor(monitor, 1))); 441 result.merge(checkElementsAccessedByModifiedMembers(new SubProgressMonitor(monitor, 1))); 442 result.merge(checkReferencesToPushedDownMembers(new SubProgressMonitor(monitor, 1))); 443 if (!JdtFlags.isAbstract(getDeclaringType()) && getAbstractDeclarationInfos().length != 0) 444 result.merge(checkConstructorCalls(getDeclaringType(), new SubProgressMonitor(monitor, 1))); 445 else 446 monitor.worked(1); 447 if (result.hasFatalError()) 448 return result; 449 List members= new ArrayList (fMemberInfos.length); 450 for (int index= 0; index < fMemberInfos.length; index++) { 451 if (fMemberInfos[index].getAction() != MemberActionInfo.NO_ACTION) 452 members.add(fMemberInfos[index].getMember()); 453 } 454 fMembersToMove= (IMember[]) members.toArray(new IMember[members.size()]); 455 fChangeManager= createChangeManager(new SubProgressMonitor(monitor, 1), result); 456 if (result.hasFatalError()) 457 return result; 458 result.merge(Checks.validateModifiesFiles(ResourceUtil.getFiles(fChangeManager.getAllCompilationUnits()), getRefactoring().getValidationContext())); 459 return result; 460 } finally { 461 monitor.done(); 462 } 463 } 464 465 468 public RefactoringStatus checkInitialConditions(IProgressMonitor monitor) throws CoreException, OperationCanceledException { 469 try { 470 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 1); 471 RefactoringStatus status= new RefactoringStatus(); 472 status.merge(checkPossibleSubclasses(new SubProgressMonitor(monitor, 1))); 473 if (status.hasFatalError()) 474 return status; 475 status.merge(checkDeclaringType(new SubProgressMonitor(monitor, 1))); 476 if (status.hasFatalError()) 477 return status; 478 status.merge(checkIfMembersExist()); 479 if (status.hasFatalError()) 480 return status; 481 fMemberInfos= createInfosForAllPushableFieldsAndMethods(getDeclaringType()); 482 List list= Arrays.asList(fMembersToMove); 483 for (int offset= 0; offset < fMemberInfos.length; offset++) { 484 MemberActionInfo info= fMemberInfos[offset]; 485 if (list.contains(info.getMember())) 486 info.setAction(MemberActionInfo.PUSH_DOWN_ACTION); 487 } 488 return status; 489 } finally { 490 monitor.done(); 491 } 492 } 493 494 private RefactoringStatus checkMembersInDestinationClasses(IProgressMonitor monitor) throws JavaModelException { 495 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 2); 496 RefactoringStatus result= new RefactoringStatus(); 497 IMember[] membersToPushDown= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()); 498 499 IType[] destinationClassesForNonAbstract= getAbstractDestinations(new SubProgressMonitor(monitor, 1)); 500 result.merge(checkNonAbstractMembersInDestinationClasses(membersToPushDown, destinationClassesForNonAbstract)); 501 List list= Arrays.asList(getAbstractMembers(getAbstractDestinations(new SubProgressMonitor(monitor, 1)))); 502 503 IType[] destinationClassesForAbstract= (IType[]) list.toArray(new IType[list.size()]); 504 result.merge(checkAbstractMembersInDestinationClasses(membersToPushDown, destinationClassesForAbstract)); 505 monitor.done(); 506 return result; 507 } 508 509 private RefactoringStatus checkNonAbstractMembersInDestinationClasses(IMember[] membersToPushDown, IType[] destinationClassesForNonAbstract) throws JavaModelException { 510 RefactoringStatus result= new RefactoringStatus(); 511 List list= new ArrayList (); list.addAll(Arrays.asList(membersToPushDown)); 513 list.removeAll(Arrays.asList(getAbstractMembers(membersToPushDown))); 514 IMember[] nonAbstractMembersToPushDown= (IMember[]) list.toArray(new IMember[list.size()]); 515 for (int i= 0; i < destinationClassesForNonAbstract.length; i++) { 516 result.merge(MemberCheckUtil.checkMembersInDestinationType(nonAbstractMembersToPushDown, destinationClassesForNonAbstract[i])); 517 } 518 return result; 519 } 520 521 private RefactoringStatus checkPossibleSubclasses(IProgressMonitor pm) throws JavaModelException { 522 IType[] modifiableSubclasses= getAbstractDestinations(pm); 523 if (modifiableSubclasses.length == 0) { 524 String msg= Messages.format(RefactoringCoreMessages.PushDownRefactoring_no_subclasses, new String [] { JavaElementLabels.getTextLabel(getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED) }); 525 return RefactoringStatus.createFatalErrorStatus(msg); 526 } 527 return new RefactoringStatus(); 528 } 529 530 private RefactoringStatus checkReferencesToPushedDownMembers(IProgressMonitor monitor) throws JavaModelException { 531 List fields= new ArrayList (fMemberInfos.length); 532 for (int index= 0; index < fMemberInfos.length; index++) { 533 MemberActionInfo info= fMemberInfos[index]; 534 if (info.isToBePushedDown()) 535 fields.add(info.getMember()); 536 } 537 IMember[] membersToPush= (IMember[]) fields.toArray(new IMember[fields.size()]); 538 RefactoringStatus result= new RefactoringStatus(); 539 List movedMembers= Arrays.asList(MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass())); 540 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_check_references, membersToPush.length); 541 for (int index= 0; index < membersToPush.length; index++) { 542 IMember member= membersToPush[index]; 543 String label= createLabel(member); 544 IJavaElement[] referencing= getReferencingElementsFromSameClass(member, new SubProgressMonitor(monitor, 1), result); 545 for (int offset= 0; offset < referencing.length; offset++) { 546 IJavaElement element= referencing[offset]; 547 if (movedMembers.contains(element)) 548 continue; 549 if (!(element instanceof IMember)) 550 continue; 551 IMember referencingMember= (IMember) element; 552 Object [] keys= { label, createLabel(referencingMember) }; 553 String msg= Messages.format(RefactoringCoreMessages.PushDownRefactoring_referenced, keys); 554 result.addError(msg, JavaStatusContext.create(referencingMember)); 555 } 556 } 557 monitor.done(); 558 return result; 559 } 560 561 public void computeAdditionalRequiredMembersToPushDown(IProgressMonitor monitor) throws JavaModelException { 562 List list= Arrays.asList(getAdditionalRequiredMembers(monitor)); 563 for (int index= 0; index < fMemberInfos.length; index++) { 564 MemberActionInfo info= fMemberInfos[index]; 565 if (list.contains(info.getMember())) 566 info.setAction(MemberActionInfo.PUSH_DOWN_ACTION); 567 } 568 } 569 570 private void copyBodyOfPushedDownMethod(ASTRewrite targetRewrite, IMethod method, MethodDeclaration oldMethod, MethodDeclaration newMethod, TypeVariableMaplet[] mapping) throws JavaModelException { 571 Block body= oldMethod.getBody(); 572 if (body == null) { 573 newMethod.setBody(null); 574 return; 575 } 576 try { 577 final IDocument document= new Document(method.getCompilationUnit().getBuffer().getContents()); 578 final ASTRewrite rewriter= ASTRewrite.create(body.getAST()); 579 final ITrackedNodePosition position= rewriter.track(body); 580 body.accept(new TypeVariableMapper(rewriter, mapping)); 581 rewriter.rewriteAST(document, getDeclaringType().getCompilationUnit().getJavaProject().getOptions(true)).apply(document, TextEdit.NONE); 582 String content= document.get(position.getStartPosition(), position.getLength()); 583 String [] lines= Strings.convertIntoLines(content); 584 Strings.trimIndentation(lines, method.getJavaProject(), false); 585 content= Strings.concatenate(lines, StubUtility.getLineDelimiterUsed(method)); 586 newMethod.setBody((Block) targetRewrite.createStringPlaceholder(content, ASTNode.BLOCK)); 587 } catch (MalformedTreeException exception) { 588 JavaPlugin.log(exception); 589 } catch (BadLocationException exception) { 590 JavaPlugin.log(exception); 591 } 592 } 593 594 private void copyMembers(Collection adjustors, Map adjustments, Map rewrites, RefactoringStatus status, MemberActionInfo[] infos, IType[] destinations, CompilationUnitRewrite sourceRewriter, CompilationUnitRewrite unitRewriter, IProgressMonitor monitor) throws JavaModelException { 595 try { 596 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 1); 597 IType type= null; 598 TypeVariableMaplet[] mapping= null; 599 for (int index= 0; index < destinations.length; index++) { 600 type= destinations[index]; 601 mapping= TypeVariableUtil.superTypeToInheritedType(getDeclaringType(), type); 602 if (unitRewriter.getCu().equals(type.getCompilationUnit())) { 603 IMember member= null; 604 MemberVisibilityAdjustor adjustor= null; 605 AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(type, unitRewriter.getRoot()); 606 for (int offset= infos.length - 1; offset >= 0; offset--) { 607 member= infos[offset].getMember(); 608 adjustor= new MemberVisibilityAdjustor(type, member); 609 if (infos[offset].isNewMethodToBeDeclaredAbstract()) 610 adjustor.setIncoming(false); 611 adjustor.setRewrite(sourceRewriter.getASTRewrite(), sourceRewriter.getRoot()); 612 adjustor.setRewrites(rewrites); 613 614 adjustor.setFailureSeverity(RefactoringStatus.WARNING); 616 617 adjustor.setStatus(status); 618 adjustor.setAdjustments(adjustments); 619 adjustor.adjustVisibility(new SubProgressMonitor(monitor, 1)); 620 adjustments.remove(member); 621 adjustors.add(adjustor); 622 status.merge(checkProjectCompliance(getCompilationUnitRewrite(rewrites, getDeclaringType().getCompilationUnit()), type, new IMember[] {infos[offset].getMember()})); 623 if (infos[offset].isFieldInfo()) { 624 final VariableDeclarationFragment oldField= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) infos[offset].getMember(), sourceRewriter.getRoot()); 625 if (oldField != null) { 626 FieldDeclaration newField= createNewFieldDeclarationNode(infos[offset], sourceRewriter.getRoot(), mapping, unitRewriter.getASTRewrite(), oldField); 627 unitRewriter.getASTRewrite().getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertAt(newField, ASTNodes.getInsertionIndex(newField, declaration.bodyDeclarations()), unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_add_member, SET_PUSH_DOWN)); 628 ImportRewriteUtil.addImports(unitRewriter, oldField.getParent(), new HashMap (), new HashMap (), false); 629 } 630 } else { 631 final MethodDeclaration oldMethod= ASTNodeSearchUtil.getMethodDeclarationNode((IMethod) infos[offset].getMember(), sourceRewriter.getRoot()); 632 if (oldMethod != null) { 633 MethodDeclaration newMethod= createNewMethodDeclarationNode(infos[offset], sourceRewriter.getRoot(), mapping, unitRewriter, oldMethod); 634 unitRewriter.getASTRewrite().getListRewrite(declaration, declaration.getBodyDeclarationsProperty()).insertAt(newMethod, ASTNodes.getInsertionIndex(newMethod, declaration.bodyDeclarations()), unitRewriter.createCategorizedGroupDescription(RefactoringCoreMessages.HierarchyRefactoring_add_member, SET_PUSH_DOWN)); 635 ImportRewriteUtil.addImports(unitRewriter, oldMethod, new HashMap (), new HashMap (), false); 636 } 637 } 638 } 639 } 640 } 641 } finally { 642 monitor.done(); 643 } 644 } 645 646 649 public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { 650 try { 651 final Map arguments= new HashMap (); 652 String project= null; 653 final IType declaring= getDeclaringType(); 654 final IJavaProject javaProject= declaring.getJavaProject(); 655 if (javaProject != null) 656 project= javaProject.getElementName(); 657 int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE; 658 try { 659 if (declaring.isLocal() || declaring.isAnonymous()) 660 flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; 661 } catch (JavaModelException exception) { 662 JavaPlugin.log(exception); 663 } 664 final String description= fMembersToMove.length == 1 ? Messages.format(RefactoringCoreMessages.PushDownRefactoring_descriptor_description_short_multi, fMembersToMove[0].getElementName()) : RefactoringCoreMessages.PushDownRefactoring_descriptor_description_short; 665 final String header= fMembersToMove.length == 1 ? Messages.format(RefactoringCoreMessages.PushDownRefactoring_descriptor_description_full, new String [] { JavaElementLabels.getElementLabel(fMembersToMove[0], JavaElementLabels.ALL_FULLY_QUALIFIED), JavaElementLabels.getElementLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED) }) : Messages.format(RefactoringCoreMessages.PushDownRefactoring_descriptor_description, new String [] { JavaElementLabels.getElementLabel(declaring, JavaElementLabels.ALL_FULLY_QUALIFIED) }); 666 final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); 667 final String [] settings= new String [fMembersToMove.length]; 668 for (int index= 0; index < settings.length; index++) 669 settings[index]= JavaElementLabels.getElementLabel(fMembersToMove[index], JavaElementLabels.ALL_FULLY_QUALIFIED); 670 comment.addSetting(JDTRefactoringDescriptorComment.createCompositeSetting(RefactoringCoreMessages.PushDownRefactoring_pushed_members_pattern, settings)); 671 addSuperTypeSettings(comment, true); 672 final JDTRefactoringDescriptor descriptor= new JDTRefactoringDescriptor(IJavaRefactorings.PUSH_DOWN, project, description, comment.asString(), arguments, flags); 673 if (fCachedDeclaringType != null) 674 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_INPUT, descriptor.elementToHandle(fCachedDeclaringType)); 675 for (int index= 0; index < fMembersToMove.length; index++) { 676 arguments.put(JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + (index + 1), descriptor.elementToHandle(fMembersToMove[index])); 677 for (int offset= 0; offset < fMemberInfos.length; offset++) { 678 if (fMemberInfos[offset].getMember().equals(fMembersToMove[index])) { 679 switch (fMemberInfos[offset].getAction()) { 680 case MemberActionInfo.PUSH_ABSTRACT_ACTION: 681 arguments.put(ATTRIBUTE_ABSTRACT + (index + 1), Boolean.valueOf(true).toString()); 682 break; 683 case MemberActionInfo.PUSH_DOWN_ACTION: 684 arguments.put(ATTRIBUTE_PUSH + (index + 1), Boolean.valueOf(true).toString()); 685 break; 686 } 687 } 688 } 689 } 690 return new DynamicValidationRefactoringChange(descriptor, RefactoringCoreMessages.PushDownRefactoring_change_name, fChangeManager.getAllChanges()); 691 } finally { 692 pm.done(); 693 clearCaches(); 694 } 695 } 696 697 private TextEditBasedChangeManager createChangeManager(final IProgressMonitor monitor, final RefactoringStatus status) throws CoreException { 698 Assert.isNotNull(monitor); 699 Assert.isNotNull(status); 700 try { 701 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, 7); 702 final ICompilationUnit source= getDeclaringType().getCompilationUnit(); 703 final CompilationUnitRewrite sourceRewriter= new CompilationUnitRewrite(source); 704 final Map rewrites= new HashMap (2); 705 rewrites.put(source, sourceRewriter); 706 IType[] types= getHierarchyOfDeclaringClass(new SubProgressMonitor(monitor, 1)).getSubclasses(getDeclaringType()); 707 final Set result= new HashSet (types.length + 1); 708 for (int index= 0; index < types.length; index++) 709 result.add(types[index].getCompilationUnit()); 710 result.add(source); 711 final Map adjustments= new HashMap (); 712 final List adjustors= new ArrayList (); 713 final ICompilationUnit[] units= (ICompilationUnit[]) result.toArray(new ICompilationUnit[result.size()]); 714 ICompilationUnit unit= null; 715 CompilationUnitRewrite rewrite= null; 716 final IProgressMonitor sub= new SubProgressMonitor(monitor, 4); 717 try { 718 sub.beginTask(RefactoringCoreMessages.PushDownRefactoring_checking, units.length * 4); 719 for (int index= 0; index < units.length; index++) { 720 unit= units[index]; 721 rewrite= getCompilationUnitRewrite(rewrites, unit); 722 if (unit.equals(sourceRewriter.getCu())) { 723 final AbstractTypeDeclaration declaration= ASTNodeSearchUtil.getAbstractTypeDeclarationNode(getDeclaringType(), rewrite.getRoot()); 724 if (!JdtFlags.isAbstract(getDeclaringType()) && getAbstractDeclarationInfos().length != 0) 725 ModifierRewrite.create(rewrite.getASTRewrite(), declaration).setModifiers((Modifier.ABSTRACT | declaration.getModifiers()), rewrite.createCategorizedGroupDescription(RefactoringCoreMessages.PushDownRefactoring_make_abstract, SET_PUSH_DOWN)); 726 deleteDeclarationNodes(sourceRewriter, false, rewrite, Arrays.asList(getDeletableMembers()), SET_PUSH_DOWN); 727 MemberActionInfo[] methods= getAbstractDeclarationInfos(); 728 for (int offset= 0; offset < methods.length; offset++) 729 declareMethodAbstract(methods[offset], sourceRewriter, rewrite); 730 } 731 final IMember[] members= getAbstractMembers(getAbstractDestinations(new SubProgressMonitor(monitor, 1))); 732 final IType[] classes= new IType[members.length]; 733 for (int offset= 0; offset < members.length; offset++) 734 classes[offset]= (IType) members[offset]; 735 copyMembers(adjustors, adjustments, rewrites, status, getAbstractMemberInfos(), classes, sourceRewriter, rewrite, sub); 736 copyMembers(adjustors, adjustments, rewrites, status, getEffectedMemberInfos(), getAbstractDestinations(new SubProgressMonitor(monitor, 1)), sourceRewriter, rewrite, sub); 737 if (monitor.isCanceled()) 738 throw new OperationCanceledException(); 739 } 740 } finally { 741 sub.done(); 742 } 743 if (!adjustors.isEmpty() && !adjustments.isEmpty()) { 744 final MemberVisibilityAdjustor adjustor= (MemberVisibilityAdjustor) adjustors.get(0); 745 adjustor.rewriteVisibility(new SubProgressMonitor(monitor, 1)); 746 } 747 final TextEditBasedChangeManager manager= new TextEditBasedChangeManager(); 748 for (final Iterator iterator= rewrites.keySet().iterator(); iterator.hasNext();) { 749 unit= (ICompilationUnit) iterator.next(); 750 rewrite= (CompilationUnitRewrite) rewrites.get(unit); 751 if (rewrite != null) 752 manager.manage(unit, rewrite.createChange()); 753 } 754 return manager; 755 } finally { 756 monitor.done(); 757 } 758 } 759 760 private FieldDeclaration createNewFieldDeclarationNode(MemberActionInfo info, CompilationUnit declaringCuNode, TypeVariableMaplet[] mapping, ASTRewrite rewrite, VariableDeclarationFragment oldFieldFragment) throws JavaModelException { 761 Assert.isTrue(info.isFieldInfo()); 762 IField field= (IField) info.getMember(); 763 AST ast= rewrite.getAST(); 764 VariableDeclarationFragment newFragment= ast.newVariableDeclarationFragment(); 765 newFragment.setExtraDimensions(oldFieldFragment.getExtraDimensions()); 766 Expression initializer= oldFieldFragment.getInitializer(); 767 if (initializer != null) { 768 Expression newInitializer= null; 769 if (mapping.length > 0) 770 newInitializer= createPlaceholderForExpression(initializer, field.getCompilationUnit(), mapping, rewrite); 771 else 772 newInitializer= createPlaceholderForExpression(initializer, field.getCompilationUnit(), rewrite); 773 newFragment.setInitializer(newInitializer); 774 } 775 newFragment.setName(ast.newSimpleName(oldFieldFragment.getName().getIdentifier())); 776 FieldDeclaration newField= ast.newFieldDeclaration(newFragment); 777 FieldDeclaration oldField= ASTNodeSearchUtil.getFieldDeclarationNode(field, declaringCuNode); 778 if (info.copyJavadocToCopiesInSubclasses()) 779 copyJavadocNode(rewrite, field, oldField, newField); 780 copyAnnotations(oldField, newField); 781 newField.modifiers().addAll(ASTNodeFactory.newModifiers(ast, info.getNewModifiersForCopyInSubclass(oldField.getModifiers()))); 782 Type oldType= oldField.getType(); 783 ICompilationUnit cu= field.getCompilationUnit(); 784 Type newType= null; 785 if (mapping.length > 0) { 786 newType= createPlaceholderForType(oldType, cu, mapping, rewrite); 787 } else 788 newType= createPlaceholderForType(oldType, cu, rewrite); 789 newField.setType(newType); 790 return newField; 791 } 792 793 private MethodDeclaration createNewMethodDeclarationNode(MemberActionInfo info, CompilationUnit declaringCuNode, TypeVariableMaplet[] mapping, CompilationUnitRewrite rewriter, MethodDeclaration oldMethod) throws JavaModelException { 794 Assert.isTrue(!info.isFieldInfo()); 795 IMethod method= (IMethod) info.getMember(); 796 ASTRewrite rewrite= rewriter.getASTRewrite(); 797 AST ast= rewrite.getAST(); 798 MethodDeclaration newMethod= ast.newMethodDeclaration(); 799 copyBodyOfPushedDownMethod(rewrite, method, oldMethod, newMethod, mapping); 800 newMethod.setConstructor(oldMethod.isConstructor()); 801 newMethod.setExtraDimensions(oldMethod.getExtraDimensions()); 802 if (info.copyJavadocToCopiesInSubclasses()) 803 copyJavadocNode(rewrite, method, oldMethod, newMethod); 804 final IJavaProject project= rewriter.getCu().getJavaProject(); 805 if (info.isNewMethodToBeDeclaredAbstract() && JavaModelUtil.is50OrHigher(project) && JavaPreferencesSettings.getCodeGenerationSettings(project).overrideAnnotation) { 806 final MarkerAnnotation annotation= ast.newMarkerAnnotation(); 807 annotation.setTypeName(ast.newSimpleName("Override")); newMethod.modifiers().add(annotation); 809 } 810 copyAnnotations(oldMethod, newMethod); 811 newMethod.modifiers().addAll(ASTNodeFactory.newModifiers(ast, info.getNewModifiersForCopyInSubclass(oldMethod.getModifiers()))); 812 newMethod.setName(ast.newSimpleName(oldMethod.getName().getIdentifier())); 813 copyReturnType(rewrite, method.getCompilationUnit(), oldMethod, newMethod, mapping); 814 copyParameters(rewrite, method.getCompilationUnit(), oldMethod, newMethod, mapping); 815 copyThrownExceptions(oldMethod, newMethod); 816 copyTypeParameters(oldMethod, newMethod); 817 return newMethod; 818 } 819 820 private void declareMethodAbstract(MemberActionInfo info, CompilationUnitRewrite sourceRewrite, CompilationUnitRewrite unitRewrite) throws JavaModelException { 821 Assert.isTrue(!info.isFieldInfo()); 822 IMethod method= (IMethod) info.getMember(); 823 if (JdtFlags.isAbstract(method)) 824 return; 825 final MethodDeclaration declaration= ASTNodeSearchUtil.getMethodDeclarationNode(method, sourceRewrite.getRoot()); 826 unitRewrite.getASTRewrite().remove(declaration.getBody(), null); 827 sourceRewrite.getImportRemover().registerRemovedNode(declaration.getBody()); 828 ModifierRewrite.create(unitRewrite.getASTRewrite(), declaration).setModifiers(info.getNewModifiersForOriginal(declaration.getModifiers()), null); 829 } 830 831 private MemberActionInfo[] getAbstractDeclarationInfos() throws JavaModelException { 832 List result= new ArrayList (fMemberInfos.length); 833 for (int index= 0; index < fMemberInfos.length; index++) { 834 MemberActionInfo info= fMemberInfos[index]; 835 if (info.isNewMethodToBeDeclaredAbstract()) 836 result.add(info); 837 } 838 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 839 } 840 841 private IType[] getAbstractDestinations(IProgressMonitor monitor) throws JavaModelException { 842 IType[] allDirectSubclasses= getHierarchyOfDeclaringClass(monitor).getSubclasses(getDeclaringType()); 843 List result= new ArrayList (allDirectSubclasses.length); 844 for (int index= 0; index < allDirectSubclasses.length; index++) { 845 IType subclass= allDirectSubclasses[index]; 846 if (subclass.exists() && !subclass.isBinary() && !subclass.isReadOnly() && subclass.getCompilationUnit() != null && subclass.isStructureKnown()) 847 result.add(subclass); 848 } 849 return (IType[]) result.toArray(new IType[result.size()]); 850 } 851 852 private MemberActionInfo[] getAbstractMemberInfos() throws JavaModelException { 853 List result= new ArrayList (fMemberInfos.length); 854 for (int index= 0; index < fMemberInfos.length; index++) { 855 MemberActionInfo info= fMemberInfos[index]; 856 if (info.isToBeCreatedInSubclassesOfDeclaringClass() && JdtFlags.isAbstract(info.getMember())) 857 result.add(info); 858 } 859 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 860 } 861 862 public IMember[] getAdditionalRequiredMembers(IProgressMonitor monitor) throws JavaModelException { 863 IMember[] members= MemberActionInfo.getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()); 864 monitor.beginTask(RefactoringCoreMessages.PushDownRefactoring_calculating_required, members.length); List queue= new ArrayList (members.length); 874 queue.addAll(Arrays.asList(members)); 875 if (queue.isEmpty()) 876 return new IMember[0]; 877 int i= 0; 878 IMember current; 879 do { 880 current= (IMember) queue.get(i); 881 addAllRequiredPushableMembers(queue, current, new SubProgressMonitor(monitor, 1)); 882 i++; 883 if (queue.size() == i) 884 current= null; 885 } while (current != null); 886 queue.removeAll(Arrays.asList(members)); return (IMember[]) queue.toArray(new IMember[queue.size()]); 888 } 889 890 private IMember[] getDeletableMembers() { 891 List result= new ArrayList (fMemberInfos.length); 892 for (int i= 0; i < fMemberInfos.length; i++) { 893 MemberActionInfo info= fMemberInfos[i]; 894 if (info.isToBeDeletedFromDeclaringClass()) 895 result.add(info.getMember()); 896 } 897 return (IMember[]) result.toArray(new IMember[result.size()]); 898 } 899 900 private MemberActionInfo[] getEffectedMemberInfos() throws JavaModelException { 901 List result= new ArrayList (fMemberInfos.length); 902 for (int i= 0; i < fMemberInfos.length; i++) { 903 MemberActionInfo info= fMemberInfos[i]; 904 if (info.isToBeCreatedInSubclassesOfDeclaringClass() && !JdtFlags.isAbstract(info.getMember())) 905 result.add(info); 906 } 907 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 908 } 909 910 913 public Object [] getElements() { 914 return fMembersToMove; 915 } 916 917 private ITypeHierarchy getHierarchyOfDeclaringClass(IProgressMonitor monitor) throws JavaModelException { 918 try { 919 if (fCachedClassHierarchy != null) 920 return fCachedClassHierarchy; 921 fCachedClassHierarchy= getDeclaringType().newTypeHierarchy(monitor); 922 return fCachedClassHierarchy; 923 } finally { 924 monitor.done(); 925 } 926 } 927 928 931 public String getIdentifier() { 932 return IDENTIFIER; 933 } 934 935 private MemberActionInfo[] getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass() throws JavaModelException { 936 MemberActionInfo[] abs= getAbstractMemberInfos(); 937 MemberActionInfo[] nonabs= getEffectedMemberInfos(); 938 List result= new ArrayList (abs.length + nonabs.length); 939 result.addAll(Arrays.asList(abs)); 940 result.addAll(Arrays.asList(nonabs)); 941 return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]); 942 } 943 944 public MemberActionInfo[] getMemberActionInfos() { 945 return fMemberInfos; 946 } 947 948 951 public String getProcessorName() { 952 return RefactoringCoreMessages.PushDownRefactoring_name; 953 } 954 955 958 public RefactoringStatus initialize(RefactoringArguments arguments) { 959 if (arguments instanceof JavaRefactoringArguments) { 960 final JavaRefactoringArguments extended= (JavaRefactoringArguments) arguments; 961 String handle= extended.getAttribute(JDTRefactoringDescriptor.ATTRIBUTE_INPUT); 962 if (handle != null) { 963 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 964 if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE) 965 return ScriptableRefactoring.createInputFatalStatus(element, getRefactoring().getName(), IJavaRefactorings.PUSH_DOWN); 966 else 967 fCachedDeclaringType= (IType) element; 968 } 969 int count= 1; 970 final List elements= new ArrayList (); 971 final List infos= new ArrayList (); 972 String attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + count; 973 final RefactoringStatus status= new RefactoringStatus(); 974 while ((handle= extended.getAttribute(attribute)) != null) { 975 final IJavaElement element= JDTRefactoringDescriptor.handleToElement(extended.getProject(), handle, false); 976 if (element == null || !element.exists()) 977 status.merge(ScriptableRefactoring.createInputWarningStatus(element, getRefactoring().getName(), IJavaRefactorings.PUSH_DOWN)); 978 else 979 elements.add(element); 980 if (extended.getAttribute(ATTRIBUTE_ABSTRACT + count) != null) 981 infos.add(MemberActionInfo.create((IMember) element, MemberActionInfo.PUSH_ABSTRACT_ACTION)); 982 else if (extended.getAttribute(ATTRIBUTE_PUSH + count) != null) 983 infos.add(MemberActionInfo.create((IMember) element, MemberActionInfo.PUSH_DOWN_ACTION)); 984 else 985 infos.add(MemberActionInfo.create((IMember) element, MemberActionInfo.NO_ACTION)); 986 count++; 987 attribute= JDTRefactoringDescriptor.ATTRIBUTE_ELEMENT + count; 988 } 989 fMembersToMove= (IMember[]) elements.toArray(new IMember[elements.size()]); 990 fMemberInfos= (MemberActionInfo[]) infos.toArray(new MemberActionInfo[infos.size()]); 991 if (!status.isOK()) 992 return status; 993 } else 994 return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments); 995 return new RefactoringStatus(); 996 } 997 998 1001 public boolean isApplicable() throws CoreException { 1002 return RefactoringAvailabilityTester.isPushDownAvailable(fMembersToMove); 1003 } 1004 1005 1008 protected void rewriteTypeOccurrences(final TextEditBasedChangeManager manager, final ASTRequestor requestor, final CompilationUnitRewrite rewrite, final ICompilationUnit unit, final CompilationUnit node, final Set replacements, final IProgressMonitor monitor) throws CoreException { 1009 } 1011} | Popular Tags |