/******************************************************************************* * Copyright (c) 2000, 2009 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.wst.jsdt.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.OperationCanceledException; 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.wst.jsdt.core.Flags; import org.eclipse.wst.jsdt.core.IField; import org.eclipse.wst.jsdt.core.IFunction; import org.eclipse.wst.jsdt.core.IInitializer; import org.eclipse.wst.jsdt.core.IJavaScriptElement; import org.eclipse.wst.jsdt.core.IJavaScriptUnit; import org.eclipse.wst.jsdt.core.IMember; import org.eclipse.wst.jsdt.core.IPackageFragment; import org.eclipse.wst.jsdt.core.IType; import org.eclipse.wst.jsdt.core.ITypeHierarchy; import org.eclipse.wst.jsdt.core.JavaScriptCore; import org.eclipse.wst.jsdt.core.JavaScriptModelException; import org.eclipse.wst.jsdt.core.WorkingCopyOwner; import org.eclipse.wst.jsdt.core.dom.ASTNode; import org.eclipse.wst.jsdt.core.dom.AbstractTypeDeclaration; import org.eclipse.wst.jsdt.core.dom.BodyDeclaration; import org.eclipse.wst.jsdt.core.dom.FieldDeclaration; import org.eclipse.wst.jsdt.core.dom.IExtendedModifier; import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit; import org.eclipse.wst.jsdt.core.dom.Modifier; import org.eclipse.wst.jsdt.core.dom.SimpleName; import org.eclipse.wst.jsdt.core.dom.Type; import org.eclipse.wst.jsdt.core.dom.VariableDeclarationFragment; import org.eclipse.wst.jsdt.core.dom.Modifier.ModifierKeyword; import org.eclipse.wst.jsdt.core.dom.rewrite.ASTRewrite; import org.eclipse.wst.jsdt.core.dom.rewrite.ListRewrite; import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchConstants; import org.eclipse.wst.jsdt.core.search.IJavaScriptSearchScope; import org.eclipse.wst.jsdt.core.search.SearchMatch; import org.eclipse.wst.jsdt.core.search.SearchPattern; import org.eclipse.wst.jsdt.internal.corext.dom.ModifierRewrite; import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringCoreMessages; import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringScopeFactory; import org.eclipse.wst.jsdt.internal.corext.refactoring.RefactoringSearchEngine2; import org.eclipse.wst.jsdt.internal.corext.refactoring.SearchResultGroup; import org.eclipse.wst.jsdt.internal.corext.refactoring.base.JavaStatusContext; import org.eclipse.wst.jsdt.internal.corext.util.Messages; import org.eclipse.wst.jsdt.internal.corext.util.SearchUtils; import org.eclipse.wst.jsdt.ui.JavaScriptElementLabels; /** * Helper class to adjust the visibilities of members with respect to a reference element. * * */ public final class MemberVisibilityAdjustor { /** * The visibility group category set. * * */ public static final GroupCategorySet SET_VISIBILITY_ADJUSTMENTS= new GroupCategorySet(new GroupCategory("org.eclipse.wst.jsdt.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 JavaScriptModelException if an error occurs */ protected final void rewriteVisibility(final MemberVisibilityAdjustor adjustor, final ASTRewrite rewrite, final JavaScriptUnit root, final CategorizedTextEditGroup group, final RefactoringStatus status) throws JavaScriptModelException { Assert.isNotNull(adjustor); Assert.isNotNull(rewrite); Assert.isNotNull(root); final int visibility= fKeyword != null ? fKeyword.toFlagValue() : Modifier.NONE; if (fMember instanceof IField) { 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.wst.jsdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IVisibilityAdjustment#rewriteVisibility(org.eclipse.wst.jsdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor, org.eclipse.core.runtime.IProgressMonitor) */ public void rewriteVisibility(final MemberVisibilityAdjustor adjustor, final IProgressMonitor monitor) throws JavaScriptModelException { 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.getJavaScriptUnit()); 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 JavaScriptModelException if an error occurs */ public void rewriteVisibility(MemberVisibilityAdjustor adjustor, IProgressMonitor monitor) throws JavaScriptModelException; } /** 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.wst.jsdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor.IVisibilityAdjustment#rewriteVisibility(org.eclipse.wst.jsdt.internal.corext.refactoring.structure.MemberVisibilityAdjustor, org.eclipse.core.runtime.IProgressMonitor) */ public void rewriteVisibility(final MemberVisibilityAdjustor adjustor, final IProgressMonitor monitor) throws JavaScriptModelException { 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.getJavaScriptUnit()); 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 IJavaScriptElement element) { Assert.isNotNull(element); return JavaScriptElementLabels.getElementLabel(element, JavaScriptElementLabels.ALL_FULLY_QUALIFIED | JavaScriptElementLabels.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 IFunction || member instanceof IField); if (member instanceof IType) return RefactoringCoreMessages.MemberVisibilityAdjustor_change_visibility_type_warning; else if (member instanceof IFunction) 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; 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 IJavaScriptElement 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 JavaScriptUnit fRoot= null; /** The incoming search scope */ private IJavaScriptSearchScope 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 IJavaScriptElement referencing, final IMember referenced) { Assert.isTrue(!(referenced instanceof IInitializer)); Assert.isTrue(referencing instanceof IJavaScriptUnit || referencing instanceof IType || referencing instanceof IPackageFragment); fScope= RefactoringScopeFactory.createReferencedScope(new IJavaScriptElement[] { referenced}, IJavaScriptSearchScope.REFERENCED_PROJECTS | IJavaScriptSearchScope.SOURCES | IJavaScriptSearchScope.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 JavaScriptModelException if the visibility adjustment could not be computed */ private void adjustIncomingVisibility(final IJavaScriptElement element, IMember referencedMovedElement, final IProgressMonitor monitor) throws JavaScriptModelException { final ModifierKeyword threshold= getVisibilityThreshold(element, referencedMovedElement, monitor); int flags= referencedMovedElement.getFlags(); IType declaring= referencedMovedElement.getDeclaringType(); 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. * @param member * @param monitor * @throws JavaScriptModelException */ private void adjustMemberVisibility(final IMember member, final IProgressMonitor monitor) throws JavaScriptModelException { if (member instanceof IType) { // recursively check accessibility of member type's members final IJavaScriptElement[] 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 IJavaScriptElement referenceToMember= (IJavaScriptElement) 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 IJavaScriptElement element) { IJavaScriptElement 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 JavaScriptModelException if an error occurs during search */ private SearchResultGroup[] findReferences(final IMember member, final IProgressMonitor monitor) throws JavaScriptModelException { final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(member, IJavaScriptSearchConstants.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 JavaScriptModelException if the java elements could not be accessed */ private void adjustIncomingVisibility(final SearchResultGroup[] groups, final IProgressMonitor monitor) throws JavaScriptModelException { 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 JavaScriptModelException if an error occurs */ private void adjustOutgoingVisibility(final IField field, final ModifierKeyword threshold) throws JavaScriptModelException { 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 JavaScriptModelException if an error occurs */ private void adjustOutgoingVisibility(final IMember member, final ModifierKeyword threshold, final String template) throws JavaScriptModelException { Assert.isTrue(!member.isBinary() && !member.isReadOnly()); boolean adjust= true; final IType declaring= member.getDeclaringType(); if (declaring != null && (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[] { JavaScriptElementLabels.getTextLabel(member, JavaScriptElementLabels.M_PARAMETER_TYPES | JavaScriptElementLabels.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 JavaScriptModelException if the visibility could not be determined */ private void adjustOutgoingVisibility(final SearchMatch match, final IProgressMonitor monitor) throws JavaScriptModelException { 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 JavaScriptModelException { if (!Modifier.isPublic(member.getFlags())) { final ModifierKeyword threshold= computeOutgoingVisibilityThreshold(fReferencing, member, monitor); if (member instanceof IFunction) { 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 JavaScriptModelException if the visibility could not be determined */ private void adjustOutgoingVisibility(final SearchResultGroup[] groups, final IProgressMonitor monitor) throws JavaScriptModelException { try { monitor.beginTask("", groups.length); //$NON-NLS-1$ monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); IJavaScriptElement element= null; SearchMatch[] matches= null; SearchResultGroup group= null; for (int index= 0; index < groups.length; index++) { group= groups[index]; element= JavaScriptCore.create(group.getResource()); if (element instanceof IJavaScriptUnit) { 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 JavaScriptModelException if an error occurs during search */ public final void adjustVisibility(final IProgressMonitor monitor) throws JavaScriptModelException { try { monitor.beginTask("", 7); //$NON-NLS-1$ monitor.setTaskName(RefactoringCoreMessages.MemberVisibilityAdjustor_checking); final RefactoringSearchEngine2 engine= new RefactoringSearchEngine2(SearchPattern.createPattern(fReferenced, IJavaScriptSearchConstants.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 JavaScriptModelException if the java elements could not be accessed */ public ModifierKeyword getVisibilityThreshold(final IJavaScriptElement referencing, final IMember referenced, final IProgressMonitor monitor) throws JavaScriptModelException { 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 IJavaScriptElement.TYPE: { final IType typeReferenced= (IType) referenced; final IJavaScriptUnit referencedUnit= typeReferenced.getJavaScriptUnit(); switch (referencingType) { case IJavaScriptElement.TYPE: { keyword= thresholdTypeToType((IType) referencing, typeReferenced, monitor); break; } case IJavaScriptElement.FIELD: case IJavaScriptElement.METHOD: { final IMember member= (IMember) referencing; if (typeReferenced.equals(member.getDeclaringType())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (referencedUnit != null && referencedUnit.equals(member.getJavaScriptUnit())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (typeReferenced.getPackageFragment().equals(member.getDeclaringType().getPackageFragment())) keyword= null; break; } case IJavaScriptElement.PACKAGE_FRAGMENT: { final IPackageFragment fragment= (IPackageFragment) referencing; if (typeReferenced.getPackageFragment().equals(fragment)) keyword= null; break; } default: Assert.isTrue(false); } break; } case IJavaScriptElement.FIELD: { final IField fieldReferenced= (IField) referenced; final IJavaScriptUnit referencedUnit= fieldReferenced.getJavaScriptUnit(); switch (referencingType) { case IJavaScriptElement.TYPE: { keyword= thresholdTypeToField((IType) referencing, fieldReferenced, monitor); break; } case IJavaScriptElement.FIELD: case IJavaScriptElement.METHOD: { final IMember member= (IMember) referencing; if (fieldReferenced.getDeclaringType().equals(member.getDeclaringType())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (referencedUnit != null && referencedUnit.equals(member.getJavaScriptUnit())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (fieldReferenced.getDeclaringType().getPackageFragment().equals(member.getDeclaringType().getPackageFragment())) keyword= null; break; } case IJavaScriptElement.PACKAGE_FRAGMENT: { final IPackageFragment fragment= (IPackageFragment) referencing; if (fieldReferenced.getDeclaringType().getPackageFragment().equals(fragment)) keyword= null; break; } default: Assert.isTrue(false); } break; } case IJavaScriptElement.METHOD: { final IFunction methodReferenced= (IFunction) referenced; final IJavaScriptUnit referencedUnit= methodReferenced.getJavaScriptUnit(); switch (referencingType) { case IJavaScriptElement.TYPE: { keyword= thresholdTypeToMethod((IType) referencing, methodReferenced, monitor); break; } case IJavaScriptElement.FIELD: case IJavaScriptElement.METHOD: { final IMember member= (IMember) referencing; if (methodReferenced.getDeclaringType().equals(member.getDeclaringType())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (referencedUnit != null && referencedUnit.equals(member.getJavaScriptUnit())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (methodReferenced.getDeclaringType().getPackageFragment().equals(member.getDeclaringType().getPackageFragment())) keyword= null; break; } case IJavaScriptElement.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 JavaScriptModelException if the java elements could not be accessed */ private ModifierKeyword computeOutgoingVisibilityThreshold(final IJavaScriptElement referencing, final IMember referenced, final IProgressMonitor monitor) throws JavaScriptModelException { Assert.isTrue(referencing instanceof IJavaScriptUnit || referencing instanceof IType || referencing instanceof IPackageFragment); Assert.isTrue(referenced instanceof IType || referenced instanceof IField || referenced instanceof IFunction); 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 IJavaScriptElement.TYPE: { final IType typeReferenced= (IType) referenced; switch (referencingType) { case IJavaScriptElement.JAVASCRIPT_UNIT: { final IJavaScriptUnit unit= (IJavaScriptUnit) referencing; final IJavaScriptUnit referencedUnit= typeReferenced.getJavaScriptUnit(); if (referencedUnit != null && referencedUnit.equals(unit)) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent())) keyword= null; break; } case IJavaScriptElement.TYPE: { keyword= thresholdTypeToType((IType) referencing, typeReferenced, monitor); break; } case IJavaScriptElement.PACKAGE_FRAGMENT: { final IPackageFragment fragment= (IPackageFragment) referencing; if (typeReferenced.getPackageFragment().equals(fragment)) keyword= null; break; } default: Assert.isTrue(false); } break; } case IJavaScriptElement.FIELD: { final IField fieldReferenced= (IField) referenced; final IJavaScriptUnit referencedUnit= fieldReferenced.getJavaScriptUnit(); switch (referencingType) { case IJavaScriptElement.JAVASCRIPT_UNIT: { final IJavaScriptUnit unit= (IJavaScriptUnit) referencing; if (referencedUnit != null && referencedUnit.equals(unit)) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent())) keyword= null; break; } case IJavaScriptElement.TYPE: { keyword= thresholdTypeToField((IType) referencing, fieldReferenced, monitor); break; } case IJavaScriptElement.PACKAGE_FRAGMENT: { final IPackageFragment fragment= (IPackageFragment) referencing; if (fieldReferenced.getDeclaringType().getPackageFragment().equals(fragment)) keyword= null; break; } default: Assert.isTrue(false); } break; } case IJavaScriptElement.METHOD: { final IFunction methodReferenced= (IFunction) referenced; final IJavaScriptUnit referencedUnit= methodReferenced.getJavaScriptUnit(); switch (referencingType) { case IJavaScriptElement.JAVASCRIPT_UNIT: { final IJavaScriptUnit unit= (IJavaScriptUnit) referencing; if (referencedUnit != null && referencedUnit.equals(unit)) keyword= ModifierKeyword.PRIVATE_KEYWORD; else if (referencedUnit != null && referencedUnit.getParent().equals(unit.getParent())) keyword= null; break; } case IJavaScriptElement.TYPE: { keyword= thresholdTypeToMethod((IType) referencing, methodReferenced, monitor); break; } case IJavaScriptElement.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 IJavaScriptUnit 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 JavaScriptModelException if the type hierarchy could not be created */ private ITypeHierarchy getTypeHierarchy(final IType type, final IProgressMonitor monitor) throws JavaScriptModelException { 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 JavaScriptModelException if an error occurs during search */ public final void rewriteVisibility(final IJavaScriptUnit unit, final IProgressMonitor monitor) throws JavaScriptModelException { 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.getJavaScriptUnit())) { 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 JavaScriptModelException if an error occurs during search */ public final void rewriteVisibility(final IProgressMonitor monitor) throws JavaScriptModelException { 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)); if (monitor.isCanceled()) throw new OperationCanceledException(); } } 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 JavaScriptUnit root) { Assert.isTrue(rewrite == null || root != null); fRewrite= rewrite; fRoot= root; } /** * Sets the compilation unit rewrites used by this adjustor (element type: Map <IJavaScriptUnit, 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 IJavaScriptSearchScope 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 JavaScriptModelException if the java elements could not be accessed */ private ModifierKeyword thresholdTypeToField(final IType referencing, final IField referenced, final IProgressMonitor monitor) throws JavaScriptModelException { ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; final IJavaScriptUnit referencedUnit= referenced.getJavaScriptUnit(); if (referenced.getDeclaringType().equals(referencing)) keyword= ModifierKeyword.PRIVATE_KEYWORD; else { final ITypeHierarchy hierarchy= getTypeHierarchy(referencing, new SubProgressMonitor(monitor, 1)); final IType superType= hierarchy.getSuperclass(referencing); if (superType.equals(referenced.getDeclaringType())) { keyword= ModifierKeyword.PROTECTED_KEYWORD; return keyword; } } final IJavaScriptUnit typeUnit= referencing.getJavaScriptUnit(); 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 JavaScriptModelException if the java elements could not be accessed */ private ModifierKeyword thresholdTypeToMethod(final IType referencing, final IFunction referenced, final IProgressMonitor monitor) throws JavaScriptModelException { final IJavaScriptUnit referencedUnit= referenced.getJavaScriptUnit(); 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 superType= hierarchy.getSuperclass(referencing); if (superType.equals(referenced.getDeclaringType())) { keyword= ModifierKeyword.PROTECTED_KEYWORD; return keyword; } } final IJavaScriptUnit typeUnit= referencing.getJavaScriptUnit(); 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 JavaScriptModelException if the java elements could not be accessed */ private ModifierKeyword thresholdTypeToType(final IType referencing, final IType referenced, final IProgressMonitor monitor) throws JavaScriptModelException { ModifierKeyword keyword= ModifierKeyword.PUBLIC_KEYWORD; final IJavaScriptUnit referencedUnit= referenced.getJavaScriptUnit(); if (referencing.equals(referenced.getDeclaringType())) keyword= ModifierKeyword.PRIVATE_KEYWORD; else { final ITypeHierarchy hierarchy= getTypeHierarchy(referencing, new SubProgressMonitor(monitor, 1)); final IType superType = hierarchy.getSuperclass(referencing); if (superType.equals(referenced)) { keyword= null; return keyword; } } final IJavaScriptUnit typeUnit= referencing.getJavaScriptUnit(); 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; } }