0001: /*******************************************************************************
0002: * Copyright (c) 2000, 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.Collections;
0015: import java.util.Comparator;
0016: import java.util.HashMap;
0017: import java.util.HashSet;
0018: import java.util.Iterator;
0019: import java.util.List;
0020: import java.util.Map;
0021: import java.util.Set;
0022:
0023: import org.eclipse.text.edits.TextEdit;
0024: import org.eclipse.text.edits.TextEditGroup;
0025:
0026: import org.eclipse.core.runtime.Assert;
0027: import org.eclipse.core.runtime.CoreException;
0028: import org.eclipse.core.runtime.IProgressMonitor;
0029: import org.eclipse.core.runtime.NullProgressMonitor;
0030: import org.eclipse.core.runtime.SubProgressMonitor;
0031:
0032: import org.eclipse.core.resources.IFile;
0033: import org.eclipse.core.resources.IResource;
0034:
0035: import org.eclipse.jface.text.BadLocationException;
0036: import org.eclipse.jface.text.Document;
0037: import org.eclipse.jface.text.IDocument;
0038:
0039: import org.eclipse.ltk.core.refactoring.Change;
0040: import org.eclipse.ltk.core.refactoring.CompositeChange;
0041: import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
0042: import org.eclipse.ltk.core.refactoring.RefactoringStatus;
0043: import org.eclipse.ltk.core.refactoring.RefactoringStatusContext;
0044: import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext;
0045: import org.eclipse.ltk.core.refactoring.participants.MoveArguments;
0046: import org.eclipse.ltk.core.refactoring.participants.MoveProcessor;
0047: import org.eclipse.ltk.core.refactoring.participants.ParticipantManager;
0048: import org.eclipse.ltk.core.refactoring.participants.RefactoringArguments;
0049: import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant;
0050: import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker;
0051: import org.eclipse.ltk.core.refactoring.participants.SharableParticipants;
0052:
0053: import org.eclipse.jdt.core.Flags;
0054: import org.eclipse.jdt.core.ICompilationUnit;
0055: import org.eclipse.jdt.core.IField;
0056: import org.eclipse.jdt.core.IInitializer;
0057: import org.eclipse.jdt.core.IJavaElement;
0058: import org.eclipse.jdt.core.IJavaProject;
0059: import org.eclipse.jdt.core.IMember;
0060: import org.eclipse.jdt.core.IMethod;
0061: import org.eclipse.jdt.core.ISourceRange;
0062: import org.eclipse.jdt.core.IType;
0063: import org.eclipse.jdt.core.JavaModelException;
0064: import org.eclipse.jdt.core.dom.ASTNode;
0065: import org.eclipse.jdt.core.dom.ASTVisitor;
0066: import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
0067: import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration;
0068: import org.eclipse.jdt.core.dom.BodyDeclaration;
0069: import org.eclipse.jdt.core.dom.EnumDeclaration;
0070: import org.eclipse.jdt.core.dom.FieldDeclaration;
0071: import org.eclipse.jdt.core.dom.IBinding;
0072: import org.eclipse.jdt.core.dom.IMethodBinding;
0073: import org.eclipse.jdt.core.dom.ITypeBinding;
0074: import org.eclipse.jdt.core.dom.IVariableBinding;
0075: import org.eclipse.jdt.core.dom.MethodDeclaration;
0076: import org.eclipse.jdt.core.dom.Modifier;
0077: import org.eclipse.jdt.core.dom.SimpleName;
0078: import org.eclipse.jdt.core.dom.TypeDeclaration;
0079: import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
0080: import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
0081: import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition;
0082: import org.eclipse.jdt.core.dom.rewrite.ListRewrite;
0083: import org.eclipse.jdt.core.refactoring.IJavaRefactorings;
0084: import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor;
0085: import org.eclipse.jdt.core.refactoring.descriptors.MoveStaticMembersDescriptor;
0086: import org.eclipse.jdt.core.search.IJavaSearchConstants;
0087: import org.eclipse.jdt.core.search.SearchMatch;
0088: import org.eclipse.jdt.core.search.SearchPattern;
0089:
0090: import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings;
0091: import org.eclipse.jdt.internal.corext.dom.ASTNodes;
0092: import org.eclipse.jdt.internal.corext.dom.ModifierRewrite;
0093: import org.eclipse.jdt.internal.corext.dom.NodeFinder;
0094: import org.eclipse.jdt.internal.corext.refactoring.Checks;
0095: import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment;
0096: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments;
0097: import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil;
0098: import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester;
0099: import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages;
0100: import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory;
0101: import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2;
0102: import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup;
0103: import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext;
0104: import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange;
0105: import org.eclipse.jdt.internal.corext.refactoring.code.ScriptableRefactoring;
0106: import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateFieldCreator;
0107: import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateMethodCreator;
0108: import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors;
0109: import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment;
0110: import org.eclipse.jdt.internal.corext.refactoring.tagging.ICommentProvider;
0111: import org.eclipse.jdt.internal.corext.refactoring.tagging.IDelegateUpdating;
0112: import org.eclipse.jdt.internal.corext.refactoring.tagging.IScriptableRefactoring;
0113: import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil;
0114: import org.eclipse.jdt.internal.corext.util.JavaModelUtil;
0115: import org.eclipse.jdt.internal.corext.util.JdtFlags;
0116: import org.eclipse.jdt.internal.corext.util.Messages;
0117: import org.eclipse.jdt.internal.corext.util.SearchUtils;
0118: import org.eclipse.jdt.internal.corext.util.Strings;
0119:
0120: import org.eclipse.jdt.ui.JavaElementLabels;
0121: import org.eclipse.jdt.ui.refactoring.IRefactoringProcessorIds;
0122:
0123: import org.eclipse.jdt.internal.ui.JavaPlugin;
0124: import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings;
0125:
0126: public final class MoveStaticMembersProcessor extends MoveProcessor
0127: implements IDelegateUpdating, IScriptableRefactoring,
0128: ICommentProvider {
0129:
0130: private static final String ATTRIBUTE_DELEGATE = "delegate"; //$NON-NLS-1$
0131: private static final String ATTRIBUTE_DEPRECATE = "deprecate"; //$NON-NLS-1$
0132: private static final String TRACKED_POSITION_PROPERTY = "MoveStaticMembersProcessor.trackedPosition"; //$NON-NLS-1$
0133:
0134: private IMember[] fMembersToMove;
0135: private IType fDestinationType;
0136: private String fDestinationTypeName;
0137:
0138: private CodeGenerationSettings fPreferences;
0139: private CompositeChange fChange;
0140: private CompilationUnitRewrite fSource;
0141: private ITypeBinding fSourceBinding;
0142: private CompilationUnitRewrite fTarget;
0143: private IBinding[] fMemberBindings;
0144: private BodyDeclaration[] fMemberDeclarations;
0145: private boolean fDelegateUpdating;
0146: private boolean fDelegateDeprecation;
0147: private String fComment;
0148:
0149: private static class TypeReferenceFinder extends ASTVisitor {
0150: List fResult = new ArrayList();
0151: Set fDefined = new HashSet();
0152:
0153: public static List perform(ASTNode root) {
0154: TypeReferenceFinder visitor = new TypeReferenceFinder();
0155: root.accept(visitor);
0156: return visitor.fResult;
0157: }
0158:
0159: public boolean visit(TypeDeclaration node) {
0160: fDefined.add(node.resolveBinding());
0161: return true;
0162: }
0163:
0164: public boolean visit(SimpleName node) {
0165: IBinding binding = node.resolveBinding();
0166: if (!(binding instanceof ITypeBinding))
0167: return true;
0168: if (!fDefined.contains(binding))
0169: fResult.add(binding);
0170: return true;
0171: }
0172:
0173: public boolean visit(AnnotationTypeDeclaration node) {
0174: fDefined.add(node.resolveBinding());
0175: return true;
0176: }
0177:
0178: public boolean visit(EnumDeclaration node) {
0179: fDefined.add(node.resolveBinding());
0180: return true;
0181: }
0182: }
0183:
0184: /**
0185: * Creates a new move static members processor.
0186: * @param members the members to move, or <code>null</code> if invoked by scripting
0187: * @param settings the code generation settings, or <code>null</code> if invoked by scripting
0188: */
0189: public MoveStaticMembersProcessor(IMember[] members,
0190: CodeGenerationSettings settings) {
0191: fMembersToMove = members;
0192: fPreferences = settings;
0193: fDelegateUpdating = false;
0194: fDelegateDeprecation = true;
0195: }
0196:
0197: /**
0198: * {@inheritDoc}
0199: */
0200: public boolean isApplicable() throws CoreException {
0201: return RefactoringAvailabilityTester
0202: .isMoveStaticMembersAvailable(fMembersToMove);
0203: }
0204:
0205: /**
0206: * {@inheritDoc}
0207: */
0208: public Object[] getElements() {
0209: Object[] result = new Object[fMembersToMove.length];
0210: System.arraycopy(fMembersToMove, 0, result, 0,
0211: fMembersToMove.length);
0212: return result;
0213: }
0214:
0215: /**
0216: * {@inheritDoc}
0217: */
0218: public String getIdentifier() {
0219: return IRefactoringProcessorIds.MOVE_STATIC_MEMBERS_PROCESSOR;
0220: }
0221:
0222: /**
0223: * {@inheritDoc}
0224: */
0225: public RefactoringParticipant[] loadParticipants(
0226: RefactoringStatus status,
0227: SharableParticipants sharedParticipants)
0228: throws CoreException {
0229: List result = new ArrayList();
0230: MoveArguments args = new MoveArguments(fDestinationType, true);
0231: String[] natures = JavaProcessors
0232: .computeAffectedNaturs(fMembersToMove);
0233: for (int i = 0; i < fMembersToMove.length; i++) {
0234: IMember member = fMembersToMove[i];
0235: result.addAll(Arrays.asList(ParticipantManager
0236: .loadMoveParticipants(status, this , member, args,
0237: natures, sharedParticipants)));
0238: }
0239: return (RefactoringParticipant[]) result
0240: .toArray(new RefactoringParticipant[result.size()]);
0241: }
0242:
0243: //------------------- IDelegateUpdating ----------------------
0244:
0245: public boolean canEnableDelegateUpdating() {
0246: try {
0247: for (int i = 0; i < fMembersToMove.length; i++) {
0248: if (isDelegateCreationAvailable(fMembersToMove[i]))
0249: return true;
0250: }
0251: } catch (JavaModelException e) {
0252: return false;
0253: }
0254: return false;
0255: }
0256:
0257: private boolean isDelegateCreationAvailable(IMember member)
0258: throws JavaModelException {
0259: if (member instanceof IMethod)
0260: return true;
0261: if (member instanceof IField
0262: && RefactoringAvailabilityTester
0263: .isDelegateCreationAvailable(((IField) member)))
0264: return true;
0265: return false;
0266: }
0267:
0268: public boolean getDelegateUpdating() {
0269: return fDelegateUpdating;
0270: }
0271:
0272: public void setDelegateUpdating(boolean updating) {
0273: fDelegateUpdating = updating;
0274: }
0275:
0276: public boolean getDeprecateDelegates() {
0277: return fDelegateDeprecation;
0278: }
0279:
0280: public void setDeprecateDelegates(boolean deprecate) {
0281: fDelegateDeprecation = deprecate;
0282: }
0283:
0284: public String getProcessorName() {
0285: return RefactoringCoreMessages.MoveMembersRefactoring_Move_Members;
0286: }
0287:
0288: public IType getDestinationType() {
0289: return fDestinationType;
0290: }
0291:
0292: public void setDestinationTypeFullyQualifiedName(
0293: String fullyQualifiedTypeName) throws JavaModelException {
0294: Assert.isNotNull(fullyQualifiedTypeName);
0295: fDestinationType = resolveType(fullyQualifiedTypeName);
0296: //workaround for bug 36032: IJavaProject#findType(..) doesn't find secondary type
0297: fDestinationTypeName = fullyQualifiedTypeName;
0298: }
0299:
0300: public IMember[] getMembersToMove() {
0301: return fMembersToMove;
0302: }
0303:
0304: public IType getDeclaringType() {
0305: //all methods declared in same type - checked in precondition
0306: return fMembersToMove[0].getDeclaringType(); //index safe - checked in areAllMoveable()
0307: }
0308:
0309: private IType resolveType(String qualifiedTypeName)
0310: throws JavaModelException {
0311: IType type = getDeclaringType().getJavaProject().findType(
0312: qualifiedTypeName);
0313: if (type == null)
0314: type = getDeclaringType().getJavaProject().findType(
0315: getDeclaringType().getPackageFragment()
0316: .getElementName(), qualifiedTypeName);
0317: return type;
0318: }
0319:
0320: //---- Activation checking ------------------------------------
0321:
0322: public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
0323: throws CoreException {
0324: try {
0325: pm
0326: .beginTask(
0327: RefactoringCoreMessages.MoveMembersRefactoring_checking,
0328: 1);
0329: RefactoringStatus result = new RefactoringStatus();
0330: result.merge(checkDeclaringType());
0331: pm.worked(1);
0332: if (result.hasFatalError())
0333: return result;
0334:
0335: fSource = new CompilationUnitRewrite(fMembersToMove[0]
0336: .getCompilationUnit());
0337: fSourceBinding = (ITypeBinding) ((SimpleName) NodeFinder
0338: .perform(fSource.getRoot(), fMembersToMove[0]
0339: .getDeclaringType().getNameRange()))
0340: .resolveBinding();
0341: fMemberBindings = getMemberBindings();
0342: if (fSourceBinding == null || hasUnresolvedMemberBinding()) {
0343: result
0344: .addFatalError(Messages
0345: .format(
0346: RefactoringCoreMessages.MoveMembersRefactoring_compile_errors,
0347: fSource.getCu()
0348: .getElementName()));
0349: }
0350: fMemberDeclarations = getASTMembers(result);
0351: return result;
0352: } finally {
0353: pm.done();
0354: }
0355: }
0356:
0357: private boolean hasUnresolvedMemberBinding() {
0358: for (int i = 0; i < fMemberBindings.length; i++) {
0359: if (fMemberBindings[i] == null)
0360: return true;
0361: }
0362: return false;
0363: }
0364:
0365: private RefactoringStatus checkDeclaringType() {
0366: IType declaringType = getDeclaringType();
0367:
0368: if (JavaModelUtil.getFullyQualifiedName(declaringType).equals(
0369: "java.lang.Object")) //$NON-NLS-1$
0370: return RefactoringStatus
0371: .createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_Object);
0372:
0373: if (declaringType.isBinary())
0374: return RefactoringStatus
0375: .createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_binary);
0376:
0377: if (declaringType.isReadOnly())
0378: return RefactoringStatus
0379: .createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_read_only);
0380:
0381: return null;
0382: }
0383:
0384: //---- Input checking ------------------------------------
0385:
0386: public RefactoringStatus checkFinalConditions(IProgressMonitor pm,
0387: CheckConditionsContext context) throws CoreException {
0388: fTarget = null;
0389: try {
0390: pm
0391: .beginTask(
0392: RefactoringCoreMessages.MoveMembersRefactoring_checking,
0393: 10);
0394:
0395: RefactoringStatus result = new RefactoringStatus();
0396:
0397: fSource.clearASTAndImportRewrites();
0398:
0399: result.merge(checkDestinationType());
0400: if (result.hasFatalError())
0401: return result;
0402:
0403: result.merge(checkDestinationInsideTypeToMove());
0404: if (result.hasFatalError())
0405: return result;
0406:
0407: result.merge(MemberCheckUtil.checkMembersInDestinationType(
0408: fMembersToMove, fDestinationType));
0409: if (result.hasFatalError())
0410: return result;
0411:
0412: result
0413: .merge(checkNativeMovedMethods(new SubProgressMonitor(
0414: pm, 1)));
0415:
0416: if (result.hasFatalError())
0417: return result;
0418:
0419: List modifiedCus = new ArrayList();
0420: createChange(modifiedCus, result, new SubProgressMonitor(
0421: pm, 7));
0422: IFile[] changedFiles = getAllFilesToModify(modifiedCus);
0423: ResourceChangeChecker checker = (ResourceChangeChecker) context
0424: .getChecker(ResourceChangeChecker.class);
0425: for (int i = 0; i < changedFiles.length; i++) {
0426: checker.getDeltaFactory().change(changedFiles[i]);
0427: }
0428:
0429: return result;
0430: } finally {
0431: pm.done();
0432: }
0433: }
0434:
0435: private IFile[] getAllFilesToModify(List modifiedCus) {
0436: Set result = new HashSet();
0437: IResource resource = fDestinationType.getCompilationUnit()
0438: .getResource();
0439: result.add(resource);
0440: for (int i = 0; i < fMembersToMove.length; i++) {
0441: resource = fMembersToMove[i].getCompilationUnit()
0442: .getResource();
0443: if (resource != null)
0444: result.add(resource);
0445: }
0446: for (Iterator iter = modifiedCus.iterator(); iter.hasNext();) {
0447: ICompilationUnit unit = (ICompilationUnit) iter.next();
0448: if (unit.getResource() != null)
0449: result.add(unit.getResource());
0450: }
0451: return (IFile[]) result.toArray(new IFile[result.size()]);
0452: }
0453:
0454: private RefactoringStatus checkDestinationType()
0455: throws JavaModelException {
0456: if (fDestinationType == null) {
0457: String message = Messages
0458: .format(
0459: RefactoringCoreMessages.MoveMembersRefactoring_not_found,
0460: fDestinationTypeName);
0461: return RefactoringStatus.createFatalErrorStatus(message);
0462: }
0463:
0464: if (fDestinationType.equals(getDeclaringType())) {
0465: String message = Messages
0466: .format(
0467: RefactoringCoreMessages.MoveMembersRefactoring_same,
0468: JavaElementUtil
0469: .createSignature(fDestinationType));
0470: return RefactoringStatus.createFatalErrorStatus(message);
0471: }
0472:
0473: if (!fDestinationType.exists()) {
0474: String message = Messages
0475: .format(
0476: RefactoringCoreMessages.MoveMembersRefactoring_not_exist,
0477: JavaElementUtil
0478: .createSignature(fDestinationType));
0479: return RefactoringStatus.createFatalErrorStatus(message);
0480: }
0481:
0482: if (fDestinationType.isBinary()) {
0483: String message = Messages
0484: .format(
0485: RefactoringCoreMessages.MoveMembersRefactoring_dest_binary,
0486: JavaElementUtil
0487: .createSignature(fDestinationType));
0488: return RefactoringStatus.createFatalErrorStatus(message);
0489: }
0490:
0491: RefactoringStatus result = new RefactoringStatus();
0492:
0493: if (fDestinationType.isInterface()
0494: && !getDeclaringType().isInterface())
0495: result.merge(checkFieldsForInterface());
0496: if (result.hasFatalError())
0497: return result;
0498:
0499: // no checking required for moving interface fields to classes
0500:
0501: if (!((JdtFlags.isStatic(fDestinationType)) || (fDestinationType
0502: .getDeclaringType() == null))) {
0503: String message = RefactoringCoreMessages.MoveMembersRefactoring_static_declaration;
0504: result.addError(message);
0505: }
0506:
0507: return result;
0508: }
0509:
0510: private RefactoringStatus checkDestinationInsideTypeToMove()
0511: throws JavaModelException {
0512: RefactoringStatus result = new RefactoringStatus();
0513: for (int i = 0; i < fMembersToMove.length; i++) {
0514: if (!(fMembersToMove[i] instanceof IType))
0515: continue;
0516: IType type = (IType) fMembersToMove[i];
0517: if (fDestinationType.equals(type)
0518: || JavaElementUtil.isAncestorOf(type,
0519: fDestinationType)) {
0520: String message = Messages
0521: .format(
0522: RefactoringCoreMessages.MoveMembersRefactoring_inside,
0523: new String[] {
0524: JavaModelUtil
0525: .getFullyQualifiedName(type),
0526: JavaModelUtil
0527: .getFullyQualifiedName(fDestinationType) });
0528: RefactoringStatusContext context = JavaStatusContext
0529: .create(fDestinationType.getCompilationUnit(),
0530: fDestinationType.getNameRange());
0531: result.addFatalError(message, context);
0532: return result;
0533: }
0534: }
0535: return result;
0536: }
0537:
0538: private RefactoringStatus checkFieldsForInterface()
0539: throws JavaModelException {
0540: //could be more clever and make field final if it is only written once...
0541: RefactoringStatus result = new RefactoringStatus();
0542: for (int i = 0; i < fMembersToMove.length; i++) {
0543: if (!canMoveToInterface(fMembersToMove[i])) {
0544: String message = RefactoringCoreMessages.MoveMembersRefactoring_only_public_static;
0545: result.addError(message, JavaStatusContext
0546: .create(fMembersToMove[i]));
0547: }
0548: }
0549: return result;
0550: }
0551:
0552: private boolean canMoveToInterface(IMember member)
0553: throws JavaModelException {
0554: int flags = member.getFlags();
0555: switch (member.getElementType()) {
0556: case IJavaElement.FIELD:
0557: if (!(Flags.isPublic(flags) && Flags.isStatic(flags) && Flags
0558: .isFinal(flags)))
0559: return false;
0560: if (Flags.isEnum(flags))
0561: return false;
0562: VariableDeclarationFragment declaration = ASTNodeSearchUtil
0563: .getFieldDeclarationFragmentNode((IField) member,
0564: fSource.getRoot());
0565: if (declaration != null)
0566: return declaration.getInitializer() != null;
0567: return false;
0568: case IJavaElement.TYPE: {
0569: IType type = (IType) member;
0570: if (type.isInterface() && !Checks.isTopLevel(type))
0571: return true;
0572: return (Flags.isPublic(flags) && Flags.isStatic(flags));
0573: }
0574: default:
0575: return false;
0576: }
0577: }
0578:
0579: private RefactoringStatus checkMovedMemberAvailability(
0580: IMember memberToMove, IProgressMonitor pm)
0581: throws JavaModelException {
0582: RefactoringStatus result = new RefactoringStatus();
0583: if (memberToMove instanceof IType) { // recursively check accessibility of member type's members
0584: IJavaElement[] typeMembers = ((IType) memberToMove)
0585: .getChildren();
0586: pm
0587: .beginTask(
0588: RefactoringCoreMessages.MoveMembersRefactoring_checking,
0589: typeMembers.length + 1);
0590: for (int i = 0; i < typeMembers.length; i++) {
0591: if (typeMembers[i] instanceof IInitializer)
0592: pm.worked(1);
0593: else
0594: result.merge(checkMovedMemberAvailability(
0595: (IMember) typeMembers[i],
0596: new SubProgressMonitor(pm, 1)));
0597: }
0598: } else {
0599: pm
0600: .beginTask(
0601: RefactoringCoreMessages.MoveMembersRefactoring_checking,
0602: 1);
0603: }
0604:
0605: IType[] blindAccessorTypes = getTypesNotSeeingMovedMember(
0606: memberToMove, new SubProgressMonitor(pm, 1), result);
0607: for (int k = 0; k < blindAccessorTypes.length; k++) {
0608: String message = createNonAccessibleMemberMessage(
0609: memberToMove, blindAccessorTypes[k],/*moved*/true);
0610: result.addError(message, JavaStatusContext
0611: .create(memberToMove));
0612: }
0613: pm.done();
0614: return result;
0615: }
0616:
0617: private IType[] getTypesNotSeeingMovedMember(IMember member,
0618: IProgressMonitor pm, RefactoringStatus status)
0619: throws JavaModelException {
0620: if (JdtFlags.isPublic(member)
0621: && JdtFlags.isPublic(fDestinationType))
0622: return new IType[0];
0623:
0624: HashSet blindAccessorTypes = new HashSet(); // referencing, but access to destination type illegal
0625: SearchResultGroup[] references = getReferences(member,
0626: new SubProgressMonitor(pm, 1), status);
0627: for (int i = 0; i < references.length; i++) {
0628: SearchMatch[] searchResults = references[i]
0629: .getSearchResults();
0630: for (int k = 0; k < searchResults.length; k++) {
0631: SearchMatch searchResult = searchResults[k];
0632: IJavaElement element = SearchUtils
0633: .getEnclosingJavaElement(searchResult);
0634: IType type = (IType) element
0635: .getAncestor(IJavaElement.TYPE);
0636: if (type != null //reference can e.g. be an import declaration
0637: && !blindAccessorTypes.contains(type)
0638: && !isWithinMemberToMove(searchResult)
0639: && !isVisibleFrom(member, getDestinationType(),
0640: type)) {
0641: blindAccessorTypes.add(type);
0642: }
0643: }
0644: }
0645:
0646: if (fDelegateUpdating && isDelegateCreationAvailable(member)) {
0647: // ensure moved member is visible from the delegate
0648: IType type = member.getDeclaringType();
0649: if (!blindAccessorTypes.contains(type)
0650: && !isVisibleFrom(member, getDestinationType(),
0651: type))
0652: blindAccessorTypes.add(type);
0653: }
0654:
0655: return (IType[]) blindAccessorTypes
0656: .toArray(new IType[blindAccessorTypes.size()]);
0657: }
0658:
0659: private String createNonAccessibleMemberMessage(IMember member,
0660: IType accessingType, boolean moved) {
0661: //Non-visibility can have various reasons and always displaying all visibility
0662: //flags for all enclosing elements would be too heavy. Context reveals exact cause.
0663: IType declaringType = moved ? getDestinationType()
0664: : getDeclaringType();
0665: String message;
0666: switch (member.getElementType()) {
0667: case IJavaElement.FIELD: {
0668: if (moved)
0669: message = Messages
0670: .format(
0671: RefactoringCoreMessages.MoveMembersRefactoring_moved_field,
0672: new String[] {
0673: JavaElementUtil
0674: .createFieldSignature((IField) member),
0675: JavaModelUtil
0676: .getFullyQualifiedName(accessingType),
0677: JavaModelUtil
0678: .getFullyQualifiedName(declaringType) });
0679: else
0680: message = Messages
0681: .format(
0682: RefactoringCoreMessages.MoveMembersRefactoring_accessed_field,
0683: new String[] {
0684: JavaElementUtil
0685: .createFieldSignature((IField) member),
0686: JavaModelUtil
0687: .getFullyQualifiedName(accessingType) });
0688: return message;
0689: }
0690: case IJavaElement.METHOD: {
0691: if (moved)
0692: message = Messages
0693: .format(
0694: RefactoringCoreMessages.MoveMembersRefactoring_moved_method,
0695: new String[] {
0696: JavaElementUtil
0697: .createMethodSignature((IMethod) member),
0698: JavaModelUtil
0699: .getFullyQualifiedName(accessingType),
0700: JavaModelUtil
0701: .getFullyQualifiedName(declaringType) });
0702: else
0703: message = Messages
0704: .format(
0705: RefactoringCoreMessages.MoveMembersRefactoring_accessed_method,
0706: new String[] {
0707: JavaElementUtil
0708: .createMethodSignature((IMethod) member),
0709: JavaModelUtil
0710: .getFullyQualifiedName(accessingType) });
0711:
0712: return message;
0713: }
0714: case IJavaElement.TYPE: {
0715: if (moved)
0716: message = Messages
0717: .format(
0718: RefactoringCoreMessages.MoveMembersRefactoring_moved_type,
0719: new String[] {
0720: JavaModelUtil
0721: .getFullyQualifiedName(((IType) member)),
0722: JavaModelUtil
0723: .getFullyQualifiedName(accessingType),
0724: JavaModelUtil
0725: .getFullyQualifiedName(declaringType) });
0726: else
0727: message = Messages
0728: .format(
0729: RefactoringCoreMessages.MoveMembersRefactoring_accessed_type,
0730: new String[] {
0731: JavaModelUtil
0732: .getFullyQualifiedName(((IType) member)),
0733: JavaModelUtil
0734: .getFullyQualifiedName(accessingType) });
0735: return message;
0736: }
0737: default:
0738: Assert.isTrue(false);
0739: return null;
0740: }
0741: }
0742:
0743: private static SearchResultGroup[] getReferences(IMember member,
0744: IProgressMonitor monitor, RefactoringStatus status)
0745: throws JavaModelException {
0746: final RefactoringSearchEngine2 engine = new RefactoringSearchEngine2(
0747: SearchPattern.createPattern(member,
0748: IJavaSearchConstants.REFERENCES,
0749: SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE));
0750: engine.setFiltering(true, true);
0751: engine.setScope(RefactoringScopeFactory.create(member));
0752: engine.setStatus(status);
0753: engine.searchPattern(new SubProgressMonitor(monitor, 1));
0754: return (SearchResultGroup[]) engine.getResults();
0755: }
0756:
0757: private static boolean isVisibleFrom(IMember member,
0758: IType newMemberDeclaringType, IType accessingType)
0759: throws JavaModelException {
0760: int memberVisibility = JdtFlags
0761: .getVisibilityCode(newMemberDeclaringType);
0762:
0763: IType declaringType = newMemberDeclaringType.getDeclaringType();
0764: while (declaringType != null) { //get lowest visibility in all parent types of newMemberDeclaringType
0765: memberVisibility = JdtFlags.getLowerVisibility(
0766: memberVisibility, JdtFlags
0767: .getVisibilityCode(declaringType));
0768: declaringType = declaringType.getDeclaringType();
0769: }
0770:
0771: switch (memberVisibility) {
0772: case Modifier.PRIVATE:
0773: return isEqualOrEnclosedType(accessingType,
0774: newMemberDeclaringType);
0775:
0776: case Modifier.NONE:
0777: return JavaModelUtil.isSamePackage(accessingType
0778: .getPackageFragment(), newMemberDeclaringType
0779: .getPackageFragment());
0780:
0781: case Modifier.PROTECTED:
0782: return JavaModelUtil.isSamePackage(accessingType
0783: .getPackageFragment(), newMemberDeclaringType
0784: .getPackageFragment())
0785: || accessingType.newSupertypeHierarchy(null)
0786: .contains(newMemberDeclaringType);
0787:
0788: case Modifier.PUBLIC:
0789: return true;
0790:
0791: default:
0792: Assert.isTrue(false);
0793: return false;
0794: }
0795: }
0796:
0797: private static boolean isEqualOrEnclosedType(IType inner,
0798: IType outer) {
0799: while (inner != null) {
0800: if (inner.equals(outer))
0801: return true;
0802: else
0803: inner = inner.getDeclaringType();
0804: }
0805: return false;
0806: }
0807:
0808: private boolean isWithinMemberToMove(SearchMatch result)
0809: throws JavaModelException {
0810: ICompilationUnit referenceCU = SearchUtils
0811: .getCompilationUnit(result);
0812: if (!referenceCU.equals(fSource.getCu()))
0813: return false;
0814: int referenceStart = result.getOffset();
0815: for (int i = 0; i < fMembersToMove.length; i++) {
0816: ISourceRange range = fMembersToMove[i].getSourceRange();
0817: if (range.getOffset() <= referenceStart
0818: && range.getOffset() + range.getLength() >= referenceStart)
0819: return true;
0820: }
0821: return false;
0822: }
0823:
0824: private RefactoringStatus checkNativeMovedMethods(
0825: IProgressMonitor pm) throws JavaModelException {
0826: pm
0827: .beginTask(
0828: RefactoringCoreMessages.MoveMembersRefactoring_checking,
0829: fMembersToMove.length);
0830: RefactoringStatus result = new RefactoringStatus();
0831: for (int i = 0; i < fMembersToMove.length; i++) {
0832: if (fMembersToMove[i].getElementType() != IJavaElement.METHOD)
0833: continue;
0834: if (!JdtFlags.isNative(fMembersToMove[i]))
0835: continue;
0836: String message = Messages
0837: .format(
0838: RefactoringCoreMessages.MoveMembersRefactoring_native,
0839: JavaElementUtil
0840: .createMethodSignature((IMethod) fMembersToMove[i]));
0841: result.addWarning(message, JavaStatusContext
0842: .create(fMembersToMove[i]));
0843: pm.worked(1);
0844: }
0845: pm.done();
0846: return result;
0847: }
0848:
0849: public Change createChange(IProgressMonitor pm)
0850: throws CoreException {
0851: pm.done();
0852: return fChange;
0853: }
0854:
0855: private void createChange(List modifiedCus,
0856: RefactoringStatus status, IProgressMonitor monitor)
0857: throws CoreException {
0858: monitor
0859: .beginTask(
0860: RefactoringCoreMessages.MoveMembersRefactoring_creating,
0861: 5);
0862: final IMember[] members = getMembersToMove();
0863: String project = null;
0864: final IJavaProject javaProject = getDeclaringType()
0865: .getJavaProject();
0866: if (javaProject != null)
0867: project = javaProject.getElementName();
0868: String header = null;
0869: if (members.length == 1)
0870: header = Messages
0871: .format(
0872: RefactoringCoreMessages.MoveStaticMembersProcessor_descriptor_description_single,
0873: new String[] {
0874: JavaElementLabels
0875: .getElementLabel(
0876: members[0],
0877: JavaElementLabels.ALL_FULLY_QUALIFIED),
0878: JavaElementLabels
0879: .getElementLabel(
0880: fDestinationType,
0881: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0882: else
0883: header = Messages
0884: .format(
0885: RefactoringCoreMessages.MoveStaticMembersProcessor_descriptor_description_multi,
0886: new String[] {
0887: String.valueOf(members.length),
0888: JavaElementLabels
0889: .getElementLabel(
0890: fDestinationType,
0891: JavaElementLabels.ALL_FULLY_QUALIFIED) });
0892: int flags = JavaRefactoringDescriptor.JAR_MIGRATION
0893: | JavaRefactoringDescriptor.JAR_REFACTORING
0894: | RefactoringDescriptor.STRUCTURAL_CHANGE
0895: | RefactoringDescriptor.MULTI_CHANGE;
0896: final IType declaring = members[0].getDeclaringType();
0897: try {
0898: if (declaring.isLocal() || declaring.isAnonymous())
0899: flags |= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT;
0900: } catch (JavaModelException exception) {
0901: JavaPlugin.log(exception);
0902: }
0903: final String description = members.length == 1 ? Messages
0904: .format(
0905: RefactoringCoreMessages.MoveStaticMembersProcessor_description_descriptor_short_multi,
0906: members[0].getElementName())
0907: : RefactoringCoreMessages.MoveMembersRefactoring_move_members;
0908: final JDTRefactoringDescriptorComment comment = new JDTRefactoringDescriptorComment(
0909: project, this , header);
0910: comment
0911: .addSetting(Messages
0912: .format(
0913: RefactoringCoreMessages.MoveStaticMembersProcessor_target_element_pattern,
0914: JavaElementLabels
0915: .getElementLabel(
0916: fDestinationType,
0917: JavaElementLabels.ALL_FULLY_QUALIFIED)));
0918: final MoveStaticMembersDescriptor descriptor = new MoveStaticMembersDescriptor();
0919: descriptor.setProject(project);
0920: descriptor.setDescription(description);
0921: descriptor.setComment(comment.asString());
0922: descriptor.setFlags(flags);
0923: descriptor.setDestinationType(fDestinationType);
0924: descriptor.setKeepOriginal(fDelegateUpdating);
0925: descriptor.setDeprecateDelegate(fDelegateDeprecation);
0926: descriptor.setMembers(members);
0927: fChange = new DynamicValidationRefactoringChange(
0928: descriptor,
0929: RefactoringCoreMessages.MoveMembersRefactoring_move_members);
0930: fTarget = getCuRewrite(fDestinationType.getCompilationUnit());
0931: ITypeBinding targetBinding = getDestinationBinding();
0932: if (targetBinding == null) {
0933: status
0934: .addFatalError(Messages
0935: .format(
0936: RefactoringCoreMessages.MoveMembersRefactoring_compile_errors,
0937: fTarget.getCu().getElementName()));
0938: monitor.done();
0939: return;
0940: }
0941:
0942: try {
0943: Map adjustments = new HashMap();
0944: IMember member = null;
0945: SubProgressMonitor sub = new SubProgressMonitor(monitor, 1,
0946: SubProgressMonitor.SUPPRESS_SUBTASK_LABEL);
0947: sub
0948: .beginTask(
0949: RefactoringCoreMessages.MoveMembersRefactoring_creating,
0950: fMembersToMove.length);
0951: Set rewritten = new HashSet();
0952: for (int index = 0; index < fMembersToMove.length; index++) {
0953: member = fMembersToMove[index];
0954: final MemberVisibilityAdjustor adjustor = new MemberVisibilityAdjustor(
0955: fDestinationType, member);
0956: adjustor.setAdjustments(adjustments);
0957: adjustor.setStatus(status);
0958: adjustor
0959: .setVisibilitySeverity(RefactoringStatus.WARNING);
0960: adjustor.setFailureSeverity(RefactoringStatus.WARNING);
0961: adjustor.setRewrite(fSource.getASTRewrite(), fSource
0962: .getRoot());
0963: adjustor.adjustVisibility(new NullProgressMonitor());
0964:
0965: if (fDelegateUpdating
0966: && isDelegateCreationAvailable(member)) {
0967: // Add a visibility adjustment so the moved member
0968: // will be visible from within the delegate
0969: ModifierKeyword threshold = adjustor
0970: .getVisibilityThreshold(member,
0971: fDestinationType,
0972: new NullProgressMonitor());
0973: IncomingMemberVisibilityAdjustment adjustment = (IncomingMemberVisibilityAdjustment) adjustments
0974: .get(member);
0975: ModifierKeyword kw = (adjustment != null) ? adjustment
0976: .getKeyword()
0977: : ModifierKeyword.fromFlagValue(JdtFlags
0978: .getVisibilityCode(member));
0979: if (MemberVisibilityAdjustor.hasLowerVisibility(kw,
0980: threshold)) {
0981: adjustments
0982: .put(
0983: member,
0984: new MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment(
0985: member,
0986: threshold,
0987: RefactoringStatus
0988: .createWarningStatus(
0989: Messages
0990: .format(
0991: MemberVisibilityAdjustor
0992: .getMessage(member),
0993: new String[] {
0994: MemberVisibilityAdjustor
0995: .getLabel(member),
0996: MemberVisibilityAdjustor
0997: .getLabel(threshold) }),
0998: JavaStatusContext
0999: .create(member))));
1000: }
1001: }
1002:
1003: // Check if destination type is visible from references ->
1004: // error message if not (for example, when moving into a private type)
1005: status.merge(checkMovedMemberAvailability(member,
1006: new SubProgressMonitor(sub, 1)));
1007: // Put rewrite info into code and into status
1008: for (final Iterator iterator = rewritten.iterator(); iterator
1009: .hasNext();) {
1010: adjustments.remove(iterator.next());
1011: }
1012: rewritten.addAll(adjustments.keySet());
1013: adjustor.rewriteVisibility(new NullProgressMonitor());
1014: }
1015:
1016: // First update references in moved members, in order to extract the
1017: // source.
1018: String[] memberSources = getUpdatedMemberSource(status,
1019: fMemberDeclarations, targetBinding);
1020: monitor.worked(1);
1021: if (status.hasFatalError())
1022: return;
1023:
1024: final RefactoringSearchEngine2 engine = new RefactoringSearchEngine2();
1025: engine.setPattern(fMembersToMove,
1026: IJavaSearchConstants.ALL_OCCURRENCES);
1027: engine
1028: .setGranularity(RefactoringSearchEngine2.GRANULARITY_COMPILATION_UNIT);
1029: engine.setFiltering(true, true);
1030: engine.setScope(RefactoringScopeFactory
1031: .create(fMembersToMove));
1032: engine.setStatus(status);
1033: engine.searchPattern(new NullProgressMonitor());
1034: ICompilationUnit[] units = engine
1035: .getAffectedCompilationUnits();
1036: modifiedCus.addAll(Arrays.asList(units));
1037: final MemberVisibilityAdjustor adjustor = new MemberVisibilityAdjustor(
1038: fDestinationType, fDestinationType);
1039: sub = new SubProgressMonitor(monitor, 1);
1040: sub
1041: .beginTask(
1042: RefactoringCoreMessages.MoveMembersRefactoring_creating,
1043: units.length);
1044: for (int index = 0; index < units.length; index++) {
1045: ICompilationUnit unit = units[index];
1046: CompilationUnitRewrite rewrite = getCuRewrite(unit);
1047: adjustor.setRewrites(Collections.singletonMap(unit,
1048: rewrite));
1049: adjustor.setAdjustments(adjustments);
1050: adjustor.rewriteVisibility(unit,
1051: new SubProgressMonitor(sub, 1));
1052: ReferenceAnalyzer analyzer = new ReferenceAnalyzer(
1053: rewrite, fMemberBindings, targetBinding,
1054: fSourceBinding);
1055: rewrite.getRoot().accept(analyzer);
1056: status.merge(analyzer.getStatus());
1057: if (status.hasFatalError()) {
1058: fChange = null;
1059: return;
1060: }
1061: if (!(fSource.getCu().equals(unit) || fTarget.getCu()
1062: .equals(unit)))
1063: fChange.add(rewrite.createChange());
1064: }
1065: status
1066: .merge(moveMembers(fMemberDeclarations,
1067: memberSources));
1068: fChange.add(fSource.createChange());
1069: modifiedCus.add(fSource.getCu());
1070: if (!fSource.getCu().equals(fTarget.getCu())) {
1071: fChange.add(fTarget.createChange());
1072: modifiedCus.add(fTarget.getCu());
1073: }
1074: monitor.worked(1);
1075: } catch (BadLocationException exception) {
1076: JavaPlugin.log(exception);
1077: }
1078: }
1079:
1080: private CompilationUnitRewrite getCuRewrite(ICompilationUnit unit) {
1081: if (fSource.getCu().equals(unit))
1082: return fSource;
1083: if (fTarget != null && fTarget.getCu().equals(unit))
1084: return fTarget;
1085: return new CompilationUnitRewrite(unit);
1086: }
1087:
1088: private ITypeBinding getDestinationBinding()
1089: throws JavaModelException {
1090: ASTNode node = NodeFinder.perform(fTarget.getRoot(),
1091: fDestinationType.getNameRange());
1092: if (!(node instanceof SimpleName))
1093: return null;
1094: IBinding binding = ((SimpleName) node).resolveBinding();
1095: if (!(binding instanceof ITypeBinding))
1096: return null;
1097: return (ITypeBinding) binding;
1098: }
1099:
1100: private IBinding[] getMemberBindings() throws JavaModelException {
1101: IBinding[] result = new IBinding[fMembersToMove.length];
1102: for (int i = 0; i < fMembersToMove.length; i++) {
1103: IMember member = fMembersToMove[i];
1104: SimpleName name = (SimpleName) NodeFinder.perform(fSource
1105: .getRoot(), member.getNameRange());
1106: result[i] = name.resolveBinding();
1107: }
1108: return result;
1109: }
1110:
1111: private String[] getUpdatedMemberSource(RefactoringStatus status,
1112: BodyDeclaration[] members, ITypeBinding target)
1113: throws CoreException, BadLocationException {
1114: List typeRefs = new ArrayList();
1115: boolean targetNeedsSourceImport = false;
1116: boolean isSourceNotTarget = fSource != fTarget;
1117: Set exclude = new HashSet();
1118: for (int i = 0; i < members.length; i++) {
1119: BodyDeclaration declaration = members[i];
1120: if (declaration instanceof AbstractTypeDeclaration) {
1121: AbstractTypeDeclaration type = (AbstractTypeDeclaration) declaration;
1122: ITypeBinding binding = type.resolveBinding();
1123: if (binding != null)
1124: exclude.add(binding);
1125: } else if (declaration instanceof MethodDeclaration) {
1126: MethodDeclaration method = (MethodDeclaration) declaration;
1127: IMethodBinding binding = method.resolveBinding();
1128: if (binding != null)
1129: exclude.add(binding);
1130: } else if (declaration instanceof FieldDeclaration) {
1131: FieldDeclaration field = (FieldDeclaration) declaration;
1132: for (final Iterator iterator = field.fragments()
1133: .iterator(); iterator.hasNext();) {
1134: VariableDeclarationFragment fragment = (VariableDeclarationFragment) iterator
1135: .next();
1136: IVariableBinding binding = fragment
1137: .resolveBinding();
1138: if (binding != null)
1139: exclude.add(binding);
1140: }
1141: }
1142: }
1143: for (int i = 0; i < members.length; i++) {
1144: BodyDeclaration declaration = members[i];
1145: if (isSourceNotTarget)
1146: typeRefs.addAll(TypeReferenceFinder
1147: .perform(declaration));
1148: MovedMemberAnalyzer analyzer = new MovedMemberAnalyzer(
1149: fSource, fMemberBindings, fSourceBinding, target);
1150: declaration.accept(analyzer);
1151: ImportRewriteUtil.addImports(fTarget, declaration,
1152: new HashMap(), new HashMap(), exclude, false);
1153: if (getDeclaringType().isInterface()
1154: && !fDestinationType.isInterface()) {
1155: if (declaration instanceof FieldDeclaration) {
1156: FieldDeclaration fieldDecl = (FieldDeclaration) declaration;
1157: int psfModifiers = Modifier.PUBLIC
1158: | Modifier.STATIC | Modifier.FINAL;
1159: if ((fieldDecl.getModifiers() & psfModifiers) != psfModifiers) {
1160: ModifierRewrite.create(fSource.getASTRewrite(),
1161: fieldDecl).setModifiers(psfModifiers,
1162: null);
1163: }
1164: } else if (declaration instanceof AbstractTypeDeclaration) {
1165: AbstractTypeDeclaration typeDecl = (AbstractTypeDeclaration) declaration;
1166: int psModifiers = Modifier.PUBLIC | Modifier.STATIC;
1167: if ((typeDecl.getModifiers() & psModifiers) != psModifiers) {
1168: ModifierRewrite.create(fSource.getASTRewrite(),
1169: typeDecl).setModifiers(
1170: typeDecl.getModifiers() | psModifiers,
1171: null);
1172: }
1173: }
1174: }
1175: ITrackedNodePosition trackedPosition = fSource
1176: .getASTRewrite().track(declaration);
1177: declaration.setProperty(TRACKED_POSITION_PROPERTY,
1178: trackedPosition);
1179: targetNeedsSourceImport |= analyzer
1180: .targetNeedsSourceImport();
1181: status.merge(analyzer.getStatus());
1182: }
1183: // Adjust imports
1184: if (targetNeedsSourceImport && isSourceNotTarget) {
1185: fTarget.getImportRewrite().addImport(fSourceBinding);
1186: }
1187: if (isSourceNotTarget) {
1188: for (Iterator iter = typeRefs.iterator(); iter.hasNext();) {
1189: ITypeBinding binding = (ITypeBinding) iter.next();
1190: fTarget.getImportRewrite().addImport(binding);
1191: }
1192: }
1193: // extract updated members
1194: String[] updatedMemberSources = new String[members.length];
1195: IDocument document = new Document(fSource.getCu().getBuffer()
1196: .getContents());
1197: TextEdit edit = fSource.getASTRewrite().rewriteAST(document,
1198: fSource.getCu().getJavaProject().getOptions(true));
1199: edit.apply(document, TextEdit.UPDATE_REGIONS);
1200: for (int i = 0; i < members.length; i++) {
1201: updatedMemberSources[i] = getUpdatedMember(document,
1202: members[i]);
1203: }
1204: fSource.clearASTRewrite();
1205: return updatedMemberSources;
1206: }
1207:
1208: private String getUpdatedMember(IDocument document,
1209: BodyDeclaration declaration) throws BadLocationException {
1210: ITrackedNodePosition trackedPosition = (ITrackedNodePosition) declaration
1211: .getProperty(TRACKED_POSITION_PROPERTY);
1212: return Strings.trimIndentation(document.get(trackedPosition
1213: .getStartPosition(), trackedPosition.getLength()),
1214: fPreferences.tabWidth, fPreferences.indentWidth, false);
1215: }
1216:
1217: private RefactoringStatus moveMembers(BodyDeclaration[] members,
1218: String[] sources) throws CoreException {
1219: RefactoringStatus result = new RefactoringStatus();
1220: AbstractTypeDeclaration destination = (AbstractTypeDeclaration) ASTNodes
1221: .getParent(NodeFinder.perform(fTarget.getRoot(),
1222: fDestinationType.getNameRange()),
1223: AbstractTypeDeclaration.class);
1224: ListRewrite containerRewrite = fTarget.getASTRewrite()
1225: .getListRewrite(destination,
1226: destination.getBodyDeclarationsProperty());
1227:
1228: TextEditGroup delete = fSource
1229: .createGroupDescription(RefactoringCoreMessages.MoveMembersRefactoring_deleteMembers);
1230: TextEditGroup add = fTarget
1231: .createGroupDescription(RefactoringCoreMessages.MoveMembersRefactoring_addMembers);
1232: for (int i = 0; i < members.length; i++) {
1233: BodyDeclaration declaration = members[i];
1234: ASTNode removeImportsOf = null;
1235: boolean addedDelegate = false;
1236:
1237: if (fDelegateUpdating) {
1238: if (declaration instanceof MethodDeclaration) {
1239:
1240: DelegateMethodCreator creator = new DelegateMethodCreator();
1241: creator.setDeclaration(declaration);
1242: creator.setDeclareDeprecated(fDelegateDeprecation);
1243: creator.setSourceRewrite(fSource);
1244: creator.setCopy(false);
1245: creator.setNewLocation(getDestinationBinding());
1246: creator.prepareDelegate();
1247: creator.createEdit();
1248:
1249: removeImportsOf = ((MethodDeclaration) declaration)
1250: .getBody();
1251: addedDelegate = true;
1252: }
1253: if (declaration instanceof FieldDeclaration) {
1254:
1255: // Note: this FieldDeclaration only has one fragment (@see #getASTMembers(RefactoringStatus))
1256: final VariableDeclarationFragment frag = (VariableDeclarationFragment) ((FieldDeclaration) declaration)
1257: .fragments().get(0);
1258:
1259: if (!Modifier.isFinal(declaration.getModifiers())) {
1260: // Don't create a delegate for non-final fields
1261: result
1262: .addInfo(
1263: Messages
1264: .format(
1265: RefactoringCoreMessages.DelegateCreator_cannot_create_field_delegate_not_final,
1266: frag.getName()),
1267: null);
1268: } else if (frag.getInitializer() == null) {
1269: // Don't create a delegate without an initializer.
1270: result
1271: .addInfo(
1272: Messages
1273: .format(
1274: RefactoringCoreMessages.DelegateCreator_cannot_create_field_delegate_no_initializer,
1275: frag.getName()),
1276: null);
1277: } else {
1278: DelegateFieldCreator creator = new DelegateFieldCreator();
1279: creator.setDeclaration(declaration);
1280: creator
1281: .setDeclareDeprecated(fDelegateDeprecation);
1282: creator.setSourceRewrite(fSource);
1283: creator.setCopy(false);
1284: creator.setNewLocation(getDestinationBinding());
1285: creator.prepareDelegate();
1286: creator.createEdit();
1287:
1288: removeImportsOf = frag.getInitializer();
1289: addedDelegate = true;
1290: }
1291: }
1292: if (declaration instanceof AbstractTypeDeclaration) {
1293: result
1294: .addInfo(
1295: Messages
1296: .format(
1297: RefactoringCoreMessages.DelegateCreator_cannot_create_delegate_for_type,
1298: ((AbstractTypeDeclaration) declaration)
1299: .getName()
1300: .getIdentifier()),
1301: null);
1302: }
1303: }
1304:
1305: if (!addedDelegate) {
1306: fSource.getASTRewrite().remove(declaration, delete);
1307: removeImportsOf = declaration;
1308: }
1309:
1310: if (removeImportsOf != null && fSource != fTarget)
1311: fSource.getImportRemover().registerRemovedNode(
1312: removeImportsOf);
1313:
1314: ASTNode node = fTarget.getASTRewrite()
1315: .createStringPlaceholder(sources[i],
1316: declaration.getNodeType());
1317: List container = containerRewrite.getRewrittenList();
1318: int insertionIndex = ASTNodes.getInsertionIndex(
1319: (BodyDeclaration) node, container);
1320: containerRewrite.insertAt(node, insertionIndex, add);
1321: }
1322: return result;
1323: }
1324:
1325: private BodyDeclaration[] getASTMembers(RefactoringStatus status)
1326: throws JavaModelException {
1327: BodyDeclaration[] result = new BodyDeclaration[fMembersToMove.length];
1328: for (int i = 0; i < fMembersToMove.length; i++) {
1329: IMember member = fMembersToMove[i];
1330: ASTNode node = NodeFinder.perform(fSource.getRoot(), member
1331: .getNameRange());
1332: result[i] = (BodyDeclaration) ASTNodes.getParent(node,
1333: BodyDeclaration.class);
1334:
1335: //Fix for bug 42383: exclude multiple VariableDeclarationFragments ("int a=1, b=2")
1336: //ReferenceAnalyzer#visit(FieldDeclaration node) depends on fragments().size() != 1 !
1337: if (result[i] instanceof FieldDeclaration
1338: && ((FieldDeclaration) result[i]).fragments()
1339: .size() != 1) {
1340: status
1341: .addFatalError(RefactoringCoreMessages.MoveMembersRefactoring_multi_var_fields);
1342: return result;
1343: }
1344:
1345: }
1346:
1347: //Sorting members is important for field declarations referring to previous fields.
1348: Arrays.sort(result, new Comparator() {
1349: public int compare(Object o1, Object o2) {
1350: return ((BodyDeclaration) o1).getStartPosition()
1351: - ((BodyDeclaration) o2).getStartPosition();
1352: }
1353: });
1354: return result;
1355: }
1356:
1357: public RefactoringStatus initialize(
1358: final RefactoringArguments arguments) {
1359: if (arguments instanceof JavaRefactoringArguments) {
1360: final JavaRefactoringArguments extended = (JavaRefactoringArguments) arguments;
1361: String handle = extended
1362: .getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT);
1363: if (handle != null) {
1364: final IJavaElement element = JavaRefactoringDescriptorUtil
1365: .handleToElement(extended.getProject(), handle,
1366: false);
1367: if (element == null
1368: || !element.exists()
1369: || element.getElementType() != IJavaElement.TYPE)
1370: return ScriptableRefactoring
1371: .createInputFatalStatus(
1372: element,
1373: getRefactoring().getName(),
1374: IJavaRefactorings.MOVE_STATIC_MEMBERS);
1375: else {
1376: fDestinationType = (IType) element;
1377: fDestinationTypeName = fDestinationType
1378: .getFullyQualifiedName();
1379: }
1380: } else
1381: return RefactoringStatus
1382: .createFatalErrorStatus(Messages
1383: .format(
1384: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1385: JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT));
1386: final String delegate = extended
1387: .getAttribute(ATTRIBUTE_DELEGATE);
1388: if (delegate != null) {
1389: fDelegateUpdating = Boolean.valueOf(delegate)
1390: .booleanValue();
1391: } else
1392: return RefactoringStatus
1393: .createFatalErrorStatus(Messages
1394: .format(
1395: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1396: ATTRIBUTE_DELEGATE));
1397: final String deprecate = extended
1398: .getAttribute(ATTRIBUTE_DEPRECATE);
1399: if (deprecate != null) {
1400: fDelegateDeprecation = Boolean.valueOf(deprecate)
1401: .booleanValue();
1402: } else
1403: return RefactoringStatus
1404: .createFatalErrorStatus(Messages
1405: .format(
1406: RefactoringCoreMessages.InitializableRefactoring_argument_not_exist,
1407: ATTRIBUTE_DEPRECATE));
1408: int count = 1;
1409: final List elements = new ArrayList();
1410: String attribute = JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
1411: + count;
1412: final RefactoringStatus status = new RefactoringStatus();
1413: while ((handle = extended.getAttribute(attribute)) != null) {
1414: final IJavaElement element = JavaRefactoringDescriptorUtil
1415: .handleToElement(extended.getProject(), handle,
1416: false);
1417: if (element == null || !element.exists())
1418: status
1419: .merge(ScriptableRefactoring
1420: .createInputWarningStatus(
1421: element,
1422: getRefactoring().getName(),
1423: IJavaRefactorings.MOVE_STATIC_MEMBERS));
1424: else
1425: elements.add(element);
1426: count++;
1427: attribute = JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT
1428: + count;
1429: }
1430: fMembersToMove = (IMember[]) elements
1431: .toArray(new IMember[elements.size()]);
1432: if (elements.isEmpty())
1433: return ScriptableRefactoring.createInputFatalStatus(
1434: null, getRefactoring().getName(),
1435: IJavaRefactorings.MOVE_STATIC_MEMBERS);
1436: IJavaProject project = null;
1437: if (fMembersToMove.length > 0)
1438: project = fMembersToMove[0].getJavaProject();
1439: fPreferences = JavaPreferencesSettings
1440: .getCodeGenerationSettings(project);
1441: if (!status.isOK())
1442: return status;
1443: } else
1444: return RefactoringStatus
1445: .createFatalErrorStatus(RefactoringCoreMessages.InitializableRefactoring_inacceptable_arguments);
1446: return new RefactoringStatus();
1447: }
1448:
1449: public boolean canEnableComment() {
1450: return true;
1451: }
1452:
1453: public String getComment() {
1454: return fComment;
1455: }
1456:
1457: public void setComment(String comment) {
1458: fComment = comment;
1459: }
1460:
1461: public String getDelegateUpdatingTitle(boolean plural) {
1462: if (plural)
1463: return RefactoringCoreMessages.DelegateMethodCreator_keep_original_moved_plural;
1464: else
1465: return RefactoringCoreMessages.DelegateMethodCreator_keep_original_moved_singular;
1466: }
1467: }
|