0001: /*******************************************************************************
0002: * Copyright (c) 2006, 2007 IBM Corporation and others.
0003: * All rights reserved. This program and the accompanying materials
0004: * are made available under the terms of the Eclipse Public License v1.0
0005: * which accompanies this distribution, and is available at
0006: * http://www.eclipse.org/legal/epl-v10.html
0007: *
0008: * Contributors:
0009: * IBM Corporation - initial API and implementation
0010: *******************************************************************************/package org.eclipse.jdt.internal.corext.refactoring.structure;
0011:
0012: import java.util.ArrayList;
0013: import java.util.Arrays;
0014: import java.util.Collection;
0015: import java.util.HashMap;
0016: import java.util.HashSet;
0017: import java.util.Iterator;
0018: import java.util.List;
0019: import java.util.Map;
0020: import java.util.Set;
0021:
0022: import org.eclipse.text.edits.MalformedTreeException;
0023: import org.eclipse.text.edits.TextEdit;
0024:
0025: import org.eclipse.core.runtime.Assert;
0026: import org.eclipse.core.runtime.CoreException;
0027: import org.eclipse.core.runtime.IProgressMonitor;
0028: import org.eclipse.core.runtime.OperationCanceledException;
0029: import org.eclipse.core.runtime.SubProgressMonitor;
0030:
0031: import org.eclipse.jface.text.BadLocationException;
0032: import org.eclipse.jface.text.Document;
0033: import org.eclipse.jface.text.IDocument;
0034:
0035: import org.eclipse.ltk.core.refactoring.Change;
0036: import org.eclipse.ltk.core.refactoring.GroupCategory;
0037: import org.eclipse.ltk.core.refactoring.GroupCategorySet;
0038: import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
0039: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0040: import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
0041: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
0042:
0043: import org.eclipse.jdt.core.Flags;
0044: import org.eclipse.jdt.core.ICompilationUnit;
0045: import org.eclipse.jdt.core.IField;
0046: import org.eclipse.jdt.core.IJavaElement;
0047: import org.eclipse.jdt.core.IJavaProject;
0048: import org.eclipse.jdt.core.IMember;
0049: import org.eclipse.jdt.core.IMethod;
0050: import org.eclipse.jdt.core.IType;
0051: import org.eclipse.jdt.core.ITypeHierarchy;
0052: import org.eclipse.jdt.core.JavaModelException;
0053: import org.eclipse.jdt.core.dom.AST;
0054: import org.eclipse.jdt.core.dom.ASTNode;
0055: import org.eclipse.jdt.core.dom.ASTRequestor;
0056: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
0057: import org.eclipse.jdt.core.dom.Block;
0058: import org.eclipse.jdt.core.dom.CompilationUnit;
0059: import org.eclipse.jdt.core.dom.Expression;
0060: import org.eclipse.jdt.core.dom.FieldDeclaration;
0061: import org.eclipse.jdt.core.dom.MarkerAnnotation;
0062: import org.eclipse.jdt.core.dom.MethodDeclaration;
0063: import org.eclipse.jdt.core.dom.Modifier;
0064: import org.eclipse.jdt.core.dom.Type;
0065: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
0066: import org.eclipse.jdt.core.dom.rewrite.ASTRewrite;
0067: import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
0068: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
0069: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
0070: import org.eclipse.jdt.core.refactoring.descriptors.PushDownDescriptor;
0071: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0072: import org.eclipse.jdt.core.search.SearchEngine;
0073: import org.eclipse.jdt.core.search.SearchMatch;
0074: import org.eclipse.jdt.core.search.SearchPattern;
0075:
0076: import org.eclipse.jdt.internal.corext.codemanipulation.StubUtility;
0077: import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
0078: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
0079: import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
0080: import org.eclipse.jdt.internal.corext.refactoring.Checks;
0081: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
0082: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
0083: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
0084: import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
0085: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0086: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
0087: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0088: import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
0089: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
0090: import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
0091: import org.eclipse.jdt.internal.corext.refactoring.rename.MethodChecks;
0092: import org.eclipse.jdt.internal.corext.refactoring.util.ResourceUtil;
0093: import org.eclipse.jdt.internal.corext.refactoring.util.TextEditBasedChangeManager;
0094: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0095: import org.eclipse.jdt.internal.corext.util.JdtFlags;
0096: import org.eclipse.jdt.internal.corext.util.Messages;
0097: import org.eclipse.jdt.internal.corext.util.SearchUtils;
0098: import org.eclipse.jdt.internal.corext.util.Strings;
0099:
0100: import org.eclipse.jdt.ui.JavaElementLabels;
0101:
0102: import org.eclipse.jdt.internal.ui.JavaPlugin;
0103: import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
0104:
0105: /**
0106: * Refactoring processor for the push down refactoring.
0107: *
0108: * @since 3.2
0109: */
0110: public final class PushDownRefactoringProcessor extends
0111: HierarchyProcessor {
0112:
0113: public static class MemberActionInfo implements IMemberActionInfo {
0114:
0115: public static final int NO_ACTION = 2;
0116:
0117: public static final int PUSH_ABSTRACT_ACTION = 1;
0118:
0119: public static final int PUSH_DOWN_ACTION = 0;
0120:
0121: private static void assertValidAction(IMember member, int action) {
0122: if (member instanceof IMethod)
0123: Assert.isTrue(action == PUSH_ABSTRACT_ACTION
0124: || action == NO_ACTION
0125: || action == PUSH_DOWN_ACTION);
0126: else if (member instanceof IField)
0127: Assert.isTrue(action == NO_ACTION
0128: || action == PUSH_DOWN_ACTION);
0129: }
0130:
0131: public static MemberActionInfo create(IMember member, int action) {
0132: return new MemberActionInfo(member, action);
0133: }
0134:
0135: static IMember[] getMembers(MemberActionInfo[] infos) {
0136: IMember[] result = new IMember[infos.length];
0137: for (int i = 0; i < result.length; i++) {
0138: result[i] = infos[i].getMember();
0139: }
0140: return result;
0141: }
0142:
0143: private int fAction;
0144:
0145: private final IMember fMember;
0146:
0147: private MemberActionInfo(IMember member, int action) {
0148: assertValidAction(member, action);
0149: Assert.isTrue(member instanceof IField
0150: || member instanceof IMethod);
0151: fMember = member;
0152: fAction = action;
0153: }
0154:
0155: boolean copyJavadocToCopiesInSubclasses() {
0156: return isToBeDeletedFromDeclaringClass();
0157: }
0158:
0159: public int getAction() {
0160: return fAction;
0161: }
0162:
0163: public int[] getAvailableActions() {
0164: if (isFieldInfo())
0165: return new int[] { PUSH_DOWN_ACTION, NO_ACTION };
0166:
0167: return new int[] { PUSH_DOWN_ACTION, PUSH_ABSTRACT_ACTION,
0168: NO_ACTION };
0169: }
0170:
0171: public IMember getMember() {
0172: return fMember;
0173: }
0174:
0175: int getNewModifiersForCopyInSubclass(int oldModifiers)
0176: throws JavaModelException {
0177: if (isFieldInfo())
0178: return oldModifiers;
0179: if (isToBeDeletedFromDeclaringClass())
0180: return oldModifiers;
0181: int modifiers = oldModifiers;
0182: if (isNewMethodToBeDeclaredAbstract()) {
0183: if (!JdtFlags.isPublic(fMember))
0184: modifiers = Modifier.PROTECTED
0185: | JdtFlags.clearAccessModifiers(modifiers);
0186: }
0187: return modifiers;
0188: }
0189:
0190: int getNewModifiersForOriginal(int oldModifiers)
0191: throws JavaModelException {
0192: if (isFieldInfo())
0193: return oldModifiers;
0194: if (isToBeDeletedFromDeclaringClass())
0195: return oldModifiers;
0196: int modifiers = oldModifiers;
0197: if (isNewMethodToBeDeclaredAbstract()) {
0198: modifiers = JdtFlags.clearFlag(Modifier.FINAL
0199: | Modifier.NATIVE, oldModifiers);
0200: modifiers |= Modifier.ABSTRACT;
0201:
0202: if (!JdtFlags.isPublic(fMember))
0203: modifiers = Modifier.PROTECTED
0204: | JdtFlags.clearAccessModifiers(modifiers);
0205: }
0206: return modifiers;
0207: }
0208:
0209: public boolean isActive() {
0210: return getAction() != NO_ACTION;
0211: }
0212:
0213: public boolean isEditable() {
0214: if (isFieldInfo())
0215: return false;
0216: if (getAction() == MemberActionInfo.NO_ACTION)
0217: return false;
0218: return true;
0219: }
0220:
0221: boolean isFieldInfo() {
0222: return fMember instanceof IField;
0223: }
0224:
0225: boolean isNewMethodToBeDeclaredAbstract()
0226: throws JavaModelException {
0227: return !isFieldInfo() && !JdtFlags.isAbstract(fMember)
0228: && fAction == PUSH_ABSTRACT_ACTION;
0229: }
0230:
0231: boolean isToBeCreatedInSubclassesOfDeclaringClass() {
0232: return fAction != NO_ACTION;
0233: }
0234:
0235: boolean isToBeDeletedFromDeclaringClass() {
0236: return isToBePushedDown();
0237: }
0238:
0239: public boolean isToBePushedDown() {
0240: return fAction == PUSH_DOWN_ACTION;
0241: }
0242:
0243: public void setAction(int action) {
0244: assertValidAction(fMember, action);
0245: if (isFieldInfo())
0246: Assert.isTrue(action != PUSH_ABSTRACT_ACTION);
0247: fAction = action;
0248: }
0249:
0250: }
0251:
0252: private static final String ATTRIBUTE_ABSTRACT = "abstract"; //$NON-NLS-1$
0253:
0254: private static final String ATTRIBUTE_PUSH = "push"; //$NON-NLS-1$
0255:
0256: /** The identifier of this processor */
0257: public static final String IDENTIFIER = "org.eclipse.jdt.ui.pushDownProcessor"; //$NON-NLS-1$
0258:
0259: /** The push down group category set */
0260: private static final GroupCategorySet SET_PUSH_DOWN = new GroupCategorySet(
0261: new GroupCategory(
0262: "org.eclipse.jdt.internal.corext.pushDown", //$NON-NLS-1$
0263: RefactoringCoreMessages.PushDownRefactoring_category_name,
0264: RefactoringCoreMessages.PushDownRefactoring_category_description));
0265:
0266: private static MemberActionInfo[] createInfosForAllPushableFieldsAndMethods(
0267: IType type) throws JavaModelException {
0268: List result = new ArrayList();
0269: IMember[] pushableMembers = RefactoringAvailabilityTester
0270: .getPushDownMembers(type);
0271: for (int i = 0; i < pushableMembers.length; i++) {
0272: result.add(MemberActionInfo.create(pushableMembers[i],
0273: MemberActionInfo.NO_ACTION));
0274: }
0275: return (MemberActionInfo[]) result
0276: .toArray(new MemberActionInfo[result.size()]);
0277: }
0278:
0279: private static IMember[] getAbstractMembers(IMember[] members)
0280: throws JavaModelException {
0281: List result = new ArrayList(members.length);
0282: for (int i = 0; i < members.length; i++) {
0283: IMember member = members[i];
0284: if (JdtFlags.isAbstract(member))
0285: result.add(member);
0286: }
0287: return (IMember[]) result.toArray(new IMember[result.size()]);
0288: }
0289:
0290: private static CompilationUnitRewrite getCompilationUnitRewrite(
0291: final Map rewrites, final ICompilationUnit unit) {
0292: Assert.isNotNull(rewrites);
0293: Assert.isNotNull(unit);
0294: CompilationUnitRewrite rewrite = (CompilationUnitRewrite) rewrites
0295: .get(unit);
0296: if (rewrite == null) {
0297: rewrite = new CompilationUnitRewrite(unit);
0298: rewrites.put(unit, rewrite);
0299: }
0300: return rewrite;
0301: }
0302:
0303: private static IJavaElement[] getReferencingElementsFromSameClass(
0304: IMember member, IProgressMonitor pm,
0305: RefactoringStatus status) throws JavaModelException {
0306: Assert.isNotNull(member);
0307: final RefactoringSearchEngine2 engine = new RefactoringSearchEngine2(
0308: SearchPattern.createPattern(member,
0309: IJavaSearchConstants.REFERENCES,
0310: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
0311: engine.setFiltering(true, true);
0312: engine.setScope(SearchEngine
0313: .createJavaSearchScope(new IJavaElement[] { member
0314: .getDeclaringType() }));
0315: engine.setStatus(status);
0316: engine.searchPattern(new SubProgressMonitor(pm, 1));
0317: SearchResultGroup[] groups = (SearchResultGroup[]) engine
0318: .getResults();
0319: Set result = new HashSet(3);
0320: for (int i = 0; i < groups.length; i++) {
0321: SearchResultGroup group = groups[i];
0322: SearchMatch[] results = group.getSearchResults();
0323: for (int j = 0; j < results.length; j++) {
0324: SearchMatch searchResult = results[i];
0325: result.add(SearchUtils
0326: .getEnclosingJavaElement(searchResult));
0327: }
0328: }
0329: return (IJavaElement[]) result.toArray(new IJavaElement[result
0330: .size()]);
0331: }
0332:
0333: private ITypeHierarchy fCachedClassHierarchy;
0334:
0335: private MemberActionInfo[] fMemberInfos;
0336:
0337: /**
0338: * Creates a new push down refactoring processor.
0339: *
0340: * @param members
0341: * the members to pull up, or <code>null</code> if invoked by
0342: * scripting
0343: */
0344: public PushDownRefactoringProcessor(IMember[] members) {
0345: super (members, null, false);
0346: if (members != null) {
0347: final IType type = RefactoringAvailabilityTester
0348: .getTopLevelType(members);
0349: try {
0350: if (type != null
0351: && RefactoringAvailabilityTester
0352: .getPushDownMembers(type).length != 0) {
0353: fMembersToMove = new IMember[0];
0354: fCachedDeclaringType = type;
0355: }
0356: } catch (JavaModelException exception) {
0357: JavaPlugin.log(exception);
0358: }
0359: }
0360: }
0361:
0362: private void addAllRequiredPushableMembers(List queue,
0363: IMember member, IProgressMonitor monitor)
0364: throws JavaModelException {
0365: monitor
0366: .beginTask(
0367: RefactoringCoreMessages.PushDownRefactoring_calculating_required,
0368: 2);
0369: IProgressMonitor sub = new SubProgressMonitor(monitor, 1);
0370: sub
0371: .beginTask(
0372: RefactoringCoreMessages.PushDownRefactoring_calculating_required,
0373: 2);
0374: IMethod[] requiredMethods = ReferenceFinderUtil
0375: .getMethodsReferencedIn(new IJavaElement[] { member },
0376: new SubProgressMonitor(sub, 1));
0377: sub = new SubProgressMonitor(sub, 1);
0378: sub
0379: .beginTask(
0380: RefactoringCoreMessages.PushDownRefactoring_calculating_required,
0381: requiredMethods.length);
0382: for (int index = 0; index < requiredMethods.length; index++) {
0383: IMethod method = requiredMethods[index];
0384: if (!MethodChecks.isVirtual(method)
0385: && (method.getDeclaringType().equals(
0386: getDeclaringType())
0387: && !queue.contains(method) && RefactoringAvailabilityTester
0388: .isPushDownAvailable(method)))
0389: queue.add(method);
0390: }
0391: sub.done();
0392: IField[] requiredFields = ReferenceFinderUtil
0393: .getFieldsReferencedIn(new IJavaElement[] { member },
0394: new SubProgressMonitor(monitor, 1));
0395: for (int index = 0; index < requiredFields.length; index++) {
0396: IField field = requiredFields[index];
0397: if (field.getDeclaringType().equals(getDeclaringType())
0398: && !queue.contains(field)
0399: && RefactoringAvailabilityTester
0400: .isPushDownAvailable(field))
0401: queue.add(field);
0402: }
0403: monitor.done();
0404: }
0405:
0406: private RefactoringStatus checkAbstractMembersInDestinationClasses(
0407: IMember[] membersToPushDown,
0408: IType[] destinationClassesForAbstract)
0409: throws JavaModelException {
0410: RefactoringStatus result = new RefactoringStatus();
0411: IMember[] abstractMembersToPushDown = getAbstractMembers(membersToPushDown);
0412: for (int index = 0; index < destinationClassesForAbstract.length; index++) {
0413: result.merge(MemberCheckUtil.checkMembersInDestinationType(
0414: abstractMembersToPushDown,
0415: destinationClassesForAbstract[index]));
0416: }
0417: return result;
0418: }
0419:
0420: private RefactoringStatus checkAccessedFields(IType[] subclasses,
0421: IProgressMonitor pm) throws JavaModelException {
0422: RefactoringStatus result = new RefactoringStatus();
0423: IMember[] membersToPushDown = MemberActionInfo
0424: .getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
0425: List pushedDownList = Arrays.asList(membersToPushDown);
0426: IField[] accessedFields = ReferenceFinderUtil
0427: .getFieldsReferencedIn(membersToPushDown, pm);
0428: for (int i = 0; i < subclasses.length; i++) {
0429: IType targetClass = subclasses[i];
0430: ITypeHierarchy targetSupertypes = targetClass
0431: .newSupertypeHierarchy(null);
0432: for (int j = 0; j < accessedFields.length; j++) {
0433: IField field = accessedFields[j];
0434: boolean isAccessible = pushedDownList.contains(field)
0435: || canBeAccessedFrom(field, targetClass,
0436: targetSupertypes)
0437: || Flags.isEnum(field.getFlags());
0438: if (!isAccessible) {
0439: String message = Messages
0440: .format(
0441: RefactoringCoreMessages.PushDownRefactoring_field_not_accessible,
0442: new String[] {
0443: JavaElementLabels
0444: .getTextLabel(
0445: field,
0446: JavaElementLabels.ALL_FULLY_QUALIFIED),
0447: JavaElementLabels
0448: .getTextLabel(
0449: targetClass,
0450: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0451: result.addError(message, JavaStatusContext
0452: .create(field));
0453: }
0454: }
0455: }
0456: pm.done();
0457: return result;
0458: }
0459:
0460: private RefactoringStatus checkAccessedMethods(IType[] subclasses,
0461: IProgressMonitor pm) throws JavaModelException {
0462: RefactoringStatus result = new RefactoringStatus();
0463: IMember[] membersToPushDown = MemberActionInfo
0464: .getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
0465: List pushedDownList = Arrays.asList(membersToPushDown);
0466: IMethod[] accessedMethods = ReferenceFinderUtil
0467: .getMethodsReferencedIn(membersToPushDown, pm);
0468: for (int index = 0; index < subclasses.length; index++) {
0469: IType targetClass = subclasses[index];
0470: ITypeHierarchy targetSupertypes = targetClass
0471: .newSupertypeHierarchy(null);
0472: for (int offset = 0; offset < accessedMethods.length; offset++) {
0473: IMethod method = accessedMethods[offset];
0474: boolean isAccessible = pushedDownList.contains(method)
0475: || canBeAccessedFrom(method, targetClass,
0476: targetSupertypes);
0477: if (!isAccessible) {
0478: String message = Messages
0479: .format(
0480: RefactoringCoreMessages.PushDownRefactoring_method_not_accessible,
0481: new String[] {
0482: JavaElementLabels
0483: .getTextLabel(
0484: method,
0485: JavaElementLabels.ALL_FULLY_QUALIFIED),
0486: JavaElementLabels
0487: .getTextLabel(
0488: targetClass,
0489: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0490: result.addError(message, JavaStatusContext
0491: .create(method));
0492: }
0493: }
0494: }
0495: pm.done();
0496: return result;
0497: }
0498:
0499: private RefactoringStatus checkAccessedTypes(IType[] subclasses,
0500: IProgressMonitor pm) throws JavaModelException {
0501: RefactoringStatus result = new RefactoringStatus();
0502: IType[] accessedTypes = getTypesReferencedInMovedMembers(pm);
0503: for (int index = 0; index < subclasses.length; index++) {
0504: IType targetClass = subclasses[index];
0505: ITypeHierarchy targetSupertypes = targetClass
0506: .newSupertypeHierarchy(null);
0507: for (int offset = 0; offset < accessedTypes.length; offset++) {
0508: IType type = accessedTypes[offset];
0509: if (!canBeAccessedFrom(type, targetClass,
0510: targetSupertypes)) {
0511: String message = Messages
0512: .format(
0513: RefactoringCoreMessages.PushDownRefactoring_type_not_accessible,
0514: new String[] {
0515: JavaElementLabels
0516: .getTextLabel(
0517: type,
0518: JavaElementLabels.ALL_FULLY_QUALIFIED),
0519: JavaElementLabels
0520: .getTextLabel(
0521: targetClass,
0522: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0523: result.addError(message, JavaStatusContext
0524: .create(type));
0525: }
0526: }
0527: }
0528: pm.done();
0529: return result;
0530: }
0531:
0532: private RefactoringStatus checkElementsAccessedByModifiedMembers(
0533: IProgressMonitor pm) throws JavaModelException {
0534: RefactoringStatus result = new RefactoringStatus();
0535: pm
0536: .beginTask(
0537: RefactoringCoreMessages.PushDownRefactoring_check_references,
0538: 3);
0539: IType[] subclasses = getAbstractDestinations(new SubProgressMonitor(
0540: pm, 1));
0541: result.merge(checkAccessedTypes(subclasses,
0542: new SubProgressMonitor(pm, 1)));
0543: result.merge(checkAccessedFields(subclasses,
0544: new SubProgressMonitor(pm, 1)));
0545: result.merge(checkAccessedMethods(subclasses,
0546: new SubProgressMonitor(pm, 1)));
0547: pm.done();
0548: return result;
0549: }
0550:
0551: /**
0552: * {@inheritDoc}
0553: */
0554: public RefactoringStatus checkFinalConditions(
0555: IProgressMonitor monitor, CheckConditionsContext context)
0556: throws CoreException, OperationCanceledException {
0557: try {
0558: monitor
0559: .beginTask(
0560: RefactoringCoreMessages.PushDownRefactoring_checking,
0561: 5);
0562: clearCaches();
0563: ICompilationUnit unit = getDeclaringType()
0564: .getCompilationUnit();
0565: if (fLayer)
0566: unit = unit.findWorkingCopy(fOwner);
0567: resetWorkingCopies(unit);
0568: final RefactoringStatus result = new RefactoringStatus();
0569: result
0570: .merge(checkMembersInDestinationClasses(new SubProgressMonitor(
0571: monitor, 1)));
0572: result
0573: .merge(checkElementsAccessedByModifiedMembers(new SubProgressMonitor(
0574: monitor, 1)));
0575: result
0576: .merge(checkReferencesToPushedDownMembers(new SubProgressMonitor(
0577: monitor, 1)));
0578: if (!JdtFlags.isAbstract(getDeclaringType())
0579: && getAbstractDeclarationInfos().length != 0)
0580: result.merge(checkConstructorCalls(getDeclaringType(),
0581: new SubProgressMonitor(monitor, 1)));
0582: else
0583: monitor.worked(1);
0584: if (result.hasFatalError())
0585: return result;
0586: List members = new ArrayList(fMemberInfos.length);
0587: for (int index = 0; index < fMemberInfos.length; index++) {
0588: if (fMemberInfos[index].getAction() != MemberActionInfo.NO_ACTION)
0589: members.add(fMemberInfos[index].getMember());
0590: }
0591: fMembersToMove = (IMember[]) members
0592: .toArray(new IMember[members.size()]);
0593: fChangeManager = createChangeManager(
0594: new SubProgressMonitor(monitor, 1), result);
0595: if (result.hasFatalError())
0596: return result;
0597: result.merge(Checks.validateModifiesFiles(ResourceUtil
0598: .getFiles(fChangeManager.getAllCompilationUnits()),
0599: getRefactoring().getValidationContext()));
0600: return result;
0601: } finally {
0602: monitor.done();
0603: }
0604: }
0605:
0606: /**
0607: * {@inheritDoc}
0608: */
0609: public RefactoringStatus checkInitialConditions(
0610: IProgressMonitor monitor) throws CoreException,
0611: OperationCanceledException {
0612: try {
0613: monitor
0614: .beginTask(
0615: RefactoringCoreMessages.PushDownRefactoring_checking,
0616: 1);
0617: RefactoringStatus status = new RefactoringStatus();
0618: status
0619: .merge(checkPossibleSubclasses(new SubProgressMonitor(
0620: monitor, 1)));
0621: if (status.hasFatalError())
0622: return status;
0623: status.merge(checkDeclaringType(new SubProgressMonitor(
0624: monitor, 1)));
0625: if (status.hasFatalError())
0626: return status;
0627: status.merge(checkIfMembersExist());
0628: if (status.hasFatalError())
0629: return status;
0630: fMemberInfos = createInfosForAllPushableFieldsAndMethods(getDeclaringType());
0631: List list = Arrays.asList(fMembersToMove);
0632: for (int offset = 0; offset < fMemberInfos.length; offset++) {
0633: MemberActionInfo info = fMemberInfos[offset];
0634: if (list.contains(info.getMember()))
0635: info.setAction(MemberActionInfo.PUSH_DOWN_ACTION);
0636: }
0637: return status;
0638: } finally {
0639: monitor.done();
0640: }
0641: }
0642:
0643: private RefactoringStatus checkMembersInDestinationClasses(
0644: IProgressMonitor monitor) throws JavaModelException {
0645: monitor
0646: .beginTask(
0647: RefactoringCoreMessages.PushDownRefactoring_checking,
0648: 2);
0649: RefactoringStatus result = new RefactoringStatus();
0650: IMember[] membersToPushDown = MemberActionInfo
0651: .getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
0652:
0653: IType[] destinationClassesForNonAbstract = getAbstractDestinations(new SubProgressMonitor(
0654: monitor, 1));
0655: result.merge(checkNonAbstractMembersInDestinationClasses(
0656: membersToPushDown, destinationClassesForNonAbstract));
0657: List list = Arrays
0658: .asList(getAbstractMembers(getAbstractDestinations(new SubProgressMonitor(
0659: monitor, 1))));
0660:
0661: IType[] destinationClassesForAbstract = (IType[]) list
0662: .toArray(new IType[list.size()]);
0663: result.merge(checkAbstractMembersInDestinationClasses(
0664: membersToPushDown, destinationClassesForAbstract));
0665: monitor.done();
0666: return result;
0667: }
0668:
0669: private RefactoringStatus checkNonAbstractMembersInDestinationClasses(
0670: IMember[] membersToPushDown,
0671: IType[] destinationClassesForNonAbstract)
0672: throws JavaModelException {
0673: RefactoringStatus result = new RefactoringStatus();
0674: List list = new ArrayList(); // Arrays.asList does not support removing
0675: list.addAll(Arrays.asList(membersToPushDown));
0676: list.removeAll(Arrays
0677: .asList(getAbstractMembers(membersToPushDown)));
0678: IMember[] nonAbstractMembersToPushDown = (IMember[]) list
0679: .toArray(new IMember[list.size()]);
0680: for (int i = 0; i < destinationClassesForNonAbstract.length; i++) {
0681: result.merge(MemberCheckUtil.checkMembersInDestinationType(
0682: nonAbstractMembersToPushDown,
0683: destinationClassesForNonAbstract[i]));
0684: }
0685: return result;
0686: }
0687:
0688: private RefactoringStatus checkPossibleSubclasses(
0689: IProgressMonitor pm) throws JavaModelException {
0690: IType[] modifiableSubclasses = getAbstractDestinations(pm);
0691: if (modifiableSubclasses.length == 0) {
0692: String msg = Messages
0693: .format(
0694: RefactoringCoreMessages.PushDownRefactoring_no_subclasses,
0695: new String[] { JavaElementLabels
0696: .getTextLabel(
0697: getDeclaringType(),
0698: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0699: return RefactoringStatus.createFatalErrorStatus(msg);
0700: }
0701: return new RefactoringStatus();
0702: }
0703:
0704: private RefactoringStatus checkReferencesToPushedDownMembers(
0705: IProgressMonitor monitor) throws JavaModelException {
0706: List fields = new ArrayList(fMemberInfos.length);
0707: for (int index = 0; index < fMemberInfos.length; index++) {
0708: MemberActionInfo info = fMemberInfos[index];
0709: if (info.isToBePushedDown())
0710: fields.add(info.getMember());
0711: }
0712: IMember[] membersToPush = (IMember[]) fields
0713: .toArray(new IMember[fields.size()]);
0714: RefactoringStatus result = new RefactoringStatus();
0715: List movedMembers = Arrays
0716: .asList(MemberActionInfo
0717: .getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()));
0718: monitor
0719: .beginTask(
0720: RefactoringCoreMessages.PushDownRefactoring_check_references,
0721: membersToPush.length);
0722: for (int index = 0; index < membersToPush.length; index++) {
0723: IMember member = membersToPush[index];
0724: String label = createLabel(member);
0725: IJavaElement[] referencing = getReferencingElementsFromSameClass(
0726: member, new SubProgressMonitor(monitor, 1), result);
0727: for (int offset = 0; offset < referencing.length; offset++) {
0728: IJavaElement element = referencing[offset];
0729: if (movedMembers.contains(element))
0730: continue;
0731: if (!(element instanceof IMember))
0732: continue;
0733: IMember referencingMember = (IMember) element;
0734: Object[] keys = { label, createLabel(referencingMember) };
0735: String msg = Messages
0736: .format(
0737: RefactoringCoreMessages.PushDownRefactoring_referenced,
0738: keys);
0739: result.addError(msg, JavaStatusContext
0740: .create(referencingMember));
0741: }
0742: }
0743: monitor.done();
0744: return result;
0745: }
0746:
0747: public void computeAdditionalRequiredMembersToPushDown(
0748: IProgressMonitor monitor) throws JavaModelException {
0749: List list = Arrays
0750: .asList(getAdditionalRequiredMembers(monitor));
0751: for (int index = 0; index < fMemberInfos.length; index++) {
0752: MemberActionInfo info = fMemberInfos[index];
0753: if (list.contains(info.getMember()))
0754: info.setAction(MemberActionInfo.PUSH_DOWN_ACTION);
0755: }
0756: }
0757:
0758: private void copyBodyOfPushedDownMethod(ASTRewrite targetRewrite,
0759: IMethod method, MethodDeclaration oldMethod,
0760: MethodDeclaration newMethod, TypeVariableMaplet[] mapping)
0761: throws JavaModelException {
0762: Block body = oldMethod.getBody();
0763: if (body == null) {
0764: newMethod.setBody(null);
0765: return;
0766: }
0767: try {
0768: final IDocument document = new Document(method
0769: .getCompilationUnit().getBuffer().getContents());
0770: final ASTRewrite rewriter = ASTRewrite
0771: .create(body.getAST());
0772: final ITrackedNodePosition position = rewriter.track(body);
0773: body.accept(new TypeVariableMapper(rewriter, mapping));
0774: rewriter.rewriteAST(
0775: document,
0776: getDeclaringType().getCompilationUnit()
0777: .getJavaProject().getOptions(true)).apply(
0778: document, TextEdit.NONE);
0779: String content = document.get(position.getStartPosition(),
0780: position.getLength());
0781: String[] lines = Strings.convertIntoLines(content);
0782: Strings.trimIndentation(lines, method.getJavaProject(),
0783: false);
0784: content = Strings.concatenate(lines, StubUtility
0785: .getLineDelimiterUsed(method));
0786: newMethod.setBody((Block) targetRewrite
0787: .createStringPlaceholder(content, ASTNode.BLOCK));
0788: } catch (MalformedTreeException exception) {
0789: JavaPlugin.log(exception);
0790: } catch (BadLocationException exception) {
0791: JavaPlugin.log(exception);
0792: }
0793: }
0794:
0795: private void copyMembers(Collection adjustors, Map adjustments,
0796: Map rewrites, RefactoringStatus status,
0797: MemberActionInfo[] infos, IType[] destinations,
0798: CompilationUnitRewrite sourceRewriter,
0799: CompilationUnitRewrite unitRewriter,
0800: IProgressMonitor monitor) throws JavaModelException {
0801: try {
0802: monitor
0803: .beginTask(
0804: RefactoringCoreMessages.PushDownRefactoring_checking,
0805: 1);
0806: IType type = null;
0807: TypeVariableMaplet[] mapping = null;
0808: for (int index = 0; index < destinations.length; index++) {
0809: type = destinations[index];
0810: mapping = TypeVariableUtil.super TypeToInheritedType(
0811: getDeclaringType(), type);
0812: if (unitRewriter.getCu().equals(
0813: type.getCompilationUnit())) {
0814: IMember member = null;
0815: MemberVisibilityAdjustor adjustor = null;
0816: AbstractTypeDeclaration declaration = ASTNodeSearchUtil
0817: .getAbstractTypeDeclarationNode(type,
0818: unitRewriter.getRoot());
0819: for (int offset = infos.length - 1; offset >= 0; offset--) {
0820: member = infos[offset].getMember();
0821: adjustor = new MemberVisibilityAdjustor(type,
0822: member);
0823: if (infos[offset]
0824: .isNewMethodToBeDeclaredAbstract())
0825: adjustor.setIncoming(false);
0826: adjustor.setRewrite(sourceRewriter
0827: .getASTRewrite(), sourceRewriter
0828: .getRoot());
0829: adjustor.setRewrites(rewrites);
0830:
0831: // TW: set to error if bug 78387 is fixed
0832: adjustor
0833: .setFailureSeverity(RefactoringStatus.WARNING);
0834:
0835: adjustor.setStatus(status);
0836: adjustor.setAdjustments(adjustments);
0837: adjustor
0838: .adjustVisibility(new SubProgressMonitor(
0839: monitor, 1));
0840: adjustments.remove(member);
0841: adjustors.add(adjustor);
0842: status.merge(checkProjectCompliance(
0843: getCompilationUnitRewrite(rewrites,
0844: getDeclaringType()
0845: .getCompilationUnit()),
0846: type, new IMember[] { infos[offset]
0847: .getMember() }));
0848: if (infos[offset].isFieldInfo()) {
0849: final VariableDeclarationFragment oldField = ASTNodeSearchUtil
0850: .getFieldDeclarationFragmentNode(
0851: (IField) infos[offset]
0852: .getMember(),
0853: sourceRewriter.getRoot());
0854: if (oldField != null) {
0855: FieldDeclaration newField = createNewFieldDeclarationNode(
0856: infos[offset], sourceRewriter
0857: .getRoot(), mapping,
0858: unitRewriter.getASTRewrite(),
0859: oldField);
0860: unitRewriter
0861: .getASTRewrite()
0862: .getListRewrite(
0863: declaration,
0864: declaration
0865: .getBodyDeclarationsProperty())
0866: .insertAt(
0867: newField,
0868: ASTNodes
0869: .getInsertionIndex(
0870: newField,
0871: declaration
0872: .bodyDeclarations()),
0873: unitRewriter
0874: .createCategorizedGroupDescription(
0875: RefactoringCoreMessages.HierarchyRefactoring_add_member,
0876: SET_PUSH_DOWN));
0877: ImportRewriteUtil.addImports(
0878: unitRewriter, oldField
0879: .getParent(),
0880: new HashMap(), new HashMap(),
0881: false);
0882: }
0883: } else {
0884: final MethodDeclaration oldMethod = ASTNodeSearchUtil
0885: .getMethodDeclarationNode(
0886: (IMethod) infos[offset]
0887: .getMember(),
0888: sourceRewriter.getRoot());
0889: if (oldMethod != null) {
0890: MethodDeclaration newMethod = createNewMethodDeclarationNode(
0891: infos[offset], mapping,
0892: unitRewriter, oldMethod);
0893: unitRewriter
0894: .getASTRewrite()
0895: .getListRewrite(
0896: declaration,
0897: declaration
0898: .getBodyDeclarationsProperty())
0899: .insertAt(
0900: newMethod,
0901: ASTNodes
0902: .getInsertionIndex(
0903: newMethod,
0904: declaration
0905: .bodyDeclarations()),
0906: unitRewriter
0907: .createCategorizedGroupDescription(
0908: RefactoringCoreMessages.HierarchyRefactoring_add_member,
0909: SET_PUSH_DOWN));
0910: ImportRewriteUtil.addImports(
0911: unitRewriter, oldMethod,
0912: new HashMap(), new HashMap(),
0913: false);
0914: }
0915: }
0916: }
0917: }
0918: }
0919: } finally {
0920: monitor.done();
0921: }
0922: }
0923:
0924: /**
0925: * {@inheritDoc}
0926: */
0927: public Change createChange(IProgressMonitor pm)
0928: throws CoreException, OperationCanceledException {
0929: try {
0930: final Map arguments = new HashMap();
0931: String project = null;
0932: final IType declaring = getDeclaringType();
0933: final IJavaProject javaProject = declaring.getJavaProject();
0934: if (javaProject != null)
0935: project = javaProject.getElementName();
0936: int flags = JavaRefactoringDescriptor.JAR_MIGRATION
0937: | JavaRefactoringDescriptor.JAR_REFACTORING
0938: | RefactoringDescriptor.STRUCTURAL_CHANGE
0939: | RefactoringDescriptor.MULTI_CHANGE;
0940: try {
0941: if (declaring.isLocal() || declaring.isAnonymous())
0942: flags |= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
0943: } catch (JavaModelException exception) {
0944: JavaPlugin.log(exception);
0945: }
0946: final String description = fMembersToMove.length == 1 ? Messages
0947: .format(
0948: RefactoringCoreMessages.PushDownRefactoring_descriptor_description_short_multi,
0949: fMembersToMove[0].getElementName())
0950: : RefactoringCoreMessages.PushDownRefactoring_descriptor_description_short;
0951: final String header = fMembersToMove.length == 1 ? Messages
0952: .format(
0953: RefactoringCoreMessages.PushDownRefactoring_descriptor_description_full,
0954: new String[] {
0955: JavaElementLabels
0956: .getElementLabel(
0957: fMembersToMove[0],
0958: JavaElementLabels.ALL_FULLY_QUALIFIED),
0959: JavaElementLabels
0960: .getElementLabel(
0961: declaring,
0962: JavaElementLabels.ALL_FULLY_QUALIFIED) })
0963: : Messages
0964: .format(
0965: RefactoringCoreMessages.PushDownRefactoring_descriptor_description,
0966: new String[] { JavaElementLabels
0967: .getElementLabel(
0968: declaring,
0969: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0970: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
0971: project, this , header);
0972: final String[] settings = new String[fMembersToMove.length];
0973: for (int index = 0; index < settings.length; index++)
0974: settings[index] = JavaElementLabels.getElementLabel(
0975: fMembersToMove[index],
0976: JavaElementLabels.ALL_FULLY_QUALIFIED);
0977: comment
0978: .addSetting(JDTRefactoringDescriptorComment
0979: .createCompositeSetting(
0980: RefactoringCoreMessages.PushDownRefactoring_pushed_members_pattern,
0981: settings));
0982: addSuperTypeSettings(comment, true);
0983: final PushDownDescriptor descriptor = new PushDownDescriptor(
0984: project, description, comment.asString(),
0985: arguments, flags);
0986: if (fCachedDeclaringType != null)
0987: arguments.put(
0988: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT,
0989: JavaRefactoringDescriptorUtil.elementToHandle(
0990: project, fCachedDeclaringType));
0991: for (int index = 0; index < fMembersToMove.length; index++) {
0992: arguments.put(
0993: JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
0994: + (index + 1),
0995: JavaRefactoringDescriptorUtil.elementToHandle(
0996: project, fMembersToMove[index]));
0997: for (int offset = 0; offset < fMemberInfos.length; offset++) {
0998: if (fMemberInfos[offset].getMember().equals(
0999: fMembersToMove[index])) {
1000: switch (fMemberInfos[offset].getAction()) {
1001: case MemberActionInfo.PUSH_ABSTRACT_ACTION:
1002: arguments.put(ATTRIBUTE_ABSTRACT
1003: + (index + 1), Boolean
1004: .valueOf(true).toString());
1005: break;
1006: case MemberActionInfo.PUSH_DOWN_ACTION:
1007: arguments.put(ATTRIBUTE_PUSH + (index + 1),
1008: Boolean.valueOf(true).toString());
1009: break;
1010: }
1011: }
1012: }
1013: }
1014: return new DynamicValidationRefactoringChange(
1015: descriptor,
1016: RefactoringCoreMessages.PushDownRefactoring_change_name,
1017: fChangeManager.getAllChanges());
1018: } finally {
1019: pm.done();
1020: clearCaches();
1021: }
1022: }
1023:
1024: private TextEditBasedChangeManager createChangeManager(
1025: final IProgressMonitor monitor,
1026: final RefactoringStatus status) throws CoreException {
1027: Assert.isNotNull(monitor);
1028: Assert.isNotNull(status);
1029: try {
1030: monitor
1031: .beginTask(
1032: RefactoringCoreMessages.PushDownRefactoring_checking,
1033: 7);
1034: final ICompilationUnit source = getDeclaringType()
1035: .getCompilationUnit();
1036: final CompilationUnitRewrite sourceRewriter = new CompilationUnitRewrite(
1037: source);
1038: final Map rewrites = new HashMap(2);
1039: rewrites.put(source, sourceRewriter);
1040: IType[] types = getHierarchyOfDeclaringClass(
1041: new SubProgressMonitor(monitor, 1)).getSubclasses(
1042: getDeclaringType());
1043: final Set result = new HashSet(types.length + 1);
1044: for (int index = 0; index < types.length; index++)
1045: result.add(types[index].getCompilationUnit());
1046: result.add(source);
1047: final Map adjustments = new HashMap();
1048: final List adjustors = new ArrayList();
1049: final ICompilationUnit[] units = (ICompilationUnit[]) result
1050: .toArray(new ICompilationUnit[result.size()]);
1051: ICompilationUnit unit = null;
1052: CompilationUnitRewrite rewrite = null;
1053: final IProgressMonitor sub = new SubProgressMonitor(
1054: monitor, 4);
1055: try {
1056: sub
1057: .beginTask(
1058: RefactoringCoreMessages.PushDownRefactoring_checking,
1059: units.length * 4);
1060: for (int index = 0; index < units.length; index++) {
1061: unit = units[index];
1062: rewrite = getCompilationUnitRewrite(rewrites, unit);
1063: if (unit.equals(sourceRewriter.getCu())) {
1064: final AbstractTypeDeclaration declaration = ASTNodeSearchUtil
1065: .getAbstractTypeDeclarationNode(
1066: getDeclaringType(), rewrite
1067: .getRoot());
1068: if (!JdtFlags.isAbstract(getDeclaringType())
1069: && getAbstractDeclarationInfos().length != 0)
1070: ModifierRewrite
1071: .create(rewrite.getASTRewrite(),
1072: declaration)
1073: .setModifiers(
1074: (Modifier.ABSTRACT | declaration
1075: .getModifiers()),
1076: rewrite
1077: .createCategorizedGroupDescription(
1078: RefactoringCoreMessages.PushDownRefactoring_make_abstract,
1079: SET_PUSH_DOWN));
1080: deleteDeclarationNodes(sourceRewriter, false,
1081: rewrite, Arrays
1082: .asList(getDeletableMembers()),
1083: SET_PUSH_DOWN);
1084: MemberActionInfo[] methods = getAbstractDeclarationInfos();
1085: for (int offset = 0; offset < methods.length; offset++)
1086: declareMethodAbstract(methods[offset],
1087: sourceRewriter, rewrite);
1088: }
1089: final IMember[] members = getAbstractMembers(getAbstractDestinations(new SubProgressMonitor(
1090: monitor, 1)));
1091: final IType[] classes = new IType[members.length];
1092: for (int offset = 0; offset < members.length; offset++)
1093: classes[offset] = (IType) members[offset];
1094: copyMembers(adjustors, adjustments, rewrites,
1095: status, getAbstractMemberInfos(), classes,
1096: sourceRewriter, rewrite, sub);
1097: copyMembers(
1098: adjustors,
1099: adjustments,
1100: rewrites,
1101: status,
1102: getEffectedMemberInfos(),
1103: getAbstractDestinations(new SubProgressMonitor(
1104: monitor, 1)), sourceRewriter,
1105: rewrite, sub);
1106: if (monitor.isCanceled())
1107: throw new OperationCanceledException();
1108: }
1109: } finally {
1110: sub.done();
1111: }
1112: if (!adjustors.isEmpty() && !adjustments.isEmpty()) {
1113: final MemberVisibilityAdjustor adjustor = (MemberVisibilityAdjustor) adjustors
1114: .get(0);
1115: adjustor.rewriteVisibility(new SubProgressMonitor(
1116: monitor, 1));
1117: }
1118: final TextEditBasedChangeManager manager = new TextEditBasedChangeManager();
1119: for (final Iterator iterator = rewrites.keySet().iterator(); iterator
1120: .hasNext();) {
1121: unit = (ICompilationUnit) iterator.next();
1122: rewrite = (CompilationUnitRewrite) rewrites.get(unit);
1123: if (rewrite != null)
1124: manager.manage(unit, rewrite.createChange());
1125: }
1126: return manager;
1127: } finally {
1128: monitor.done();
1129: }
1130: }
1131:
1132: private FieldDeclaration createNewFieldDeclarationNode(
1133: MemberActionInfo info, CompilationUnit declaringCuNode,
1134: TypeVariableMaplet[] mapping, ASTRewrite rewrite,
1135: VariableDeclarationFragment oldFieldFragment)
1136: throws JavaModelException {
1137: Assert.isTrue(info.isFieldInfo());
1138: IField field = (IField) info.getMember();
1139: AST ast = rewrite.getAST();
1140: VariableDeclarationFragment newFragment = ast
1141: .newVariableDeclarationFragment();
1142: newFragment.setExtraDimensions(oldFieldFragment
1143: .getExtraDimensions());
1144: Expression initializer = oldFieldFragment.getInitializer();
1145: if (initializer != null) {
1146: Expression newInitializer = null;
1147: if (mapping.length > 0)
1148: newInitializer = createPlaceholderForExpression(
1149: initializer, field.getCompilationUnit(),
1150: mapping, rewrite);
1151: else
1152: newInitializer = createPlaceholderForExpression(
1153: initializer, field.getCompilationUnit(),
1154: rewrite);
1155: newFragment.setInitializer(newInitializer);
1156: }
1157: newFragment.setName(ast.newSimpleName(oldFieldFragment
1158: .getName().getIdentifier()));
1159: FieldDeclaration newField = ast
1160: .newFieldDeclaration(newFragment);
1161: FieldDeclaration oldField = ASTNodeSearchUtil
1162: .getFieldDeclarationNode(field, declaringCuNode);
1163: if (info.copyJavadocToCopiesInSubclasses())
1164: copyJavadocNode(rewrite, oldField, newField);
1165: copyAnnotations(oldField, newField);
1166: newField.modifiers().addAll(
1167: ASTNodeFactory.newModifiers(ast, info
1168: .getNewModifiersForCopyInSubclass(oldField
1169: .getModifiers())));
1170: Type oldType = oldField.getType();
1171: ICompilationUnit cu = field.getCompilationUnit();
1172: Type newType = null;
1173: if (mapping.length > 0) {
1174: newType = createPlaceholderForType(oldType, cu, mapping,
1175: rewrite);
1176: } else
1177: newType = createPlaceholderForType(oldType, cu, rewrite);
1178: newField.setType(newType);
1179: return newField;
1180: }
1181:
1182: private MethodDeclaration createNewMethodDeclarationNode(
1183: MemberActionInfo info, TypeVariableMaplet[] mapping,
1184: CompilationUnitRewrite rewriter, MethodDeclaration oldMethod)
1185: throws JavaModelException {
1186: Assert.isTrue(!info.isFieldInfo());
1187: IMethod method = (IMethod) info.getMember();
1188: ASTRewrite rewrite = rewriter.getASTRewrite();
1189: AST ast = rewrite.getAST();
1190: MethodDeclaration newMethod = ast.newMethodDeclaration();
1191: copyBodyOfPushedDownMethod(rewrite, method, oldMethod,
1192: newMethod, mapping);
1193: newMethod.setConstructor(oldMethod.isConstructor());
1194: newMethod.setExtraDimensions(oldMethod.getExtraDimensions());
1195: if (info.copyJavadocToCopiesInSubclasses())
1196: copyJavadocNode(rewrite, oldMethod, newMethod);
1197: final IJavaProject project = rewriter.getCu().getJavaProject();
1198: if (info.isNewMethodToBeDeclaredAbstract()
1199: && JavaModelUtil.is50OrHigher(project)
1200: && JavaPreferencesSettings
1201: .getCodeGenerationSettings(project).overrideAnnotation) {
1202: final MarkerAnnotation annotation = ast
1203: .newMarkerAnnotation();
1204: annotation.setTypeName(ast.newSimpleName("Override")); //$NON-NLS-1$
1205: newMethod.modifiers().add(annotation);
1206: }
1207: copyAnnotations(oldMethod, newMethod);
1208: newMethod.modifiers().addAll(
1209: ASTNodeFactory.newModifiers(ast, info
1210: .getNewModifiersForCopyInSubclass(oldMethod
1211: .getModifiers())));
1212: newMethod.setName(ast.newSimpleName(oldMethod.getName()
1213: .getIdentifier()));
1214: copyReturnType(rewrite, method.getCompilationUnit(), oldMethod,
1215: newMethod, mapping);
1216: copyParameters(rewrite, method.getCompilationUnit(), oldMethod,
1217: newMethod, mapping);
1218: copyThrownExceptions(oldMethod, newMethod);
1219: copyTypeParameters(oldMethod, newMethod);
1220: return newMethod;
1221: }
1222:
1223: private void declareMethodAbstract(MemberActionInfo info,
1224: CompilationUnitRewrite sourceRewrite,
1225: CompilationUnitRewrite unitRewrite)
1226: throws JavaModelException {
1227: Assert.isTrue(!info.isFieldInfo());
1228: IMethod method = (IMethod) info.getMember();
1229: if (JdtFlags.isAbstract(method))
1230: return;
1231: final MethodDeclaration declaration = ASTNodeSearchUtil
1232: .getMethodDeclarationNode(method, sourceRewrite
1233: .getRoot());
1234: unitRewrite.getASTRewrite().remove(declaration.getBody(), null);
1235: sourceRewrite.getImportRemover().registerRemovedNode(
1236: declaration.getBody());
1237: ModifierRewrite
1238: .create(unitRewrite.getASTRewrite(), declaration)
1239: .setModifiers(
1240: info.getNewModifiersForOriginal(declaration
1241: .getModifiers()), null);
1242: }
1243:
1244: private MemberActionInfo[] getAbstractDeclarationInfos()
1245: throws JavaModelException {
1246: List result = new ArrayList(fMemberInfos.length);
1247: for (int index = 0; index < fMemberInfos.length; index++) {
1248: MemberActionInfo info = fMemberInfos[index];
1249: if (info.isNewMethodToBeDeclaredAbstract())
1250: result.add(info);
1251: }
1252: return (MemberActionInfo[]) result
1253: .toArray(new MemberActionInfo[result.size()]);
1254: }
1255:
1256: private IType[] getAbstractDestinations(IProgressMonitor monitor)
1257: throws JavaModelException {
1258: IType[] allDirectSubclasses = getHierarchyOfDeclaringClass(
1259: monitor).getSubclasses(getDeclaringType());
1260: List result = new ArrayList(allDirectSubclasses.length);
1261: for (int index = 0; index < allDirectSubclasses.length; index++) {
1262: IType subclass = allDirectSubclasses[index];
1263: if (subclass.exists() && !subclass.isBinary()
1264: && !subclass.isReadOnly()
1265: && subclass.getCompilationUnit() != null
1266: && subclass.isStructureKnown())
1267: result.add(subclass);
1268: }
1269: return (IType[]) result.toArray(new IType[result.size()]);
1270: }
1271:
1272: private MemberActionInfo[] getAbstractMemberInfos()
1273: throws JavaModelException {
1274: List result = new ArrayList(fMemberInfos.length);
1275: for (int index = 0; index < fMemberInfos.length; index++) {
1276: MemberActionInfo info = fMemberInfos[index];
1277: if (info.isToBeCreatedInSubclassesOfDeclaringClass()
1278: && JdtFlags.isAbstract(info.getMember()))
1279: result.add(info);
1280: }
1281: return (MemberActionInfo[]) result
1282: .toArray(new MemberActionInfo[result.size()]);
1283: }
1284:
1285: public IMember[] getAdditionalRequiredMembers(
1286: IProgressMonitor monitor) throws JavaModelException {
1287: IMember[] members = MemberActionInfo
1288: .getMembers(getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass());
1289: monitor
1290: .beginTask(
1291: RefactoringCoreMessages.PushDownRefactoring_calculating_required,
1292: members.length);// not
1293: // true,
1294: // but
1295: // not
1296: // easy
1297: // to
1298: // give
1299: // anything
1300: // better
1301: List queue = new ArrayList(members.length);
1302: queue.addAll(Arrays.asList(members));
1303: if (queue.isEmpty())
1304: return new IMember[0];
1305: int i = 0;
1306: IMember current;
1307: do {
1308: current = (IMember) queue.get(i);
1309: addAllRequiredPushableMembers(queue, current,
1310: new SubProgressMonitor(monitor, 1));
1311: i++;
1312: if (queue.size() == i)
1313: current = null;
1314: } while (current != null);
1315: queue.removeAll(Arrays.asList(members));// report only additional
1316: return (IMember[]) queue.toArray(new IMember[queue.size()]);
1317: }
1318:
1319: private IMember[] getDeletableMembers() {
1320: List result = new ArrayList(fMemberInfos.length);
1321: for (int i = 0; i < fMemberInfos.length; i++) {
1322: MemberActionInfo info = fMemberInfos[i];
1323: if (info.isToBeDeletedFromDeclaringClass())
1324: result.add(info.getMember());
1325: }
1326: return (IMember[]) result.toArray(new IMember[result.size()]);
1327: }
1328:
1329: private MemberActionInfo[] getEffectedMemberInfos()
1330: throws JavaModelException {
1331: List result = new ArrayList(fMemberInfos.length);
1332: for (int i = 0; i < fMemberInfos.length; i++) {
1333: MemberActionInfo info = fMemberInfos[i];
1334: if (info.isToBeCreatedInSubclassesOfDeclaringClass()
1335: && !JdtFlags.isAbstract(info.getMember()))
1336: result.add(info);
1337: }
1338: return (MemberActionInfo[]) result
1339: .toArray(new MemberActionInfo[result.size()]);
1340: }
1341:
1342: /**
1343: * {@inheritDoc}
1344: */
1345: public Object[] getElements() {
1346: return fMembersToMove;
1347: }
1348:
1349: private ITypeHierarchy getHierarchyOfDeclaringClass(
1350: IProgressMonitor monitor) throws JavaModelException {
1351: try {
1352: if (fCachedClassHierarchy != null)
1353: return fCachedClassHierarchy;
1354: fCachedClassHierarchy = getDeclaringType()
1355: .newTypeHierarchy(monitor);
1356: return fCachedClassHierarchy;
1357: } finally {
1358: monitor.done();
1359: }
1360: }
1361:
1362: /**
1363: * {@inheritDoc}
1364: */
1365: public String getIdentifier() {
1366: return IDENTIFIER;
1367: }
1368:
1369: private MemberActionInfo[] getInfosForMembersToBeCreatedInSubclassesOfDeclaringClass()
1370: throws JavaModelException {
1371: MemberActionInfo[] abs = getAbstractMemberInfos();
1372: MemberActionInfo[] nonabs = getEffectedMemberInfos();
1373: List result = new ArrayList(abs.length + nonabs.length);
1374: result.addAll(Arrays.asList(abs));
1375: result.addAll(Arrays.asList(nonabs));
1376: return (MemberActionInfo[]) result
1377: .toArray(new MemberActionInfo[result.size()]);
1378: }
1379:
1380: public MemberActionInfo[] getMemberActionInfos() {
1381: return fMemberInfos;
1382: }
1383:
1384: /**
1385: * {@inheritDoc}
1386: */
1387: public String getProcessorName() {
1388: return RefactoringCoreMessages.PushDownRefactoring_name;
1389: }
1390:
1391: /**
1392: * {@inheritDoc}
1393: */
1394: public RefactoringStatus initialize(RefactoringArguments arguments) {
1395: if (arguments instanceof JavaRefactoringArguments) {
1396: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
1397: String handle = extended
1398: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1399: if (handle != null) {
1400: final IJavaElement element = JavaRefactoringDescriptorUtil
1401: .handleToElement(extended.getProject(), handle,
1402: false);
1403: if (element == null
1404: || !element.exists()
1405: || element.getElementType() != IJavaElement.TYPE)
1406: return ScriptableRefactoring
1407: .createInputFatalStatus(element,
1408: getRefactoring().getName(),
1409: IJavaRefactorings.PUSH_DOWN);
1410: else
1411: fCachedDeclaringType = (IType) element;
1412: }
1413: int count = 1;
1414: final List elements = new ArrayList();
1415: final List infos = new ArrayList();
1416: String attribute = JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
1417: + count;
1418: final RefactoringStatus status = new RefactoringStatus();
1419: while ((handle = extended.getAttribute(attribute)) != null) {
1420: final IJavaElement element = JavaRefactoringDescriptorUtil
1421: .handleToElement(extended.getProject(), handle,
1422: false);
1423: if (element == null || !element.exists())
1424: status.merge(ScriptableRefactoring
1425: .createInputWarningStatus(element,
1426: getRefactoring().getName(),
1427: IJavaRefactorings.PUSH_DOWN));
1428: else
1429: elements.add(element);
1430: if (extended.getAttribute(ATTRIBUTE_ABSTRACT + count) != null)
1431: infos.add(MemberActionInfo.create(
1432: (IMember) element,
1433: MemberActionInfo.PUSH_ABSTRACT_ACTION));
1434: else if (extended.getAttribute(ATTRIBUTE_PUSH + count) != null)
1435: infos.add(MemberActionInfo.create(
1436: (IMember) element,
1437: MemberActionInfo.PUSH_DOWN_ACTION));
1438: else
1439: infos.add(MemberActionInfo.create(
1440: (IMember) element,
1441: MemberActionInfo.NO_ACTION));
1442: count++;
1443: attribute = JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
1444: + count;
1445: }
1446: fMembersToMove = (IMember[]) elements
1447: .toArray(new IMember[elements.size()]);
1448: fMemberInfos = (MemberActionInfo[]) infos
1449: .toArray(new MemberActionInfo[infos.size()]);
1450: if (!status.isOK())
1451: return status;
1452: } else
1453: return RefactoringStatus
1454: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
1455: return new RefactoringStatus();
1456: }
1457:
1458: /**
1459: * {@inheritDoc}
1460: */
1461: public boolean isApplicable() throws CoreException {
1462: return RefactoringAvailabilityTester
1463: .isPushDownAvailable(fMembersToMove);
1464: }
1465:
1466: /**
1467: * {@inheritDoc}
1468: */
1469: protected void rewriteTypeOccurrences(
1470: final TextEditBasedChangeManager manager,
1471: final ASTRequestor requestor,
1472: final CompilationUnitRewrite rewrite,
1473: final ICompilationUnit unit, final CompilationUnit node,
1474: final Set replacements, final IProgressMonitor monitor)
1475: throws CoreException {
1476: // Not needed
1477: }
1478: }
|