| /******************************************************************************* |
| * Copyright (c) 2000, 2006 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.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.SubProgressMonitor; |
| |
| import org.eclipse.ltk.core.refactoring.CategorizedTextEditGroup; |
| import org.eclipse.ltk.core.refactoring.GroupCategory; |
| import org.eclipse.ltk.core.refactoring.GroupCategorySet; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatus; |
| import org.eclipse.ltk.core.refactoring.RefactoringStatusEntry; |
| |
| 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.IMember; |
| import org.eclipse.jdt.core.IMethod; |
| import org.eclipse.jdt.core.IPackageFragment; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.ITypeHierarchy; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.WorkingCopyOwner; |
| import org.eclipse.jdt.core.dom.ASTNode; |
| import org.eclipse.jdt.core.dom.AbstractTypeDeclaration; |
| import org.eclipse.jdt.core.dom.BodyDeclaration; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jdt.core.dom.FieldDeclaration; |
| import org.eclipse.jdt.core.dom.IExtendedModifier; |
| import org.eclipse.jdt.core.dom.Modifier; |
| import org.eclipse.jdt.core.dom.SimpleName; |
| import org.eclipse.jdt.core.dom.Type; |
| import org.eclipse.jdt.core.dom.VariableDeclarationFragment; |
| import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword; |
| import org.eclipse.jdt.core.dom.rewrite.ASTRewrite; |
| import org.eclipse.jdt.core.dom.rewrite.ListRewrite; |
| 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.corext.dom.ModifierRewrite; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringCoreMessages; |
| import org.eclipse.jdt.internal.corext.refactoring.RefactoringScopeFactory; |
| 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.util.JavaModelUtil; |
| import org.eclipse.jdt.internal.corext.util.Messages; |
| import org.eclipse.jdt.internal.corext.util.SearchUtils; |
| |
| import org.eclipse.jdt.ui.JavaElementLabels; |
| |
| /** |
| * Helper class to adjust the visibilities of members with respect to a reference element. |
| * |
| * @since 3.1 |
| */ |
| public final class MemberVisibilityAdjustor { |
| |
| /** |
| * The visibility group category set. |
| * |
| * @since 3.2 |
| */ |
| public static final GroupCategorySet SET_VISIBILITY_ADJUSTMENTS= new GroupCategorySet(new GroupCategory("org.eclipse.jdt.internal.corext.visibilityAdjustments", //$NON-NLS-1$ |
| RefactoringCoreMessages.MemberVisibilityAdjustor_adjustments_name, RefactoringCoreMessages.MemberVisibilityAdjustor_adjustments_description)); |
| |
| /** Description of a member visibility adjustment */ |
| public static class IncomingMemberVisibilityAdjustment implements IVisibilityAdjustment { |
| |
| /** The keyword representing the adjusted visibility */ |
| protected final ModifierKeyword fKeyword; |
| |
| /** The member whose visibility has been adjusted */ |
| protected final IMember fMember; |
| |
| /** Does the visibility adjustment need rewriting? */ |
| protected boolean fNeedsRewriting= true; |
| |
| /** The associated refactoring status */ |
| protected final RefactoringStatus fRefactoringStatus; |
| |
| /** |
| * Creates a new incoming member visibility adjustment. |
| * |
| * @param member the member which is adjusted |
| * @param keyword the keyword representing the adjusted visibility |
| * @param status the associated status, or <code>null</code> |
| */ |
| public IncomingMemberVisibilityAdjustment(final IMember member, final ModifierKeyword keyword, final RefactoringStatus status) { |
| Assert.isNotNull(member); |
| Assert.isTrue(!(member instanceof IInitializer)); |
| Assert.isTrue(isVisibilityKeyword(keyword)); |
| fMember= member; |
| fKeyword= keyword; |
| fRefactoringStatus= status; |
| } |
| |
| /** |
| * Returns the visibility keyword. |
| * |
| * @return the visibility keyword |
| */ |
| public final ModifierKeyword getKeyword() { |
| return fKeyword; |
| } |
| |
| /** |
| * Returns the adjusted member. |
| * |
| * @return the adjusted member |
| */ |
| public final IMember getMember() { |
| return fMember; |
| } |
| |
| /** |
| * Returns the associated refactoring status. |
| * |
| * @return the associated refactoring status |
| */ |
| public final RefactoringStatus getStatus() { |
| return fRefactoringStatus; |
| } |
| |
| /** |
| * Does the visibility adjustment need rewriting? |
| * |
| * @return <code>true</code> if it needs rewriting, <code>false</code> otherwise |
| */ |
| public final boolean needsRewriting() { |
| return fNeedsRewriting; |
| } |
| |
| /** |
| * Rewrites the visibility adjustment. |
| * |
| * @param adjustor the java element visibility adjustor |
| * @param rewrite the AST rewrite to use |
| * @param root the root of the AST used in the rewrite |
| * @param group the text edit group description to use, or <code>null</code> |
| * @param status the refactoring status, or <code>null</code> |
| * @throws JavaModelException if an error occurs |
| */ |
| protected final void rewriteVisibility(final MemberVisibilityAdjustor adjustor, final ASTRewrite rewrite, final CompilationUnit root, final CategorizedTextEditGroup group, final RefactoringStatus status) throws JavaModelException { |
| Assert.isNotNull(adjustor); |
| Assert.isNotNull(rewrite); |
| Assert.isNotNull(root); |
| final int visibility= fKeyword != null ? fKeyword.toFlagValue() : Modifier.NONE; |
| if (fMember instanceof IField && !Flags.isEnum(fMember.getFlags())) { |
| final VariableDeclarationFragment fragment= ASTNodeSearchUtil.getFieldDeclarationFragmentNode((IField) fMember, root); |
| final FieldDeclaration declaration= (FieldDeclaration) fragment.getParent(); |
| if (declaration.fragments().size() == 1) |
| ModifierRewrite.create(rewrite, declaration).setVisibility(visibility, group); |
| else { |
| final VariableDeclarationFragment newFragment= rewrite.getAST().newVariableDeclarationFragment(); |
| newFragment.setName((SimpleName) rewrite.createCopyTarget(fragment.getName())); |
| final FieldDeclaration newDeclaration= rewrite.getAST().newFieldDeclaration(newFragment); |
| newDeclaration.setType((Type) rewrite.createCopyTarget(declaration.getType())); |
| IExtendedModifier extended= null; |
| for (final Iterator iterator= declaration.modifiers().iterator(); iterator.hasNext();) { |
| extended= (IExtendedModifier) iterator.next(); |
| if (extended.isModifier()) { |
| final Modifier modifier= (Modifier) extended; |
| final int flag= modifier.getKeyword().toFlagValue(); |
| if ((flag & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)) != 0) |
| continue; |
| } |
| newDeclaration.modifiers().add(rewrite.createCopyTarget((ASTNode) extended)); |
| } |
| ModifierRewrite.create(rewrite, newDeclaration).setVisibility(visibility, group); |
| final AbstractTypeDeclaration type= (AbstractTypeDeclaration) declaration.getParent(); |
| rewrite.getListRewrite(type, type.getBodyDeclarationsProperty()).insertAfter(newDeclaration, declaration, null); |
| final ListRewrite list= rewrite.getListRewrite(declaration, FieldDeclaration.FRAGMENTS_PROPERTY); |
| list.remove(fragment, group); |
| if (list.getRewrittenList().isEmpty()) |
| rewrite.remove(declaration, null); |
| } |
| if (status != null) |
| adjustor.fStatus.merge(status); |
| } else if (fMember != null) { |
| final BodyDeclaration declaration= ASTNodeSearchUtil.getBodyDeclarationNode(fMember, root); |
| if (declaration != null) { |
| ModifierRewrite.create(rewrite, declaration).setVisibility(visibility, group); |
| if (status != null) |
| adjustor.fStatus.merge(status); |
| } |
| } |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IVisibilityAdjustment#rewriteVisibility(org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor, org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public void rewriteVisibility(final MemberVisibilityAdjustor adjustor, final IProgressMonitor monitor) throws JavaModelException { |
| Assert.isNotNull(adjustor); |
| Assert.isNotNull(monitor); |
| try { |
| monitor.beginTask("", 1); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_adjusting); |
| if (fNeedsRewriting) { |
| if (adjustor.fRewrite != null && adjustor.fRoot != null) |
| rewriteVisibility(adjustor, adjustor.fRewrite, adjustor.fRoot, null, fRefactoringStatus); |
| else { |
| final CompilationUnitRewrite rewrite= adjustor.getCompilationUnitRewrite(fMember.getCompilationUnit()); |
| rewriteVisibility(adjustor, rewrite.getASTRewrite(), rewrite.getRoot(), rewrite.createCategorizedGroupDescription(Messages.format(RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility, getLabel(getKeyword())), SET_VISIBILITY_ADJUSTMENTS), fRefactoringStatus); |
| } |
| } else if (fRefactoringStatus != null) |
| adjustor.fStatus.merge(fRefactoringStatus); |
| monitor.worked(1); |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Determines whether the visibility adjustment needs rewriting. |
| * |
| * @param rewriting <code>true</code> if it needs rewriting, <code>false</code> otherwise |
| */ |
| public final void setNeedsRewriting(final boolean rewriting) { |
| fNeedsRewriting= rewriting; |
| } |
| } |
| |
| /** Interface for visibility adjustments */ |
| public interface IVisibilityAdjustment { |
| |
| /** |
| * Rewrites the visibility adjustment. |
| * |
| * @param adjustor the java element visibility adjustor |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if an error occurs |
| */ |
| public void rewriteVisibility(MemberVisibilityAdjustor adjustor, IProgressMonitor monitor) throws JavaModelException; |
| } |
| |
| /** Description of an outgoing member visibility adjustment */ |
| public static class OutgoingMemberVisibilityAdjustment extends IncomingMemberVisibilityAdjustment { |
| |
| /** |
| * Creates a new outgoing member visibility adjustment. |
| * |
| * @param member the member which is adjusted |
| * @param keyword the keyword representing the adjusted visibility |
| * @param status the associated status |
| */ |
| public OutgoingMemberVisibilityAdjustment(final IMember member, final ModifierKeyword keyword, final RefactoringStatus status) { |
| super(member, keyword, status); |
| } |
| |
| /* |
| * @see org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IVisibilityAdjustment#rewriteVisibility(org.eclipse.jdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor, org.eclipse.core.runtime.IProgressMonitor) |
| */ |
| public void rewriteVisibility(final MemberVisibilityAdjustor adjustor, final IProgressMonitor monitor) throws JavaModelException { |
| Assert.isNotNull(adjustor); |
| Assert.isNotNull(monitor); |
| try { |
| monitor.beginTask("", 1); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_adjusting); |
| if (fNeedsRewriting) { |
| final CompilationUnitRewrite rewrite= adjustor.getCompilationUnitRewrite(fMember.getCompilationUnit()); |
| rewriteVisibility(adjustor, rewrite.getASTRewrite(), rewrite.getRoot(), rewrite.createCategorizedGroupDescription(Messages.format(RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility, getLabel(getKeyword())), SET_VISIBILITY_ADJUSTMENTS), fRefactoringStatus); |
| } |
| monitor.worked(1); |
| } finally { |
| monitor.done(); |
| } |
| } |
| } |
| |
| /** |
| * Returns the label for the specified java element. |
| * |
| * @param element the element to get the label for |
| * @return the label for the element |
| */ |
| public static String getLabel(final IJavaElement element) { |
| Assert.isNotNull(element); |
| return JavaElementLabels.getElementLabel(element, JavaElementLabels.ALL_FULLY_QUALIFIED | JavaElementLabels.ALL_DEFAULT); |
| } |
| |
| /** |
| * Returns the label for the specified visibility keyword. |
| * |
| * @param keyword the keyword to get the label for, or <code>null</code> for default visibility |
| * @return the label for the keyword |
| */ |
| public static String getLabel(final ModifierKeyword keyword) { |
| Assert.isTrue(isVisibilityKeyword(keyword)); |
| if (keyword == null) |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_default; |
| else if (ModifierKeyword.PUBLIC_KEYWORD.equals(keyword)) |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_public; |
| else if (ModifierKeyword.PROTECTED_KEYWORD.equals(keyword)) |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_protected; |
| else |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_private; |
| } |
| |
| /** |
| * Returns the message string for the specified member. |
| * |
| * @param member the member to get the string for |
| * @return the string for the member |
| */ |
| public static String getMessage(final IMember member) { |
| Assert.isTrue(member instanceof IType || member instanceof IMethod || member instanceof IField); |
| if (member instanceof IType) |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_type_warning; |
| else if (member instanceof IMethod) |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_method_warning; |
| else |
| return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_field_warning; |
| } |
| |
| /** |
| * Do the specified modifiers represent a lower visibility than the required threshold? |
| * |
| * @param modifiers the modifiers to test |
| * @param threshold the visibility threshold to compare with |
| * @return <code>true</code> if the visibility is lower than required, <code>false</code> otherwise |
| */ |
| public static boolean hasLowerVisibility(final int modifiers, final int threshold) { |
| if (Modifier.isPrivate(threshold)) |
| return false; |
| else if (Modifier.isPublic(threshold)) |
| return !Modifier.isPublic(modifiers); |
| else if (Modifier.isProtected(threshold)) |
| return !Modifier.isProtected(modifiers) && !Modifier.isPublic(modifiers); |
| else |
| return Modifier.isPrivate(modifiers); |
| } |
| |
| /** |
| * Does the specified modifier keyword represent a lower visibility than the required threshold? |
| * |
| * @param keyword the visibility keyword to test, or <code>null</code> for default visibility |
| * @param threshold the visibility threshold keyword to compare with, or <code>null</code> to compare with default visibility |
| * @return <code>true</code> if the visibility is lower than required, <code>false</code> otherwise |
| */ |
| public static boolean hasLowerVisibility(final ModifierKeyword keyword, final ModifierKeyword threshold) { |
| Assert.isTrue(isVisibilityKeyword(keyword)); |
| Assert.isTrue(isVisibilityKeyword(threshold)); |
| return hasLowerVisibility(keyword != null ? keyword.toFlagValue() : Modifier.NONE, threshold != null ? threshold.toFlagValue() : Modifier.NONE); |
| } |
| |
| /** |
| * Is the specified severity a refactoring status severity? |
| * |
| * @param severity the severity to test |
| * @return <code>true</code> if it is a refactoring status severity, <code>false</code> otherwise |
| */ |
| private static boolean isStatusSeverity(final int severity) { |
| return severity == RefactoringStatus.ERROR || severity == RefactoringStatus.FATAL || severity == RefactoringStatus.INFO || severity == RefactoringStatus.OK || severity == RefactoringStatus.WARNING; |
| } |
| |
| /** |
| * Is the specified modifier keyword a visibility keyword? |
| * |
| * @param keyword the keyword to test, or <code>null</code> |
| * @return <code>true</code> if it is a visibility keyword, <code>false</code> otherwise |
| */ |
| private static boolean isVisibilityKeyword(final ModifierKeyword keyword) { |
| return keyword == null || ModifierKeyword.PUBLIC_KEYWORD.equals(keyword) || ModifierKeyword.PROTECTED_KEYWORD.equals(keyword) || ModifierKeyword.PRIVATE_KEYWORD.equals(keyword); |
| } |
| |
| /** |
| * Is the specified modifier a visibility modifier? |
| * |
| * @param modifier the keyword to test |
| * @return <code>true</code> if it is a visibility modifier, <code>false</code> otherwise |
| */ |
| private static boolean isVisibilityModifier(final int modifier) { |
| return modifier == Modifier.NONE || modifier == Modifier.PUBLIC || modifier == Modifier.PROTECTED || modifier == Modifier.PRIVATE; |
| } |
| |
| /** |
| * Converts a given modifier keyword into a visibility flag. |
| * |
| * @param keyword the keyword to convert |
| * @return the visibility flag |
| */ |
| private static int keywordToVisibility(final ModifierKeyword keyword) { |
| int visibility= 0; |
| if (keyword == ModifierKeyword.PUBLIC_KEYWORD) |
| visibility= Flags.AccPublic; |
| else if (keyword == ModifierKeyword.PRIVATE_KEYWORD) |
| visibility= Flags.AccPrivate; |
| else if (keyword == ModifierKeyword.PROTECTED_KEYWORD) |
| visibility= Flags.AccProtected; |
| return visibility; |
| } |
| |
| /** |
| * Does the specified member need further visibility adjustment? |
| * |
| * @param member the member to test |
| * @param threshold the visibility threshold to test for |
| * @param adjustments the map of members to visibility adjustments |
| * @return <code>true</code> if the member needs further adjustment, <code>false</code> otherwise |
| */ |
| public static boolean needsVisibilityAdjustments(final IMember member, final int threshold, final Map adjustments) { |
| Assert.isNotNull(member); |
| Assert.isTrue(isVisibilityModifier(threshold)); |
| Assert.isNotNull(adjustments); |
| final IncomingMemberVisibilityAdjustment adjustment= (IncomingMemberVisibilityAdjustment) adjustments.get(member); |
| if (adjustment != null) { |
| final ModifierKeyword keyword= adjustment.getKeyword(); |
| return hasLowerVisibility(keyword == null ? Modifier.NONE : keyword.toFlagValue(), threshold); |
| } |
| return true; |
| } |
| |
| /** |
| * Does the specified member need further visibility adjustment? |
| * |
| * @param member the member to test |
| * @param threshold the visibility threshold to test for, or <code>null</code> for default visibility |
| * @param adjustments the map of members to visibility adjustments |
| * @return <code>true</code> if the member needs further adjustment, <code>false</code> otherwise |
| */ |
| public static boolean needsVisibilityAdjustments(final IMember member, final ModifierKeyword threshold, final Map adjustments) { |
| Assert.isNotNull(member); |
| Assert.isNotNull(adjustments); |
| final IncomingMemberVisibilityAdjustment adjustment= (IncomingMemberVisibilityAdjustment) adjustments.get(member); |
| if (adjustment != null) |
| return hasLowerVisibility(adjustment.getKeyword(), threshold); |
| return true; |
| } |
| |
| /** The map of members to visibility adjustments */ |
| private Map fAdjustments= new HashMap(); |
| |
| /** Should incoming references be adjusted? */ |
| private boolean fIncoming= true; |
| |
| /** Should outgoing references be adjusted? */ |
| private boolean fOutgoing= true; |
| |
| /** The referenced element causing the visibility adjustment */ |
| private final IMember fReferenced; |
| |
| /** The referencing java element */ |
| private final IJavaElement fReferencing; |
| |
| /** The AST rewrite to use for reference visibility adjustments, or <code>null</code> to use a compilation unit rewrite */ |
| private ASTRewrite fRewrite= null; |
| |
| /** The map of compilation units to compilation unit rewrites */ |
| private Map fRewrites= new HashMap(3); |
| |
| /** The root node of the AST rewrite for reference visibility adjustments, or <code>null</code> to use a compilation unit rewrite */ |
| private CompilationUnit fRoot= null; |
| |
| /** The incoming search scope */ |
| private IJavaSearchScope fScope; |
| |
| /** The status of the visibility adjustment */ |
| private RefactoringStatus fStatus= new RefactoringStatus(); |
| |
| /** The type hierarchy cache */ |
| private final Map fTypeHierarchies= new HashMap(); |
| |
| /** The visibility message severity */ |
| private int fVisibilitySeverity= RefactoringStatus.WARNING; |
| |
| /** The working copy owner, or <code>null</code> to use none */ |
| private WorkingCopyOwner fOwner= null; |
| |
| /** |
| * Creates a new java element visibility adjustor. |
| * |
| * @param referencing the referencing element used to compute the visibility |
| * @param referenced the referenced member which causes the visibility changes |
| */ |
| public MemberVisibilityAdjustor(final IJavaElement referencing, final IMember referenced) { |
| Assert.isTrue(!(referenced instanceof IInitializer)); |
| Assert.isTrue(referencing instanceof ICompilationUnit || referencing instanceof IType || referencing instanceof IPackageFragment); |
| fScope= RefactoringScopeFactory.createReferencedScope(new IJavaElement[] { referenced}, IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.SOURCES | IJavaSearchScope.APPLICATION_LIBRARIES); |
| fReferencing= referencing; |
| fReferenced= referenced; |
| } |
| |
| /** |
| * Adjusts the visibility of the specified member. |
| * |
| * @param element the "source" point from which to calculate the visibility |
| * @param referencedMovedElement the moved element which may be adjusted in visibility |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if the visibility adjustment could not be computed |
| */ |
| private void adjustIncomingVisibility(final IJavaElement element, IMember referencedMovedElement, final IProgressMonitor monitor) throws JavaModelException { |
| final ModifierKeyword threshold= getVisibilityThreshold(element, referencedMovedElement, monitor); |
| int flags= referencedMovedElement.getFlags(); |
| IType declaring= referencedMovedElement.getDeclaringType(); |
| if (declaring.isInterface()) |
| return; |
| if (hasLowerVisibility(flags, threshold == null ? Modifier.NONE : threshold.toFlagValue()) && needsVisibilityAdjustment(referencedMovedElement, threshold)) |
| fAdjustments.put(referencedMovedElement, new IncomingMemberVisibilityAdjustment(referencedMovedElement, threshold, RefactoringStatus.createStatus(fVisibilitySeverity, Messages.format(getMessage(referencedMovedElement), new String[] { getLabel(referencedMovedElement), getLabel(threshold)}), JavaStatusContext.create(referencedMovedElement), null, RefactoringStatusEntry.NO_CODE, null))); |
| } |
| |
| /** |
| * Check whether anyone accesses the members of the moved type from the |
| * outside. Those may need to have their visibility adjusted. |
| */ |
| private void adjustMemberVisibility(final IMember member, final IProgressMonitor monitor) throws JavaModelException { |
| |
| if (member instanceof IType) { |
| // recursively check accessibility of member type's members |
| final IJavaElement[] typeMembers= ((IType) member).getChildren(); |
| for (int i= 0; i < typeMembers.length; i++) { |
| if (! (typeMembers[i] instanceof IInitializer)) |
| adjustMemberVisibility((IMember) typeMembers[i], monitor); |
| } |
| } |
| |
| if ((member.equals(fReferenced)) || (Modifier.isPublic(member.getFlags()))) |
| return; |
| |
| final SearchResultGroup[] references= findReferences(member, monitor); |
| for (int i= 0; i < references.length; i++) { |
| final SearchMatch[] searchResults= references[i].getSearchResults(); |
| for (int k= 0; k < searchResults.length; k++) { |
| final IJavaElement referenceToMember= (IJavaElement) searchResults[k].getElement(); |
| if (fAdjustments.get(member) == null && referenceToMember instanceof IMember && !isInsideMovedMember(referenceToMember)) { |
| // check whether the member is still visible from the |
| // destination. As we are moving a type, the destination is |
| // a package or another type. |
| adjustIncomingVisibility(fReferencing, member, new SubProgressMonitor(monitor, 1)); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Is the specified member inside the moved member? |
| * @param element the element |
| * @return <code>true</code> if it is inside, <code>false</code> otherwise |
| */ |
| private boolean isInsideMovedMember(final IJavaElement element) { |
| IJavaElement current= element; |
| while ((current= current.getParent()) != null) |
| if (current.equals(fReferenced)) |
| return true; |
| return false; |
| } |
| |
| /** |
| * Finds references to the specified member. |
| * @param member the member |
| * @param monitor the progress monitor to use |
| * @return the search result groups |
| * @throws JavaModelException if an error occurs during search |
| */ |
| private SearchResultGroup[] findReferences(final IMember member, final IProgressMonitor monitor) throws JavaModelException { |
| final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); |
| engine.setOwner(fOwner); |
| engine.setFiltering(true, true); |
| engine.setScope(RefactoringScopeFactory.create(member)); |
| engine.searchPattern(new SubProgressMonitor(monitor, 1)); |
| return (SearchResultGroup[]) engine.getResults(); |
| } |
| |
| /** |
| * Adjusts the visibility of the member based on the incoming references |
| * represented by the specified search result groups. |
| * |
| * If there is at least one reference to the moved element from outside the |
| * moved element, visibility must be increased such that the moved element |
| * (fReferenced) is still visible at the target from all references. This |
| * effectively means that the old element (fReferenced) must be visible from |
| * the new location (fReferencing). |
| * |
| * @param groups the search result groups representing the references |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if the java elements could not be accessed |
| */ |
| private void adjustIncomingVisibility(final SearchResultGroup[] groups, final IProgressMonitor monitor) throws JavaModelException { |
| try { |
| monitor.beginTask("", groups.length); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); |
| SearchMatch[] matches= null; |
| boolean adjusted= false; |
| for (int index= 0; index < groups.length; index++) { |
| matches= groups[index].getSearchResults(); |
| for (int offset= 0; offset < matches.length; offset++) { |
| final Object element= matches[offset].getElement(); |
| if (element instanceof IMember && !isInsideMovedMember((IMember) element)) { |
| // found one reference which is not inside the moved |
| // element => adjust visibility of the moved element |
| adjustIncomingVisibility(fReferencing, fReferenced, monitor); |
| adjusted= true; // one adjustment is enough |
| break; |
| } |
| } |
| if (adjusted) |
| break; |
| monitor.worked(1); |
| } |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Adjusts the visibility of the referenced field found in a compilation unit. |
| * |
| * @param field the referenced field to adjust |
| * @param threshold the visibility threshold, or <code>null</code> for default visibility |
| * @throws JavaModelException if an error occurs |
| */ |
| private void adjustOutgoingVisibility(final IField field, final ModifierKeyword threshold) throws JavaModelException { |
| Assert.isTrue(!field.isBinary() && !field.isReadOnly()); |
| //bug 100555 (moving inner class to top level class; taking private fields with you) |
| final IType declaring= field.getDeclaringType(); |
| if (declaring != null && declaring.equals(fReferenced)) return; |
| if (hasLowerVisibility(field.getFlags(), keywordToVisibility(threshold)) && needsVisibilityAdjustment(field, threshold)) |
| adjustOutgoingVisibility(field, threshold, RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_field_warning); |
| } |
| |
| /** |
| * Adjusts the visibility of the referenced body declaration. |
| * |
| * @param member the member where to adjust the visibility |
| * @param threshold the visibility keyword representing the required visibility, or <code>null</code> for default visibility |
| * @param template the message template to use |
| * @throws JavaModelException if an error occurs |
| */ |
| private void adjustOutgoingVisibility(final IMember member, final ModifierKeyword threshold, final String template) throws JavaModelException { |
| Assert.isTrue(!member.isBinary() && !member.isReadOnly()); |
| boolean adjust= true; |
| final IType declaring= member.getDeclaringType(); |
| if (declaring != null && (JavaModelUtil.isInterfaceOrAnnotation(declaring) || declaring.equals(fReferenced))) |
| adjust= false; |
| if (adjust && hasLowerVisibility(member.getFlags(), keywordToVisibility(threshold)) && needsVisibilityAdjustment(member, threshold)) |
| fAdjustments.put(member, new OutgoingMemberVisibilityAdjustment(member, threshold, RefactoringStatus.createStatus(fVisibilitySeverity, Messages.format(template, new String[] { JavaElementLabels.getTextLabel(member, JavaElementLabels.M_PARAMETER_TYPES | JavaElementLabels.ALL_FULLY_QUALIFIED), getLabel(threshold)}), JavaStatusContext.create(member), null, RefactoringStatusEntry.NO_CODE, null))); |
| } |
| |
| /** |
| * Adjusts the visibilities of the referenced element from the search match found in a compilation unit. |
| * |
| * @param match the search match representing the element declaration |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if the visibility could not be determined |
| */ |
| private void adjustOutgoingVisibility(final SearchMatch match, final IProgressMonitor monitor) throws JavaModelException { |
| final Object element= match.getElement(); |
| if (element instanceof IMember) { |
| final IMember member= (IMember) element; |
| if (!member.isBinary() && !member.isReadOnly() && !isInsideMovedMember(member)) { |
| adjustOutgoingVisibilityChain(member, monitor); |
| } |
| } |
| } |
| |
| private void adjustOutgoingVisibilityChain(final IMember member, final IProgressMonitor monitor) throws JavaModelException { |
| |
| if (!Modifier.isPublic(member.getFlags())) { |
| final ModifierKeyword threshold= computeOutgoingVisibilityThreshold(fReferencing, member, monitor); |
| if (member instanceof IMethod) { |
| adjustOutgoingVisibility(member, threshold, RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_method_warning); |
| } else if (member instanceof IField) { |
| adjustOutgoingVisibility((IField) member, threshold); |
| } else if (member instanceof IType) { |
| adjustOutgoingVisibility(member, threshold, RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_type_warning); |
| } |
| } |
| |
| if (member.getDeclaringType() != null) |
| adjustOutgoingVisibilityChain(member.getDeclaringType(), monitor); |
| } |
| |
| /** |
| * Adjusts the visibilities of the outgoing references from the member represented by the specified search result groups. |
| * |
| * @param groups the search result groups representing the references |
| * @param monitor the progress monitor to us |
| * @throws JavaModelException if the visibility could not be determined |
| */ |
| private void adjustOutgoingVisibility(final SearchResultGroup[] groups, final IProgressMonitor monitor) throws JavaModelException { |
| try { |
| monitor.beginTask("", groups.length); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); |
| IJavaElement element= null; |
| SearchMatch[] matches= null; |
| SearchResultGroup group= null; |
| for (int index= 0; index < groups.length; index++) { |
| group= groups[index]; |
| element= JavaCore.create(group.getResource()); |
| if (element instanceof ICompilationUnit) { |
| matches= group.getSearchResults(); |
| for (int offset= 0; offset < matches.length; offset++) |
| adjustOutgoingVisibility(matches[offset], new SubProgressMonitor(monitor, 1)); |
| } // else if (element != null) |
| // fStatus.merge(RefactoringStatus.createStatus(fFailureSeverity, RefactoringCoreMessages.getFormattedString("MemberVisibilityAdjustor.binary.outgoing.project", new String[] { element.getJavaProject().getElementName(), getLabel(fReferenced)}), null, null, RefactoringStatusEntry.NO_CODE, null)); //$NON-NLS-1$ |
| // else if (group.getResource() != null) |
| // fStatus.merge(RefactoringStatus.createStatus(fFailureSeverity, RefactoringCoreMessages.getFormattedString("MemberVisibilityAdjustor.binary.outgoing.resource", new String[] { group.getResource().getName(), getLabel(fReferenced)}), null, null, RefactoringStatusEntry.NO_CODE, null)); //$NON-NLS-1$ |
| |
| // TW: enable when bug 78387 is fixed |
| |
| monitor.worked(1); |
| } |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Adjusts the visibilities of the referenced and referencing elements. |
| * |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if an error occurs during search |
| */ |
| public final void adjustVisibility(final IProgressMonitor monitor) throws JavaModelException { |
| try { |
| monitor.beginTask("", 7); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); |
| final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(fReferenced, IJavaSearchConstants.REFERENCES, SearchUtils.GENERICS_AGNOSTIC_MATCH_RULE)); |
| engine.setScope(fScope); |
| engine.setStatus(fStatus); |
| engine.setOwner(fOwner); |
| if (fIncoming) { |
| // check calls to the referenced (moved) element, adjust element |
| // visibility if necessary. |
| engine.searchPattern(new SubProgressMonitor(monitor, 1)); |
| adjustIncomingVisibility((SearchResultGroup[]) engine.getResults(), new SubProgressMonitor(monitor, 1)); |
| engine.clearResults(); |
| // If the moved element is a type: Adjust visibility of members |
| // of the type if they are accessed outside of the moved type |
| if (fReferenced instanceof IType) { |
| final IType type= (IType) fReferenced; |
| adjustMemberVisibility(type, new SubProgressMonitor(monitor, 1)); |
| } |
| } |
| if (fOutgoing) { |
| /* |
| * Search for the types, fields, and methods which |
| * are called/acted upon inside the referenced element (the one |
| * to be moved) and assure that they are also visible from |
| * within the referencing element (the destination type (or |
| * package if move to new type)). |
| */ |
| engine.searchReferencedTypes(fReferenced, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); |
| engine.searchReferencedFields(fReferenced, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); |
| engine.searchReferencedMethods(fReferenced, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); |
| adjustOutgoingVisibility((SearchResultGroup[]) engine.getResults(), new SubProgressMonitor(monitor, 1)); |
| } |
| } finally { |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Computes the visibility threshold for the referenced element. |
| * |
| * @param referencing the referencing element |
| * @param referenced the referenced element |
| * @param monitor the progress monitor to use |
| * @return the visibility keyword corresponding to the threshold, or <code>null</code> for default visibility |
| * @throws JavaModelException if the java elements could not be accessed |
| */ |
| public ModifierKeyword getVisibilityThreshold(final IJavaElement referencing, final IMember referenced, final IProgressMonitor monitor) throws JavaModelException { |
| Assert.isTrue(!(referencing instanceof IInitializer)); |
| Assert.isTrue(!(referenced instanceof IInitializer)); |
| ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; |
| try { |
| monitor.beginTask("", 1); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); |
| final int referencingType= referencing.getElementType(); |
| final int referencedType= referenced.getElementType(); |
| switch (referencedType) { |
| case IJavaElement.TYPE: { |
| final IType typeReferenced= (IType) referenced; |
| final ICompilationUnit referencedUnit= typeReferenced.getCompilationUnit(); |
| switch (referencingType) { |
| case IJavaElement.TYPE: { |
| keyword= thresholdTypeToType((IType) referencing, typeReferenced, monitor); |
| break; |
| } |
| case IJavaElement.FIELD: |
| case IJavaElement.METHOD: { |
| final IMember member= (IMember) referencing; |
| if (typeReferenced.equals(member.getDeclaringType())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && referencedUnit.equals(member.getCompilationUnit())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (typeReferenced.getPackageFragment().equals(member.getDeclaringType().getPackageFragment())) |
| keyword= null; |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| final IPackageFragment fragment= (IPackageFragment) referencing; |
| if (typeReferenced.getPackageFragment().equals(fragment)) |
| keyword= null; |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| break; |
| } |
| case IJavaElement.FIELD: { |
| final IField fieldReferenced= (IField) referenced; |
| final ICompilationUnit referencedUnit= fieldReferenced.getCompilationUnit(); |
| switch (referencingType) { |
| case IJavaElement.TYPE: { |
| keyword= thresholdTypeToField((IType) referencing, fieldReferenced, monitor); |
| break; |
| } |
| case IJavaElement.FIELD: |
| case IJavaElement.METHOD: { |
| final IMember member= (IMember) referencing; |
| if (fieldReferenced.getDeclaringType().equals(member.getDeclaringType())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && referencedUnit.equals(member.getCompilationUnit())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (fieldReferenced.getDeclaringType().getPackageFragment().equals(member.getDeclaringType().getPackageFragment())) |
| keyword= null; |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| final IPackageFragment fragment= (IPackageFragment) referencing; |
| if (fieldReferenced.getDeclaringType().getPackageFragment().equals(fragment)) |
| keyword= null; |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| break; |
| } |
| case IJavaElement.METHOD: { |
| final IMethod methodReferenced= (IMethod) referenced; |
| final ICompilationUnit referencedUnit= methodReferenced.getCompilationUnit(); |
| switch (referencingType) { |
| case IJavaElement.TYPE: { |
| keyword= thresholdTypeToMethod((IType) referencing, methodReferenced, monitor); |
| break; |
| } |
| case IJavaElement.FIELD: |
| case IJavaElement.METHOD: { |
| final IMember member= (IMember) referencing; |
| if (methodReferenced.getDeclaringType().equals(member.getDeclaringType())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && referencedUnit.equals(member.getCompilationUnit())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (methodReferenced.getDeclaringType().getPackageFragment().equals(member.getDeclaringType().getPackageFragment())) |
| keyword= null; |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| final IPackageFragment fragment= (IPackageFragment) referencing; |
| if (methodReferenced.getDeclaringType().getPackageFragment().equals(fragment)) |
| keyword= null; |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| } finally { |
| monitor.done(); |
| } |
| return keyword; |
| } |
| |
| /** |
| * Computes the visibility threshold for the referenced element. |
| * |
| * @param referencing the referencing element |
| * @param referenced the referenced element |
| * @param monitor the progress monitor to use |
| * @return the visibility keyword corresponding to the threshold, or <code>null</code> for default visibility |
| * @throws JavaModelException if the java elements could not be accessed |
| */ |
| private ModifierKeyword computeOutgoingVisibilityThreshold(final IJavaElement referencing, final IMember referenced, final IProgressMonitor monitor) throws JavaModelException { |
| Assert.isTrue(referencing instanceof ICompilationUnit || referencing instanceof IType || referencing instanceof IPackageFragment); |
| Assert.isTrue(referenced instanceof IType || referenced instanceof IField || referenced instanceof IMethod); |
| ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; |
| try { |
| monitor.beginTask("", 1); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); |
| final int referencingType= referencing.getElementType(); |
| final int referencedType= referenced.getElementType(); |
| switch (referencedType) { |
| case IJavaElement.TYPE: { |
| final IType typeReferenced= (IType) referenced; |
| switch (referencingType) { |
| case IJavaElement.COMPILATION_UNIT: { |
| final ICompilationUnit unit= (ICompilationUnit) referencing; |
| final ICompilationUnit referencedUnit= typeReferenced.getCompilationUnit(); |
| if (referencedUnit != null && referencedUnit.equals(unit)) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent())) |
| keyword= null; |
| break; |
| } |
| case IJavaElement.TYPE: { |
| keyword= thresholdTypeToType((IType) referencing, typeReferenced, monitor); |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| final IPackageFragment fragment= (IPackageFragment) referencing; |
| if (typeReferenced.getPackageFragment().equals(fragment)) |
| keyword= null; |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| break; |
| } |
| case IJavaElement.FIELD: { |
| final IField fieldReferenced= (IField) referenced; |
| final ICompilationUnit referencedUnit= fieldReferenced.getCompilationUnit(); |
| switch (referencingType) { |
| case IJavaElement.COMPILATION_UNIT: { |
| final ICompilationUnit unit= (ICompilationUnit) referencing; |
| if (referencedUnit != null && referencedUnit.equals(unit)) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent())) |
| keyword= null; |
| break; |
| } |
| case IJavaElement.TYPE: { |
| keyword= thresholdTypeToField((IType) referencing, fieldReferenced, monitor); |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| final IPackageFragment fragment= (IPackageFragment) referencing; |
| if (fieldReferenced.getDeclaringType().getPackageFragment().equals(fragment)) |
| keyword= null; |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| break; |
| } |
| case IJavaElement.METHOD: { |
| final IMethod methodReferenced= (IMethod) referenced; |
| final ICompilationUnit referencedUnit= methodReferenced.getCompilationUnit(); |
| switch (referencingType) { |
| case IJavaElement.COMPILATION_UNIT: { |
| final ICompilationUnit unit= (ICompilationUnit) referencing; |
| if (referencedUnit != null && referencedUnit.equals(unit)) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent())) |
| keyword= null; |
| break; |
| } |
| case IJavaElement.TYPE: { |
| keyword= thresholdTypeToMethod((IType) referencing, methodReferenced, monitor); |
| break; |
| } |
| case IJavaElement.PACKAGE_FRAGMENT: { |
| final IPackageFragment fragment= (IPackageFragment) referencing; |
| if (methodReferenced.getDeclaringType().getPackageFragment().equals(fragment)) |
| keyword= null; |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| break; |
| } |
| default: |
| Assert.isTrue(false); |
| } |
| } finally { |
| monitor.done(); |
| } |
| return keyword; |
| } |
| |
| /** |
| * Returns the existing visibility adjustments (element type: Map <IMember, IVisibilityAdjustment>). |
| * |
| * @return the visibility adjustments |
| */ |
| public final Map getAdjustments() { |
| return fAdjustments; |
| } |
| |
| /** |
| * Returns a compilation unit rewrite for the specified compilation unit. |
| * |
| * @param unit the compilation unit to get the rewrite for |
| * @return the rewrite for the compilation unit |
| */ |
| private CompilationUnitRewrite getCompilationUnitRewrite(final ICompilationUnit unit) { |
| CompilationUnitRewrite rewrite= (CompilationUnitRewrite) fRewrites.get(unit); |
| if (rewrite == null) { |
| if (fOwner == null) |
| rewrite= new CompilationUnitRewrite(unit); |
| else |
| rewrite= new CompilationUnitRewrite(fOwner, unit); |
| } |
| return rewrite; |
| } |
| |
| /** |
| * Returns a cached type hierarchy for the specified type. |
| * |
| * @param type the type to get the hierarchy for |
| * @param monitor the progress monitor to use |
| * @return the type hierarchy |
| * @throws JavaModelException if the type hierarchy could not be created |
| */ |
| private ITypeHierarchy getTypeHierarchy(final IType type, final IProgressMonitor monitor) throws JavaModelException { |
| ITypeHierarchy hierarchy= null; |
| try { |
| monitor.beginTask("", 1); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); |
| try { |
| hierarchy= (ITypeHierarchy) fTypeHierarchies.get(type); |
| if (hierarchy == null) { |
| if (fOwner == null) |
| hierarchy= type.newSupertypeHierarchy(new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); |
| else |
| hierarchy= type.newSupertypeHierarchy(fOwner, new SubProgressMonitor(monitor, 1, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL)); |
| } |
| } finally { |
| monitor.done(); |
| } |
| } finally { |
| monitor.done(); |
| } |
| return hierarchy; |
| } |
| |
| /** |
| * Does the specified member need further visibility adjustment? |
| * |
| * @param member the member to test |
| * @param threshold the visibility threshold to test for |
| * @return <code>true</code> if the member needs further adjustment, <code>false</code> otherwise |
| */ |
| private boolean needsVisibilityAdjustment(final IMember member, final ModifierKeyword threshold) { |
| Assert.isNotNull(member); |
| return needsVisibilityAdjustments(member, threshold, fAdjustments); |
| } |
| |
| /** |
| * Rewrites the computed adjustments for the specified compilation unit. |
| * |
| * @param unit the compilation unit to rewrite the adjustments |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if an error occurs during search |
| */ |
| public final void rewriteVisibility(final ICompilationUnit unit, final IProgressMonitor monitor) throws JavaModelException { |
| try { |
| monitor.beginTask("", fAdjustments.keySet().size()); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_adjusting); |
| IMember member= null; |
| IVisibilityAdjustment adjustment= null; |
| for (final Iterator iterator= fAdjustments.keySet().iterator(); iterator.hasNext();) { |
| member= (IMember) iterator.next(); |
| if (unit.equals(member.getCompilationUnit())) { |
| adjustment= (IVisibilityAdjustment) fAdjustments.get(member); |
| if (adjustment != null) |
| adjustment.rewriteVisibility(this, new SubProgressMonitor(monitor, 1)); |
| } |
| } |
| } finally { |
| fTypeHierarchies.clear(); |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Rewrites the computed adjustments. |
| * |
| * @param monitor the progress monitor to use |
| * @throws JavaModelException if an error occurs during search |
| */ |
| public final void rewriteVisibility(final IProgressMonitor monitor) throws JavaModelException { |
| try { |
| monitor.beginTask("", fAdjustments.keySet().size()); //$NON-NLS-1$ |
| monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_adjusting); |
| IMember member= null; |
| IVisibilityAdjustment adjustment= null; |
| for (final Iterator iterator= fAdjustments.keySet().iterator(); iterator.hasNext();) { |
| member= (IMember) iterator.next(); |
| adjustment= (IVisibilityAdjustment) fAdjustments.get(member); |
| if (adjustment != null) |
| adjustment.rewriteVisibility(this, new SubProgressMonitor(monitor, 1)); |
| } |
| } finally { |
| fTypeHierarchies.clear(); |
| monitor.done(); |
| } |
| } |
| |
| /** |
| * Sets the existing visibility adjustments to be taken into account (element type: Map <IMember, IVisibilityAdjustment>). |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is to take no existing adjustments into account. |
| * |
| * @param adjustments the existing adjustments to set |
| */ |
| public final void setAdjustments(final Map adjustments) { |
| Assert.isNotNull(adjustments); |
| fAdjustments= adjustments; |
| } |
| |
| /** |
| * Sets the severity of failure messages. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is a status with value {@link RefactoringStatus#ERROR}. |
| * |
| * @param severity the severity of failure messages |
| */ |
| public final void setFailureSeverity(final int severity) { |
| Assert.isTrue(isStatusSeverity(severity)); |
| } |
| |
| /** |
| * Determines whether incoming references should be adjusted. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is to adjust incoming references. |
| * |
| * @param incoming <code>true</code> if incoming references should be adjusted, <code>false</code> otherwise |
| */ |
| public final void setIncoming(final boolean incoming) { |
| fIncoming= incoming; |
| } |
| |
| /** |
| * Determines whether outgoing references should be adjusted. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is to adjust outgoing references. |
| * |
| * @param outgoing <code>true</code> if outgoing references should be adjusted, <code>false</code> otherwise |
| */ |
| public final void setOutgoing(final boolean outgoing) { |
| fOutgoing= outgoing; |
| } |
| |
| /** |
| * Sets the AST rewrite to use for member visibility adjustments. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is to use a compilation unit rewrite. |
| * |
| * @param rewrite the AST rewrite to set |
| * @param root the root of the AST used in the rewrite |
| */ |
| public final void setRewrite(final ASTRewrite rewrite, final CompilationUnit root) { |
| Assert.isTrue(rewrite == null || root != null); |
| fRewrite= rewrite; |
| fRoot= root; |
| } |
| |
| /** |
| * Sets the compilation unit rewrites used by this adjustor (element type: Map <ICompilationUnit, CompilationUnitRewrite>). |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is to use no existing rewrites. |
| * |
| * @param rewrites the map of compilation units to compilation unit rewrites to set |
| */ |
| public final void setRewrites(final Map rewrites) { |
| Assert.isNotNull(rewrites); |
| fRewrites= rewrites; |
| } |
| |
| /** |
| * Sets the incoming search scope used by this adjustor. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is the whole workspace as scope. |
| * |
| * @param scope the search scope to set |
| */ |
| public final void setScope(final IJavaSearchScope scope) { |
| Assert.isNotNull(scope); |
| fScope= scope; |
| } |
| |
| /** |
| * Sets the working copy owner used by this adjustor. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is to use none. |
| * |
| * @param owner the working copy owner, or <code>null</code> to use none |
| */ |
| public final void setOwner(final WorkingCopyOwner owner) { |
| fOwner= owner; |
| } |
| |
| /** |
| * Sets the refactoring status used by this adjustor. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is a fresh status with status {@link RefactoringStatus#OK}. |
| * |
| * @param status the refactoring status to set |
| */ |
| public final void setStatus(final RefactoringStatus status) { |
| Assert.isNotNull(status); |
| fStatus= status; |
| } |
| |
| /** |
| * Sets the severity of visibility messages. |
| * <p> |
| * This method must be called before calling {@link MemberVisibilityAdjustor#adjustVisibility(IProgressMonitor)}. The default is a status with value {@link RefactoringStatus#WARNING}. |
| * |
| * @param severity the severity of visibility messages |
| */ |
| public final void setVisibilitySeverity(final int severity) { |
| Assert.isTrue(isStatusSeverity(severity)); |
| fVisibilitySeverity= severity; |
| } |
| |
| /** |
| * Returns the visibility threshold from a type to a field. |
| * |
| * @param referencing the referencing type |
| * @param referenced the referenced field |
| * @param monitor the progress monitor to use |
| * @return the visibility keyword corresponding to the threshold, or <code>null</code> for default visibility |
| * @throws JavaModelException if the java elements could not be accessed |
| */ |
| private ModifierKeyword thresholdTypeToField(final IType referencing, final IField referenced, final IProgressMonitor monitor) throws JavaModelException { |
| ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; |
| final ICompilationUnit referencedUnit= referenced.getCompilationUnit(); |
| if (referenced.getDeclaringType().equals(referencing)) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else { |
| final ITypeHierarchy hierarchy= getTypeHierarchy(referencing, new SubProgressMonitor(monitor, 1)); |
| final IType[] types= hierarchy.getSupertypes(referencing); |
| IType superType= null; |
| for (int index= 0; index < types.length; index++) { |
| superType= types[index]; |
| if (superType.equals(referenced.getDeclaringType())) { |
| keyword= ModifierKeyword.PROTECTED_KEYWORD; |
| return keyword; |
| } |
| } |
| } |
| final ICompilationUnit typeUnit= referencing.getCompilationUnit(); |
| if (referencedUnit != null && referencedUnit.equals(typeUnit)) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else if (referencedUnit != null && typeUnit != null && referencedUnit.getParent().equals(typeUnit.getParent())) |
| keyword= null; |
| return keyword; |
| } |
| |
| /** |
| * Returns the visibility threshold from a type to a method. |
| * |
| * @param referencing the referencing type |
| * @param referenced the referenced method |
| * @param monitor the progress monitor to use |
| * @return the visibility keyword corresponding to the threshold, or <code>null</code> for default visibility |
| * @throws JavaModelException if the java elements could not be accessed |
| */ |
| private ModifierKeyword thresholdTypeToMethod(final IType referencing, final IMethod referenced, final IProgressMonitor monitor) throws JavaModelException { |
| final ICompilationUnit referencedUnit= referenced.getCompilationUnit(); |
| ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; |
| if (referenced.getDeclaringType().equals(referencing)) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else { |
| final ITypeHierarchy hierarchy= getTypeHierarchy(referencing, new SubProgressMonitor(monitor, 1)); |
| final IType[] types= hierarchy.getSupertypes(referencing); |
| IType superType= null; |
| for (int index= 0; index < types.length; index++) { |
| superType= types[index]; |
| if (superType.equals(referenced.getDeclaringType())) { |
| keyword= ModifierKeyword.PROTECTED_KEYWORD; |
| return keyword; |
| } |
| } |
| } |
| final ICompilationUnit typeUnit= referencing.getCompilationUnit(); |
| if (referencedUnit != null && referencedUnit.equals(typeUnit)) { |
| if (referenced.getDeclaringType().getDeclaringType() != null) |
| keyword= null; |
| else |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| } else if (referencedUnit != null && referencedUnit.getParent().equals(typeUnit.getParent())) |
| keyword= null; |
| return keyword; |
| } |
| |
| /** |
| * Returns the visibility threshold from a type to another type. |
| * |
| * @param referencing the referencing type |
| * @param referenced the referenced type |
| * @param monitor the progress monitor to use |
| * @return the visibility keyword corresponding to the threshold, or <code>null</code> for default visibility |
| * @throws JavaModelException if the java elements could not be accessed |
| */ |
| private ModifierKeyword thresholdTypeToType(final IType referencing, final IType referenced, final IProgressMonitor monitor) throws JavaModelException { |
| ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; |
| final ICompilationUnit referencedUnit= referenced.getCompilationUnit(); |
| if (referencing.equals(referenced.getDeclaringType())) |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| else { |
| final ITypeHierarchy hierarchy= getTypeHierarchy(referencing, new SubProgressMonitor(monitor, 1)); |
| final IType[] types= hierarchy.getSupertypes(referencing); |
| IType superType= null; |
| for (int index= 0; index < types.length; index++) { |
| superType= types[index]; |
| if (superType.equals(referenced)) { |
| keyword= null; |
| return keyword; |
| } |
| } |
| } |
| final ICompilationUnit typeUnit= referencing.getCompilationUnit(); |
| if (referencedUnit != null && referencedUnit.equals(typeUnit)) { |
| if (referenced.getDeclaringType() != null) |
| keyword= null; |
| else |
| keyword= ModifierKeyword.PRIVATE_KEYWORD; |
| } else if (referencedUnit != null && typeUnit != null && referencedUnit.getParent().equals(typeUnit.getParent())) |
| keyword= null; |
| return keyword; |
| } |
| } |