| /******************************************************************************* |
| * Copyright (c) 2000, 2011 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.corext.refactoring.structure; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IResource; |
| |
| import org.eclipse.text.edits.TextEdit; |
| import org.eclipse.text.edits.TextEditGroup; |
| |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.IDocument; |
| |
| import org.eclipse.ltk.core.refactoring.Change; |
| import org.eclipse.ltk.core.refactoring.CompositeChange; |
| import org.eclipse.ltk.core.refactoring.RefactoringDescriptor; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatusContext; |
| import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; |
| import org.eclipse.ltk.core.refactoring.participants.MoveArguments; |
| import org.eclipse.ltk.core.refactoring.participants.MoveParticipant; |
| import org.eclipse.ltk.core.refactoring.participants.MoveProcessor; |
| import org.eclipse.ltk.core.refactoring.participants.ParticipantManager; |
| import org.eclipse.ltk.core.refactoring.participants.RefactoringParticipant; |
| import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker; |
| import org.eclipse.ltk.core.refactoring.participants.SharableParticipants; |
| |
| import org.eclipse.jdt.core.Flags; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.IInitializer; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.IMember; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.ISourceRange; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.ASTVisitor; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.AnnotationTypeDeclaration; |
| import org.eclipse.jdt.core.dom.BodyDeclaration; |
| import org.eclipse.jdt.core.dom.EnumDeclaration; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.IBinding; |
| import org.eclipse.jdt.core.dom.IMethodBinding; |
| import org.eclipse.jdt.core.dom.ITypeBinding; |
| import org.eclipse.jdt.core.dom.IVariableBinding; |
| import org.eclipse.jdt.core.dom.MethodDeclaration; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; |
| import org.eclipse.jdt.core.dom.Name; |
| import org.eclipse.jdt.core.dom.NodeFinder; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.TypeDeclaration; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.rewrite.ITrackedNodePosition; |
| import org.eclipse.jdt.core.dom.rewrite.ImportRewrite.ImportRewriteContext; |
| import org.eclipse.jdt.core.dom.rewrite.ListRewrite; |
| import org.eclipse.jdt.core.refactoring.IJavaRefactorings; |
| import org.eclipse.jdt.core.refactoring.descriptors.JavaRefactoringDescriptor; |
| import org.eclipse.jdt.core.refactoring.descriptors.MoveStaticMembersDescriptor; |
| import org.eclipse.jdt.core.search.IJavaSearchConstants; |
| import org.eclipse.jdt.core.search.IJavaSearchScope; |
| import org.eclipse.jdt.core.search.SearchMatch; |
| import org.eclipse.jdt.core.search.SearchPattern; |
| |
| import org.eclipse.jdt.internal.core.refactoring.descriptors.RefactoringSignatureDescriptorFactory; |
| import org.eclipse.jdt.internal.corext.codemanipulation.CodeGenerationSettings; |
| import org.eclipse.jdt.internal.corext.codemanipulation.ContextSensitiveImportRewriteContext; |
| import org.eclipse.jdt.internal.corext.dom.ASTNodes; |
| import org.eclipse.jdt.internal.corext.dom.ModifierRewrite; |
| import org.eclipse.jdt.internal.corext.refactoring.Checks; |
| import org.eclipse.jdt.internal.corext.refactoring.CollectingSearchRequestor; |
| import org.eclipse.jdt.internal.corext.refactoring.JDTRefactoringDescriptorComment; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringArguments; |
| import org.eclipse.jdt.internal.corext.refactoring.JavaRefactoringDescriptorUtil; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringAvailabilityTester; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringSearchEngine2; |
| import org.eclipse.jdt.internal.corext.refactoring.SearchResultGroup; |
| import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; |
| import org.eclipse.jdt.internal.corext.refactoring.base.ReferencesInBinaryContext; |
| import org.eclipse.jdt.internal.corext.refactoring.changes.DynamicValidationRefactoringChange; |
| import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateFieldCreator; |
| import org.eclipse.jdt.internal.corext.refactoring.delegates.DelegateMethodCreator; |
| import org.eclipse.jdt.internal.corext.refactoring.participants.JavaProcessors; |
| import org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment; |
| import org.eclipse.jdt.internal.corext.refactoring.tagging.IDelegateUpdating; |
| import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; |
| import org.eclipse.jdt.internal.corext.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.JdtFlags; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| import org.eclipse.jdt.internal.corext.util.SearchUtils; |
| import org.eclipse.jdt.internal.corext.util.Strings; |
| |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| import org.eclipse.jdt.ui.refactoring.IRefactoringProcessorIds; |
| |
| import org.eclipse.jdt.internal.ui.JavaPlugin; |
| import org.eclipse.jdt.internal.ui.preferences.JavaPreferencesSettings; |
| import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; |
| |
| |
| public final class MoveStaticMembersProcessor extends MoveProcessor implements IDelegateUpdating { |
| |
| private static final String ATTRIBUTE_DELEGATE="delegate"; //$NON-NLS-1$ |
| private static final String ATTRIBUTE_DEPRECATE="deprecate"; //$NON-NLS-1$ |
| private static final String TRACKED_POSITION_PROPERTY= "MoveStaticMembersProcessor.trackedPosition"; //$NON-NLS-1$ |
| |
| private IMember[] fMembersToMove; |
| private IType fDestinationType; |
| private String fDestinationTypeName; |
| |
| private CodeGenerationSettings fPreferences; |
| private CompositeChange fChange; |
| private CompilationUnitRewrite fSource; |
| private ITypeBinding fSourceBinding; |
| private CompilationUnitRewrite fTarget; |
| private IBinding[] fMemberBindings; |
| private BodyDeclaration[] fMemberDeclarations; |
| private boolean fDelegateUpdating; |
| private boolean fDelegateDeprecation; |
| |
| private static class TypeReferenceFinder extends ASTVisitor { |
| List<IBinding> fResult= new ArrayList<IBinding>(); |
| Set<ITypeBinding> fDefined= new HashSet<ITypeBinding>(); |
| public static List<IBinding> perform(ASTNode root) { |
| TypeReferenceFinder visitor= new TypeReferenceFinder(); |
| root.accept(visitor); |
| return visitor.fResult; |
| } |
| @Override |
| public boolean visit(TypeDeclaration node) { |
| fDefined.add(node.resolveBinding()); |
| return true; |
| } |
| @Override |
| public boolean visit(SimpleName node) { |
| IBinding binding= node.resolveBinding(); |
| if (!(binding instanceof ITypeBinding)) |
| return true; |
| if (!fDefined.contains(binding)) |
| fResult.add(binding); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(AnnotationTypeDeclaration node) { |
| fDefined.add(node.resolveBinding()); |
| return true; |
| } |
| |
| @Override |
| public boolean visit(EnumDeclaration node) { |
| fDefined.add(node.resolveBinding()); |
| return true; |
| } |
| } |
| |
| /** |
| * Creates a new move static members processor. |
| * @param members the members to move, or <code>null</code> if invoked by scripting |
| * @param settings the code generation settings, or <code>null</code> if invoked by scripting |
| */ |
| public MoveStaticMembersProcessor(IMember[] members, CodeGenerationSettings settings) { |
| fMembersToMove= members; |
| fPreferences= settings; |
| fDelegateUpdating= false; |
| fDelegateDeprecation= true; |
| } |
| |
| public MoveStaticMembersProcessor(JavaRefactoringArguments arguments, RefactoringStatus status) { |
| fDelegateUpdating= false; |
| fDelegateDeprecation= true; |
| RefactoringStatus initializeStatus= initialize(arguments); |
| status.merge(initializeStatus); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public boolean isApplicable() throws CoreException { |
| return RefactoringAvailabilityTester.isMoveStaticMembersAvailable(fMembersToMove); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public Object[] getElements() { |
| Object[] result= new Object[fMembersToMove.length]; |
| System.arraycopy(fMembersToMove, 0, result, 0, fMembersToMove.length); |
| return result; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public String getIdentifier() { |
| return IRefactoringProcessorIds.MOVE_STATIC_MEMBERS_PROCESSOR; |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public RefactoringParticipant[] loadParticipants(RefactoringStatus status, SharableParticipants sharedParticipants) throws CoreException { |
| List<MoveParticipant> result= new ArrayList<MoveParticipant>(); |
| MoveArguments args= new MoveArguments(fDestinationType, true); |
| String[] natures= JavaProcessors.computeAffectedNaturs(fMembersToMove); |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| IMember member= fMembersToMove[i]; |
| result.addAll(Arrays.asList(ParticipantManager.loadMoveParticipants( |
| status, this, member, args, natures, sharedParticipants))); |
| } |
| return result.toArray(new RefactoringParticipant[result.size()]); |
| } |
| |
| //------------------- IDelegateUpdating ---------------------- |
| |
| public boolean canEnableDelegateUpdating() { |
| try { |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| if (isDelegateCreationAvailable(fMembersToMove[i])) |
| return true; |
| } |
| } catch (JavaModelException e) { |
| return false; |
| } |
| return false; |
| } |
| |
| private boolean isDelegateCreationAvailable(IMember member) throws JavaModelException { |
| if (member instanceof IMethod) |
| return true; |
| if (member instanceof IField && RefactoringAvailabilityTester.isDelegateCreationAvailable(((IField)member))) |
| return true; |
| return false; |
| } |
| |
| public boolean getDelegateUpdating() { |
| return fDelegateUpdating; |
| } |
| |
| public void setDelegateUpdating(boolean updating) { |
| fDelegateUpdating= updating; |
| } |
| |
| public boolean getDeprecateDelegates() { |
| return fDelegateDeprecation; |
| } |
| |
| public void setDeprecateDelegates(boolean deprecate) { |
| fDelegateDeprecation= deprecate; |
| } |
| |
| @Override |
| public String getProcessorName() { |
| return RefactoringCoreMessages.MoveMembersRefactoring_Move_Members; |
| } |
| |
| public IType getDestinationType() { |
| return fDestinationType; |
| } |
| |
| public void setDestinationTypeFullyQualifiedName(String fullyQualifiedTypeName) throws JavaModelException { |
| Assert.isNotNull(fullyQualifiedTypeName); |
| fDestinationType= resolveType(fullyQualifiedTypeName); |
| //workaround for bug 36032: IJavaProject#findType(..) doesn't find secondary type |
| fDestinationTypeName= fullyQualifiedTypeName; |
| } |
| |
| public IMember[] getMembersToMove() { |
| return fMembersToMove; |
| } |
| |
| public IType getDeclaringType() { |
| //all methods declared in same type - checked in precondition |
| return fMembersToMove[0].getDeclaringType(); //index safe - checked in areAllMoveable() |
| } |
| |
| private IType resolveType(String qualifiedTypeName) throws JavaModelException{ |
| IType type= getDeclaringType().getJavaProject().findType(qualifiedTypeName); |
| if (type == null) |
| type= getDeclaringType().getJavaProject().findType(getDeclaringType().getPackageFragment().getElementName(), qualifiedTypeName); |
| return type; |
| } |
| |
| //---- Activation checking ------------------------------------ |
| |
| @Override |
| public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException { |
| try { |
| pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, 1); |
| RefactoringStatus result= new RefactoringStatus(); |
| result.merge(checkDeclaringType()); |
| pm.worked(1); |
| if (result.hasFatalError()) |
| return result; |
| |
| fSource= new CompilationUnitRewrite(fMembersToMove[0].getCompilationUnit()); |
| fSourceBinding= (ITypeBinding)((SimpleName)NodeFinder.perform(fSource.getRoot(), fMembersToMove[0].getDeclaringType().getNameRange())).resolveBinding(); |
| fMemberBindings= getMemberBindings(); |
| if (fSourceBinding == null || hasUnresolvedMemberBinding()) { |
| result.addFatalError(Messages.format( |
| RefactoringCoreMessages.MoveMembersRefactoring_compile_errors, |
| BasicElementLabels.getFileName(fSource.getCu()))); |
| } |
| fMemberDeclarations= getASTMembers(result); |
| return result; |
| } finally { |
| pm.done(); |
| } |
| } |
| |
| private boolean hasUnresolvedMemberBinding() { |
| for (int i= 0; i < fMemberBindings.length; i++) { |
| if (fMemberBindings[i] == null) |
| return true; |
| } |
| return false; |
| } |
| |
| private RefactoringStatus checkDeclaringType(){ |
| IType declaringType= getDeclaringType(); |
| |
| if (declaringType.getFullyQualifiedName('.').equals("java.lang.Object")) //$NON-NLS-1$ |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_Object); |
| |
| if (declaringType.isBinary()) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_binary); |
| |
| if (declaringType.isReadOnly()) |
| return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.MoveMembersRefactoring_read_only); |
| |
| return null; |
| } |
| |
| //---- Input checking ------------------------------------ |
| |
| @Override |
| public RefactoringStatus checkFinalConditions(IProgressMonitor pm, CheckConditionsContext context) throws CoreException { |
| fTarget= null; |
| try { |
| pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, 10); |
| |
| RefactoringStatus result= new RefactoringStatus(); |
| |
| fSource.clearASTAndImportRewrites(); |
| |
| result.merge(checkDestinationType()); |
| if (result.hasFatalError()) |
| return result; |
| |
| result.merge(checkDestinationInsideTypeToMove()); |
| if (result.hasFatalError()) |
| return result; |
| |
| result.merge(MemberCheckUtil.checkMembersInDestinationType(fMembersToMove, fDestinationType)); |
| if (result.hasFatalError()) |
| return result; |
| |
| result.merge(checkNativeMovedMethods(new SubProgressMonitor(pm, 1))); |
| |
| if (result.hasFatalError()) |
| return result; |
| |
| List<ICompilationUnit> modifiedCus= new ArrayList<ICompilationUnit>(); |
| createChange(modifiedCus, result, new SubProgressMonitor(pm, 7)); |
| IFile[] changedFiles= getAllFilesToModify(modifiedCus); |
| ResourceChangeChecker checker= (ResourceChangeChecker)context.getChecker(ResourceChangeChecker.class); |
| for (int i= 0; i < changedFiles.length; i++) { |
| checker.getDeltaFactory().change(changedFiles[i]); |
| } |
| |
| return result; |
| } finally { |
| pm.done(); |
| } |
| } |
| |
| private IFile[] getAllFilesToModify(List<ICompilationUnit> modifiedCus) { |
| Set<IResource> result= new HashSet<IResource>(); |
| IResource resource= fDestinationType.getCompilationUnit().getResource(); |
| result.add(resource); |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| resource= fMembersToMove[i].getCompilationUnit().getResource(); |
| if (resource != null) |
| result.add(resource); |
| } |
| for (Iterator<ICompilationUnit> iter= modifiedCus.iterator(); iter.hasNext();) { |
| ICompilationUnit unit= iter.next(); |
| if (unit.getResource() != null) |
| result.add(unit.getResource()); |
| } |
| return result.toArray(new IFile[result.size()]); |
| } |
| |
| private RefactoringStatus checkDestinationType() throws JavaModelException { |
| if (fDestinationType == null){ |
| String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_not_found, BasicElementLabels.getJavaElementName(fDestinationTypeName)); |
| return RefactoringStatus.createFatalErrorStatus(message); |
| } |
| |
| if (fDestinationType.equals(getDeclaringType())){ |
| String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_same, |
| JavaElementUtil.createSignature(fDestinationType)); |
| return RefactoringStatus.createFatalErrorStatus(message); |
| } |
| |
| if (! fDestinationType.exists()){ |
| String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_not_exist, |
| JavaElementUtil.createSignature(fDestinationType)); |
| return RefactoringStatus.createFatalErrorStatus(message); |
| } |
| |
| if (fDestinationType.isBinary()){ |
| String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_dest_binary, |
| JavaElementUtil.createSignature(fDestinationType)); |
| return RefactoringStatus.createFatalErrorStatus(message); |
| } |
| |
| RefactoringStatus result= new RefactoringStatus(); |
| |
| if (fDestinationType.isInterface() && ! getDeclaringType().isInterface()) |
| result.merge(checkFieldsForInterface()); |
| if (result.hasFatalError()) |
| return result; |
| |
| // no checking required for moving interface fields to classes |
| |
| if (! (JdtFlags.isStatic(fDestinationType) || fDestinationType.getDeclaringType() == null)){ |
| String message= RefactoringCoreMessages.MoveMembersRefactoring_static_declaration; |
| result.addError(message); |
| } |
| |
| return result; |
| } |
| |
| private RefactoringStatus checkDestinationInsideTypeToMove() throws JavaModelException { |
| RefactoringStatus result= new RefactoringStatus(); |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| if (! (fMembersToMove[i] instanceof IType)) |
| continue; |
| IType type= (IType) fMembersToMove[i]; |
| if (fDestinationType.equals(type) || JavaElementUtil.isAncestorOf(type, fDestinationType)) { |
| String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_inside, |
| new String[] { getQualifiedTypeLabel(type), getQualifiedTypeLabel(fDestinationType)}); |
| RefactoringStatusContext context= JavaStatusContext.create(fDestinationType.getCompilationUnit(), fDestinationType.getNameRange()); |
| result.addFatalError(message, context); |
| return result; |
| } |
| } |
| return result; |
| } |
| |
| private RefactoringStatus checkFieldsForInterface() throws JavaModelException { |
| //could be more clever and make field final if it is only written once... |
| RefactoringStatus result= new RefactoringStatus(); |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| if (! canMoveToInterface(fMembersToMove[i])) { |
| String message= RefactoringCoreMessages.MoveMembersRefactoring_only_public_static; |
| result.addError(message, JavaStatusContext.create(fMembersToMove[i])); |
| } |
| } |
| return result; |
| } |
| |
| private boolean canMoveToInterface(IMember member) throws JavaModelException { |
| int flags= member.getFlags(); |
| switch (member.getElementType()) { |
| case IJavaElement.FIELD: |
| if (!(Flags.isPublic(flags) && Flags.isStatic(flags) && Flags.isFinal(flags))) |
| return false; |
| if (Flags.isEnum(flags)) |
| return false; |
| VariableDeclarationFragment declaration= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) member, fSource.getRoot()); |
| if (declaration != null) |
| return declaration.getInitializer() != null; |
| return false; |
| case IJavaElement.TYPE: { |
| IType type= (IType) member; |
| if (type.isInterface() && !Checks.isTopLevel(type)) |
| return true; |
| return Flags.isPublic(flags) && Flags.isStatic(flags); |
| } |
| default: |
| return false; |
| } |
| } |
| |
| private RefactoringStatus checkMovedMemberAvailability(IMember memberToMove, IProgressMonitor pm) throws JavaModelException{ |
| RefactoringStatus result= new RefactoringStatus(); |
| if (memberToMove instanceof IType) { // recursively check accessibility of member type's members |
| IJavaElement[] typeMembers= ((IType) memberToMove).getChildren(); |
| pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, typeMembers.length + 1); |
| for (int i= 0; i < typeMembers.length; i++) { |
| if (typeMembers[i] instanceof IInitializer) |
| pm.worked(1); |
| else |
| result.merge(checkMovedMemberAvailability((IMember) typeMembers[i], new SubProgressMonitor(pm, 1))); |
| } |
| } else { |
| pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, 1); |
| } |
| |
| IType[] blindAccessorTypes= getTypesNotSeeingMovedMember(memberToMove, new SubProgressMonitor(pm, 1), result); |
| for (int k= 0; k < blindAccessorTypes.length; k++) { |
| String message= createNonAccessibleMemberMessage(memberToMove, blindAccessorTypes[k],/*moved*/true); |
| result.addError(message, JavaStatusContext.create(memberToMove)); |
| } |
| pm.done(); |
| return result; |
| } |
| |
| private IType[] getTypesNotSeeingMovedMember(IMember member, IProgressMonitor pm, RefactoringStatus status) throws JavaModelException { |
| if (JdtFlags.isPublic(member) && JdtFlags.isPublic(fDestinationType)) |
| return new IType[0]; |
| |
| HashSet<IType> blindAccessorTypes= new HashSet<IType>(); // referencing, but access to destination type illegal |
| SearchResultGroup[] references= getReferences(member, new SubProgressMonitor(pm, 1), status); |
| for (int i = 0; i < references.length; i++) { |
| SearchMatch[] searchResults= references[i].getSearchResults(); |
| for (int k= 0; k < searchResults.length; k++) { |
| SearchMatch searchResult= searchResults[k]; |
| IJavaElement element= SearchUtils.getEnclosingJavaElement(searchResult); |
| IType type= (IType) element.getAncestor(IJavaElement.TYPE); |
| if (type != null //reference can e.g. be an import declaration |
| && ! blindAccessorTypes.contains(type) |
| && ! isWithinMemberToMove(searchResult) |
| && !isVisibleFrom(getDestinationType(), type)) { |
| blindAccessorTypes.add(type); |
| } |
| } |
| } |
| |
| if (fDelegateUpdating && isDelegateCreationAvailable(member)) { |
| // ensure moved member is visible from the delegate |
| IType type= member.getDeclaringType(); |
| if (!blindAccessorTypes.contains(type) && !isVisibleFrom(getDestinationType(), type)) |
| blindAccessorTypes.add(type); |
| } |
| |
| return blindAccessorTypes.toArray(new IType[blindAccessorTypes.size()]); |
| } |
| |
| private String createNonAccessibleMemberMessage(IMember member, IType accessingType, boolean moved){ |
| //Non-visibility can have various reasons and always displaying all visibility |
| //flags for all enclosing elements would be too heavy. Context reveals exact cause. |
| IType declaringType= moved ? getDestinationType() : getDeclaringType(); |
| String message; |
| switch (member.getElementType()){ |
| case IJavaElement.FIELD: { |
| if (moved) |
| message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_moved_field, |
| new String[]{JavaElementUtil.createFieldSignature((IField)member), |
| getQualifiedTypeLabel(accessingType), |
| getQualifiedTypeLabel(declaringType)}); |
| else |
| message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_accessed_field, |
| new String[]{JavaElementUtil.createFieldSignature((IField)member), |
| getQualifiedTypeLabel(accessingType)}); |
| return message; |
| } |
| case IJavaElement.METHOD: { |
| if (moved) |
| message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_moved_method, |
| new String[]{JavaElementUtil.createMethodSignature((IMethod)member), |
| getQualifiedTypeLabel(accessingType), |
| getQualifiedTypeLabel(declaringType)}); |
| else |
| message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_accessed_method, |
| new String[]{JavaElementUtil.createMethodSignature((IMethod)member), |
| getQualifiedTypeLabel(accessingType)}); |
| |
| return message; |
| } |
| case IJavaElement.TYPE:{ |
| if (moved) |
| message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_moved_type, |
| new String[]{getQualifiedTypeLabel((IType)member), |
| getQualifiedTypeLabel(accessingType), |
| getQualifiedTypeLabel(declaringType)}); |
| else |
| message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_accessed_type, |
| new String[]{ getQualifiedTypeLabel((IType)member), getQualifiedTypeLabel(accessingType)}); |
| return message; |
| } |
| default: |
| Assert.isTrue(false); |
| return null; |
| } |
| } |
| |
| private String getQualifiedTypeLabel(IType accessingType) { |
| return BasicElementLabels.getJavaCodeString(accessingType.getFullyQualifiedName('.')); |
| } |
| |
| private static SearchResultGroup[] getReferences(IMember member, IProgressMonitor monitor, RefactoringStatus status) throws JavaModelException { |
| final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); |
| engine.setFiltering(true, true); |
| engine.setScope(RefactoringScopeFactory.create(member)); |
| engine.setStatus(status); |
| engine.searchPattern(new SubProgressMonitor(monitor, 1)); |
| return (SearchResultGroup[]) engine.getResults(); |
| } |
| |
| private static boolean isVisibleFrom(IType newMemberDeclaringType, IType accessingType) throws JavaModelException { |
| int memberVisibility= JdtFlags.getVisibilityCode(newMemberDeclaringType); |
| |
| IType declaringType= newMemberDeclaringType.getDeclaringType(); |
| while (declaringType != null) { //get lowest visibility in all parent types of newMemberDeclaringType |
| memberVisibility= JdtFlags.getLowerVisibility( |
| memberVisibility, JdtFlags.getVisibilityCode(declaringType)); |
| declaringType= declaringType.getDeclaringType(); |
| } |
| |
| switch (memberVisibility) { |
| case Modifier.PRIVATE : |
| return isEqualOrEnclosedType(accessingType, newMemberDeclaringType); |
| |
| case Modifier.NONE : |
| return JavaModelUtil.isSamePackage(accessingType.getPackageFragment(), newMemberDeclaringType.getPackageFragment()); |
| |
| case Modifier.PROTECTED : |
| return JavaModelUtil.isSamePackage(accessingType.getPackageFragment(), newMemberDeclaringType.getPackageFragment()) |
| || accessingType.newSupertypeHierarchy(null).contains(newMemberDeclaringType); |
| |
| case Modifier.PUBLIC : |
| return true; |
| |
| default: |
| Assert.isTrue(false); |
| return false; |
| } |
| } |
| |
| private static boolean isEqualOrEnclosedType(IType inner, IType outer) { |
| while (inner != null) { |
| if (inner.equals(outer)) |
| return true; |
| else |
| inner= inner.getDeclaringType(); |
| } |
| return false; |
| } |
| |
| private boolean isWithinMemberToMove(SearchMatch result) throws JavaModelException { |
| ICompilationUnit referenceCU= SearchUtils.getCompilationUnit(result); |
| if (! referenceCU.equals(fSource.getCu())) |
| return false; |
| int referenceStart= result.getOffset(); |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| ISourceRange range= fMembersToMove[i].getSourceRange(); |
| if (range.getOffset() <= referenceStart && range.getOffset() + range.getLength() >= referenceStart) |
| return true; |
| } |
| return false; |
| } |
| |
| private RefactoringStatus checkNativeMovedMethods(IProgressMonitor pm) throws JavaModelException{ |
| pm.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_checking, fMembersToMove.length); |
| RefactoringStatus result= new RefactoringStatus(); |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| if (fMembersToMove[i].getElementType() != IJavaElement.METHOD) |
| continue; |
| if (! JdtFlags.isNative(fMembersToMove[i])) |
| continue; |
| String message= Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_native, |
| JavaElementUtil.createMethodSignature((IMethod)fMembersToMove[i])); |
| result.addWarning(message, JavaStatusContext.create(fMembersToMove[i])); |
| pm.worked(1); |
| } |
| pm.done(); |
| return result; |
| } |
| |
| @Override |
| public Change createChange(IProgressMonitor pm) throws CoreException { |
| pm.done(); |
| return fChange; |
| } |
| |
| private void createChange(List<ICompilationUnit> modifiedCus, RefactoringStatus status, IProgressMonitor monitor) throws CoreException { |
| monitor.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_creating, 5); |
| fChange= new DynamicValidationRefactoringChange(createDescriptor(), RefactoringCoreMessages.MoveMembersRefactoring_move_members); |
| fTarget= getCuRewrite(fDestinationType.getCompilationUnit()); |
| ITypeBinding targetBinding= getDestinationBinding(); |
| if (targetBinding == null) { |
| status.addFatalError(Messages.format(RefactoringCoreMessages.MoveMembersRefactoring_compile_errors, BasicElementLabels.getFileName(fTarget.getCu()))); |
| monitor.done(); |
| return; |
| } |
| |
| try { |
| Map<IMember, IncomingMemberVisibilityAdjustment> adjustments= new HashMap<IMember, IncomingMemberVisibilityAdjustment>(); |
| IMember member= null; |
| SubProgressMonitor sub= new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL); |
| sub.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_creating, fMembersToMove.length); |
| Set<IMember> rewritten= new HashSet<IMember>(); |
| for (int index= 0; index < fMembersToMove.length; index++) { |
| member= fMembersToMove[index]; |
| final MemberVisibilityAdjustor adjustor= new MemberVisibilityAdjustor(fDestinationType, member); |
| adjustor.setAdjustments(adjustments); |
| adjustor.setStatus(status); |
| adjustor.setVisibilitySeverity(RefactoringStatus.WARNING); |
| adjustor.setFailureSeverity(RefactoringStatus.WARNING); |
| adjustor.setRewrite(fSource.getASTRewrite(), fSource.getRoot()); |
| adjustor.adjustVisibility(new NullProgressMonitor()); |
| |
| if (fDelegateUpdating && isDelegateCreationAvailable(member)) { |
| // Add a visibility adjustment so the moved member |
| // will be visible from within the delegate |
| ModifierKeyword threshold= adjustor.getVisibilityThreshold(member, fDestinationType, new NullProgressMonitor()); |
| IncomingMemberVisibilityAdjustment adjustment= adjustments.get(member); |
| ModifierKeyword kw= adjustment != null ? adjustment.getKeyword() : ModifierKeyword.fromFlagValue(JdtFlags.getVisibilityCode(member)); |
| if (MemberVisibilityAdjustor.hasLowerVisibility(kw, threshold)) { |
| adjustments.put(member, new MemberVisibilityAdjustor.IncomingMemberVisibilityAdjustment(member, threshold, RefactoringStatus.createWarningStatus(Messages.format(MemberVisibilityAdjustor.getMessage(member), new String[] { MemberVisibilityAdjustor.getLabel(member), MemberVisibilityAdjustor.getLabel(threshold)}), JavaStatusContext.create(member)))); |
| } |
| } |
| |
| // Check if destination type is visible from references -> |
| // error message if not (for example, when moving into a private type) |
| status.merge(checkMovedMemberAvailability(member, new SubProgressMonitor(sub, 1))); |
| // Put rewrite info into code and into status |
| for (final Iterator<IMember> iterator= rewritten.iterator(); iterator.hasNext();) { |
| adjustments.remove(iterator.next()); |
| } |
| rewritten.addAll(adjustments.keySet()); |
| adjustor.rewriteVisibility(new NullProgressMonitor()); |
| } |
| |
| // First update references in moved members, in order to extract the |
| // source. |
| String[] memberSources= getUpdatedMemberSource(status, fMemberDeclarations, targetBinding); |
| monitor.worked(1); |
| if (status.hasFatalError()) |
| return; |
| |
| ReferencesInBinaryContext binaryRefs= new ReferencesInBinaryContext(RefactoringCoreMessages.ReferencesInBinaryContext_ref_in_binaries_description_plural); |
| IJavaSearchScope scope= RefactoringScopeFactory.create(fMembersToMove, false); |
| SearchPattern pattern= RefactoringSearchEngine.createOrPattern(fMembersToMove, IJavaSearchConstants.ALL_OCCURRENCES); |
| final HashSet<ICompilationUnit> affectedCompilationUnits= new HashSet<ICompilationUnit>(); |
| |
| CollectingSearchRequestor requestor= new CollectingSearchRequestor(binaryRefs) { |
| private ICompilationUnit fLastCU; |
| @Override |
| public void acceptSearchMatch(SearchMatch match) throws CoreException { |
| if (filterMatch(match)) |
| return; |
| if (match.getAccuracy() == SearchMatch.A_INACCURATE) |
| return; |
| ICompilationUnit unit= SearchUtils.getCompilationUnit(match); |
| if (unit != null && ! unit.equals(fLastCU)) { |
| fLastCU= unit; |
| affectedCompilationUnits.add(unit); |
| } |
| } |
| }; |
| RefactoringSearchEngine.search(pattern, scope, requestor, new NullProgressMonitor(), status); |
| binaryRefs.addErrorIfNecessary(status); |
| ICompilationUnit[] units= affectedCompilationUnits.toArray(new ICompilationUnit[affectedCompilationUnits.size()]); |
| |
| modifiedCus.addAll(Arrays.asList(units)); |
| final MemberVisibilityAdjustor adjustor= new MemberVisibilityAdjustor(fDestinationType, fDestinationType); |
| sub= new SubProgressMonitor(monitor, 1); |
| sub.beginTask(RefactoringCoreMessages.MoveMembersRefactoring_creating, units.length); |
| for (int index= 0; index < units.length; index++) { |
| ICompilationUnit unit= units[index]; |
| CompilationUnitRewrite rewrite= getCuRewrite(unit); |
| adjustor.setRewrites(Collections.singletonMap(unit, rewrite)); |
| adjustor.setAdjustments(adjustments); |
| adjustor.rewriteVisibility(unit, new SubProgressMonitor(sub, 1)); |
| ReferenceAnalyzer analyzer= new ReferenceAnalyzer(rewrite, fMemberBindings, targetBinding, fSourceBinding); |
| rewrite.getRoot().accept(analyzer); |
| status.merge(analyzer.getStatus()); |
| if (status.hasFatalError()) { |
| fChange= null; |
| return; |
| } |
| if (!(fSource.getCu().equals(unit) || fTarget.getCu().equals(unit))) |
| fChange.add(rewrite.createChange(true)); |
| } |
| status.merge(moveMembers(fMemberDeclarations, memberSources)); |
| fChange.add(fSource.createChange(true)); |
| modifiedCus.add(fSource.getCu()); |
| if (!fSource.getCu().equals(fTarget.getCu())) { |
| fChange.add(fTarget.createChange(true)); |
| modifiedCus.add(fTarget.getCu()); |
| } |
| monitor.worked(1); |
| } catch (BadLocationException exception) { |
| JavaPlugin.log(exception); |
| } |
| } |
| |
| private MoveStaticMembersDescriptor createDescriptor() { |
| final IMember[] members= getMembersToMove(); |
| String project= null; |
| final IJavaProject javaProject= getDeclaringType().getJavaProject(); |
| if (javaProject != null) |
| project= javaProject.getElementName(); |
| String header= null; |
| if (members.length == 1) |
| header= Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_descriptor_description_single, new String[] { JavaElementLabels.getElementLabel(members[0], JavaElementLabels.ALL_FULLY_QUALIFIED), getQualifiedTypeLabel(fDestinationType) }); |
| else |
| header= Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_descriptor_description_multi, new String[] { String.valueOf(members.length), getQualifiedTypeLabel(fDestinationType) }); |
| int flags= JavaRefactoringDescriptor.JAR_MIGRATION | JavaRefactoringDescriptor.JAR_REFACTORING | RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE; |
| final IType declaring= members[0].getDeclaringType(); |
| try { |
| if (declaring.isLocal() || declaring.isAnonymous()) |
| flags|= JavaRefactoringDescriptor.JAR_SOURCE_ATTACHMENT; |
| } catch (JavaModelException exception) { |
| JavaPlugin.log(exception); |
| } |
| final String description= members.length == 1 ? Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_description_descriptor_short_multi, BasicElementLabels.getJavaElementName(members[0].getElementName())) : RefactoringCoreMessages.MoveMembersRefactoring_move_members; |
| final JDTRefactoringDescriptorComment comment= new JDTRefactoringDescriptorComment(project, this, header); |
| comment.addSetting(Messages.format(RefactoringCoreMessages.MoveStaticMembersProcessor_target_element_pattern, getQualifiedTypeLabel(fDestinationType))); |
| final MoveStaticMembersDescriptor descriptor= RefactoringSignatureDescriptorFactory.createMoveStaticMembersDescriptor(); |
| descriptor.setProject(project); |
| descriptor.setDescription(description); |
| descriptor.setComment(comment.asString()); |
| descriptor.setFlags(flags); |
| descriptor.setDestinationType(fDestinationType); |
| descriptor.setKeepOriginal(fDelegateUpdating); |
| descriptor.setDeprecateDelegate(fDelegateDeprecation); |
| descriptor.setMembers(members); |
| return descriptor; |
| } |
| |
| private CompilationUnitRewrite getCuRewrite(ICompilationUnit unit) { |
| if (fSource.getCu().equals(unit)) |
| return fSource; |
| if (fTarget != null && fTarget.getCu().equals(unit)) |
| return fTarget; |
| return new CompilationUnitRewrite(unit); |
| } |
| |
| private AbstractTypeDeclaration getDestinationNode() throws JavaModelException { |
| AbstractTypeDeclaration destination= (AbstractTypeDeclaration) |
| ASTNodes.getParent( |
| NodeFinder.perform(fTarget.getRoot(), fDestinationType.getNameRange()), |
| AbstractTypeDeclaration.class); |
| return destination; |
| } |
| |
| private ITypeBinding getDestinationBinding() throws JavaModelException { |
| ASTNode node= NodeFinder.perform(fTarget.getRoot(), fDestinationType.getNameRange()); |
| if (!(node instanceof SimpleName)) |
| return null; |
| IBinding binding= ((SimpleName)node).resolveBinding(); |
| if (!(binding instanceof ITypeBinding)) |
| return null; |
| return (ITypeBinding)binding; |
| } |
| |
| private IBinding[] getMemberBindings() throws JavaModelException { |
| IBinding[] result= new IBinding[fMembersToMove.length]; |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| IMember member= fMembersToMove[i]; |
| SimpleName name= (SimpleName)NodeFinder.perform(fSource.getRoot(), member.getNameRange()); |
| result[i]= name.resolveBinding(); |
| } |
| return result; |
| } |
| |
| private String[] getUpdatedMemberSource(RefactoringStatus status, BodyDeclaration[] members, ITypeBinding target) throws CoreException, BadLocationException { |
| List<IBinding> typeRefs= new ArrayList<IBinding>(); |
| boolean targetNeedsSourceImport= false; |
| boolean isSourceNotTarget= fSource != fTarget; |
| Set<IBinding> exclude= new HashSet<IBinding>(); |
| for (int i= 0; i < members.length; i++) { |
| BodyDeclaration declaration= members[i]; |
| if (declaration instanceof AbstractTypeDeclaration) { |
| AbstractTypeDeclaration type= (AbstractTypeDeclaration) declaration; |
| ITypeBinding binding= type.resolveBinding(); |
| if (binding != null) |
| exclude.add(binding); |
| } else if (declaration instanceof MethodDeclaration) { |
| MethodDeclaration method= (MethodDeclaration) declaration; |
| IMethodBinding binding= method.resolveBinding(); |
| if (binding != null) |
| exclude.add(binding); |
| } else if (declaration instanceof FieldDeclaration) { |
| FieldDeclaration field= (FieldDeclaration) declaration; |
| for (final Iterator<VariableDeclarationFragment> iterator= field.fragments().iterator(); iterator.hasNext();) { |
| VariableDeclarationFragment fragment= iterator.next(); |
| IVariableBinding binding= fragment.resolveBinding(); |
| if (binding != null) |
| exclude.add(binding); |
| } |
| } |
| } |
| ImportRewriteContext context= new ContextSensitiveImportRewriteContext(getDestinationNode(), fTarget.getImportRewrite()); |
| for (int i= 0; i < members.length; i++) { |
| BodyDeclaration declaration= members[i]; |
| if (isSourceNotTarget) |
| typeRefs.addAll(TypeReferenceFinder.perform(declaration)); |
| MovedMemberAnalyzer analyzer= new MovedMemberAnalyzer(fSource, fMemberBindings, fSourceBinding, target); |
| declaration.accept(analyzer); |
| ImportRewriteUtil.addImports(fTarget, context, declaration, new HashMap<Name, String>(), new HashMap<Name, String>(), exclude, false); |
| if (getDeclaringType().isInterface() && !fDestinationType.isInterface()) { |
| if (declaration instanceof FieldDeclaration) { |
| FieldDeclaration fieldDecl= (FieldDeclaration) declaration; |
| int psfModifiers= Modifier.PUBLIC | Modifier.STATIC | Modifier.FINAL; |
| if ((fieldDecl.getModifiers() & psfModifiers) != psfModifiers) { |
| ModifierRewrite.create(fSource.getASTRewrite(), fieldDecl).setModifiers(psfModifiers, null); |
| } |
| } else if (declaration instanceof AbstractTypeDeclaration) { |
| AbstractTypeDeclaration typeDecl= (AbstractTypeDeclaration) declaration; |
| int psModifiers= Modifier.PUBLIC | Modifier.STATIC; |
| if ((typeDecl.getModifiers() & psModifiers) != psModifiers) { |
| ModifierRewrite.create(fSource.getASTRewrite(), typeDecl).setModifiers(typeDecl.getModifiers() | psModifiers, null); |
| } |
| } |
| } |
| ITrackedNodePosition trackedPosition= fSource.getASTRewrite().track(declaration); |
| declaration.setProperty(TRACKED_POSITION_PROPERTY, trackedPosition); |
| targetNeedsSourceImport|= analyzer.targetNeedsSourceImport(); |
| status.merge(analyzer.getStatus()); |
| } |
| // Adjust imports |
| if (targetNeedsSourceImport && isSourceNotTarget) { |
| fTarget.getImportRewrite().addImport(fSourceBinding, context); |
| } |
| if (isSourceNotTarget) { |
| for (Iterator<IBinding> iter= typeRefs.iterator(); iter.hasNext();) { |
| ITypeBinding binding= (ITypeBinding) iter.next(); |
| fTarget.getImportRewrite().addImport(binding, context); |
| } |
| } |
| // extract updated members |
| String[] updatedMemberSources= new String[members.length]; |
| IDocument document= new Document(fSource.getCu().getBuffer().getContents()); |
| TextEdit edit= fSource.getASTRewrite().rewriteAST(document, fSource.getCu().getJavaProject().getOptions(true)); |
| edit.apply(document, TextEdit.UPDATE_REGIONS); |
| for (int i= 0; i < members.length; i++) { |
| updatedMemberSources[i]= getUpdatedMember(document, members[i]); |
| } |
| fSource.clearASTRewrite(); |
| return updatedMemberSources; |
| } |
| |
| private String getUpdatedMember(IDocument document, BodyDeclaration declaration) throws BadLocationException { |
| ITrackedNodePosition trackedPosition= (ITrackedNodePosition) declaration.getProperty(TRACKED_POSITION_PROPERTY); |
| return Strings.trimIndentation(document.get(trackedPosition.getStartPosition(), trackedPosition.getLength()), fPreferences.tabWidth, fPreferences.indentWidth, false); |
| } |
| |
| private RefactoringStatus moveMembers(BodyDeclaration[] members, String[] sources) throws CoreException { |
| RefactoringStatus result= new RefactoringStatus(); |
| AbstractTypeDeclaration destination= getDestinationNode(); |
| ListRewrite containerRewrite= fTarget.getASTRewrite().getListRewrite(destination, destination.getBodyDeclarationsProperty()); |
| |
| TextEditGroup delete= fSource.createGroupDescription(RefactoringCoreMessages.MoveMembersRefactoring_deleteMembers); |
| TextEditGroup add= fTarget.createGroupDescription(RefactoringCoreMessages.MoveMembersRefactoring_addMembers); |
| for (int i= 0; i < members.length; i++) { |
| BodyDeclaration declaration= members[i]; |
| ASTNode removeImportsOf= null; |
| boolean addedDelegate= false; |
| |
| if (fDelegateUpdating) { |
| if (declaration instanceof MethodDeclaration) { |
| |
| DelegateMethodCreator creator= new DelegateMethodCreator(); |
| creator.setDeclaration(declaration); |
| creator.setDeclareDeprecated(fDelegateDeprecation); |
| creator.setSourceRewrite(fSource); |
| creator.setCopy(false); |
| creator.setNewLocation(getDestinationBinding()); |
| creator.prepareDelegate(); |
| creator.createEdit(); |
| |
| removeImportsOf= ((MethodDeclaration) declaration).getBody(); |
| addedDelegate= true; |
| } |
| if (declaration instanceof FieldDeclaration) { |
| |
| // Note: this FieldDeclaration only has one fragment (@see #getASTMembers(RefactoringStatus)) |
| final VariableDeclarationFragment frag= (VariableDeclarationFragment) ((FieldDeclaration) declaration).fragments().get(0); |
| |
| if (!Modifier.isFinal(declaration.getModifiers())) { |
| // Don't create a delegate for non-final fields |
| result.addInfo(Messages.format(RefactoringCoreMessages.DelegateCreator_cannot_create_field_delegate_not_final, BasicElementLabels.getJavaElementName(frag.getName().getIdentifier())), null); |
| } else if (frag.getInitializer() == null) { |
| // Don't create a delegate without an initializer. |
| result.addInfo(Messages.format(RefactoringCoreMessages.DelegateCreator_cannot_create_field_delegate_no_initializer, BasicElementLabels.getJavaElementName(frag.getName().getIdentifier())), null); |
| } else { |
| DelegateFieldCreator creator= new DelegateFieldCreator(); |
| creator.setDeclaration(declaration); |
| creator.setDeclareDeprecated(fDelegateDeprecation); |
| creator.setSourceRewrite(fSource); |
| creator.setCopy(false); |
| creator.setNewLocation(getDestinationBinding()); |
| creator.prepareDelegate(); |
| creator.createEdit(); |
| |
| removeImportsOf= frag.getInitializer(); |
| addedDelegate= true; |
| } |
| } |
| if (declaration instanceof AbstractTypeDeclaration) { |
| result.addInfo(Messages.format(RefactoringCoreMessages.DelegateCreator_cannot_create_delegate_for_type, BasicElementLabels.getJavaElementName(((AbstractTypeDeclaration) declaration).getName().getIdentifier())), |
| null); |
| } |
| } |
| |
| if (!addedDelegate) { |
| fSource.getASTRewrite().remove(declaration, delete); |
| removeImportsOf= declaration; |
| } |
| |
| if (removeImportsOf != null && fSource != fTarget) |
| fSource.getImportRemover().registerRemovedNode(removeImportsOf); |
| |
| ASTNode node= fTarget.getASTRewrite().createStringPlaceholder(sources[i], declaration.getNodeType()); |
| List<BodyDeclaration> container= containerRewrite.getRewrittenList(); |
| int insertionIndex= ASTNodes.getInsertionIndex((BodyDeclaration) node, container); |
| containerRewrite.insertAt(node, insertionIndex, add); |
| } |
| return result; |
| } |
| |
| private BodyDeclaration[] getASTMembers(RefactoringStatus status) throws JavaModelException { |
| BodyDeclaration[] result= new BodyDeclaration[fMembersToMove.length]; |
| for (int i= 0; i < fMembersToMove.length; i++) { |
| IMember member= fMembersToMove[i]; |
| ASTNode node= NodeFinder.perform(fSource.getRoot(), member.getNameRange()); |
| result[i]= (BodyDeclaration)ASTNodes.getParent(node, BodyDeclaration.class); |
| |
| //Fix for bug 42383: exclude multiple VariableDeclarationFragments ("int a=1, b=2") |
| //ReferenceAnalyzer#visit(FieldDeclaration node) depends on fragments().size() != 1 ! |
| if (result[i] instanceof FieldDeclaration |
| && ((FieldDeclaration) result[i]).fragments().size() != 1) { |
| status.addFatalError(RefactoringCoreMessages.MoveMembersRefactoring_multi_var_fields); |
| return result; |
| } |
| |
| } |
| |
| //Sorting members is important for field declarations referring to previous fields. |
| Arrays.sort(result, new Comparator<BodyDeclaration>() { |
| public int compare(BodyDeclaration o1, BodyDeclaration o2) { |
| return o1.getStartPosition() - o2.getStartPosition(); |
| } |
| }); |
| return result; |
| } |
| |
| private RefactoringStatus initialize(JavaRefactoringArguments extended) { |
| String handle= extended.getAttribute(JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT); |
| if (handle != null) { |
| final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false); |
| if (element == null || !element.exists() || element.getElementType() != IJavaElement.TYPE) |
| return JavaRefactoringDescriptorUtil.createInputFatalStatus(element, getProcessorName(), IJavaRefactorings.MOVE_STATIC_MEMBERS); |
| else { |
| fDestinationType= (IType) element; |
| fDestinationTypeName= fDestinationType.getFullyQualifiedName(); |
| } |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, JavaRefactoringDescriptorUtil.ATTRIBUTE_INPUT)); |
| final String delegate= extended.getAttribute(ATTRIBUTE_DELEGATE); |
| if (delegate != null) { |
| fDelegateUpdating= Boolean.valueOf(delegate).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DELEGATE)); |
| final String deprecate= extended.getAttribute(ATTRIBUTE_DEPRECATE); |
| if (deprecate != null) { |
| fDelegateDeprecation= Boolean.valueOf(deprecate).booleanValue(); |
| } else |
| return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.InitializableRefactoring_argument_not_exist, ATTRIBUTE_DEPRECATE)); |
| int count= 1; |
| final List<IJavaElement> elements= new ArrayList<IJavaElement>(); |
| String attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count; |
| final RefactoringStatus status= new RefactoringStatus(); |
| while ((handle= extended.getAttribute(attribute)) != null) { |
| final IJavaElement element= JavaRefactoringDescriptorUtil.handleToElement(extended.getProject(), handle, false); |
| if (element == null || !element.exists()) |
| status.merge(JavaRefactoringDescriptorUtil.createInputWarningStatus(element, getProcessorName(), IJavaRefactorings.MOVE_STATIC_MEMBERS)); |
| else |
| elements.add(element); |
| count++; |
| attribute= JavaRefactoringDescriptorUtil.ATTRIBUTE_ELEMENT + count; |
| } |
| fMembersToMove= elements.toArray(new IMember[elements.size()]); |
| if (elements.isEmpty()) |
| return JavaRefactoringDescriptorUtil.createInputFatalStatus(null, getProcessorName(), IJavaRefactorings.MOVE_STATIC_MEMBERS); |
| IJavaProject project= null; |
| if (fMembersToMove.length > 0) |
| project= fMembersToMove[0].getJavaProject(); |
| fPreferences= JavaPreferencesSettings.getCodeGenerationSettings(project); |
| if (!status.isOK()) |
| return status; |
| return new RefactoringStatus(); |
| } |
| |
| public String getDelegateUpdatingTitle(boolean plural) { |
| if (plural) |
| return RefactoringCoreMessages.DelegateMethodCreator_keep_original_moved_plural_member; |
| else |
| return RefactoringCoreMessages.DelegateMethodCreator_keep_original_moved_singular_member; |
| } |
| } |