com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor.java

Source

/*
 * Copyright 2000-2010 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.refactoring.move.moveClassesOrPackages;

import java.util.*;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.wm.WindowManager;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PackageScope;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.util.MethodSignatureUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.MoveDestination;
import com.intellij.refactoring.PackageWrapper;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.refactoring.listeners.RefactoringElementListener;
import com.intellij.refactoring.move.MoveCallback;
import com.intellij.refactoring.move.MoveClassesOrPackagesCallback;
import com.intellij.refactoring.move.MoveMultipleElementsViewDescriptor;
import com.intellij.refactoring.rename.RenameUtil;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.refactoring.util.ConflictsUtil;
import com.intellij.refactoring.util.MoveRenameUsageInfo;
import com.intellij.refactoring.util.NonCodeUsageInfo;
import com.intellij.refactoring.util.RefactoringUIUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.intellij.refactoring.util.classRefs.ClassInstanceScanner;
import com.intellij.refactoring.util.classRefs.ClassReferenceScanner;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.usageView.UsageViewUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.VisibilityUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;

/**
 * @author Jeka,dsl
 */
public class MoveClassesOrPackagesProcessor extends BaseRefactoringProcessor {
    private static final Logger LOG = Logger
            .getInstance("#com.intellij.refactoring.move.moveClassesOrPackages.MoveClassesOrPackagesProcessor");

    private final PsiElement[] myElementsToMove;
    private boolean mySearchInComments;
    private boolean mySearchInNonJavaFiles;
    private final PackageWrapper myTargetPackage;
    private final MoveCallback myMoveCallback;
    protected @NotNull final MoveDestination myMoveDestination;
    protected NonCodeUsageInfo[] myNonCodeUsages;

    public MoveClassesOrPackagesProcessor(Project project, PsiElement[] elements,
            @NotNull final MoveDestination moveDestination, boolean searchInComments, boolean searchInNonJavaFiles,
            MoveCallback moveCallback) {
        super(project);
        final Set<PsiElement> toMove = new LinkedHashSet<PsiElement>();
        for (PsiElement element : elements) {
            if (element instanceof PsiClassOwner) {
                Collections.addAll(toMove, ((PsiClassOwner) element).getClasses());
            } else {
                toMove.add(element);
            }
        }
        myElementsToMove = PsiUtilCore.toPsiElementArray(toMove);
        Arrays.sort(myElementsToMove, new Comparator<PsiElement>() {
            @Override
            public int compare(PsiElement o1, PsiElement o2) {
                if (o1 instanceof PsiClass && o2 instanceof PsiClass) {
                    final PsiFile containingFile = o1.getContainingFile();
                    if (Comparing.equal(containingFile, o2.getContainingFile())) {
                        final VirtualFile virtualFile = containingFile.getVirtualFile();
                        if (virtualFile != null) {
                            final String fileName = virtualFile.getNameWithoutExtension();
                            if (Comparing.strEqual(fileName, ((PsiClass) o1).getName()))
                                return -1;
                            if (Comparing.strEqual(fileName, ((PsiClass) o2).getName()))
                                return 1;
                        }
                    }
                }
                return 0;
            }
        });
        myMoveDestination = moveDestination;
        myTargetPackage = myMoveDestination.getTargetPackage();
        mySearchInComments = searchInComments;
        mySearchInNonJavaFiles = searchInNonJavaFiles;
        myMoveCallback = moveCallback;
    }

    @NotNull
    protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
        PsiElement[] elements = new PsiElement[myElementsToMove.length];
        System.arraycopy(myElementsToMove, 0, elements, 0, myElementsToMove.length);
        return new MoveMultipleElementsViewDescriptor(elements,
                MoveClassesOrPackagesUtil.getPackageName(myTargetPackage));
    }

    public boolean verifyValidPackageName() {
        String qName = myTargetPackage.getQualifiedName();
        if (!StringUtil.isEmpty(qName)) {
            PsiNameHelper helper = PsiNameHelper.getInstance(myProject);
            if (!helper.isQualifiedName(qName)) {
                Messages.showMessageDialog(myProject,
                        RefactoringBundle.message("invalid.target.package.name.specified"), "Invalid Package Name",
                        Messages.getErrorIcon());
                return false;
            }
        }
        return true;
    }

    private boolean hasClasses() {
        for (PsiElement element : getElements()) {
            if (element instanceof PsiClass)
                return true;
        }
        return false;
    }

    public boolean isSearchInComments() {
        return mySearchInComments;
    }

    public boolean isSearchInNonJavaFiles() {
        return mySearchInNonJavaFiles;
    }

    public void setSearchInComments(boolean searchInComments) {
        mySearchInComments = searchInComments;
    }

    public void setSearchInNonJavaFiles(boolean searchInNonJavaFiles) {
        mySearchInNonJavaFiles = searchInNonJavaFiles;
    }

    @NotNull
    protected UsageInfo[] findUsages() {
        List<UsageInfo> allUsages = new ArrayList<UsageInfo>();
        MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
        for (PsiElement element : myElementsToMove) {
            String newName = getNewQName(element);
            if (newName == null)
                continue;
            final UsageInfo[] usages = MoveClassesOrPackagesUtil.findUsages(element, mySearchInComments,
                    mySearchInNonJavaFiles, newName);
            allUsages.addAll(new ArrayList<UsageInfo>(Arrays.asList(usages)));
            if (element instanceof PsiJavaPackage) {
                for (PsiDirectory directory : ((PsiJavaPackage) element).getDirectories()) {
                    final UsageInfo[] dirUsages = MoveClassesOrPackagesUtil.findUsages(directory,
                            mySearchInComments, mySearchInNonJavaFiles, newName);
                    allUsages.addAll(new ArrayList<UsageInfo>(Arrays.asList(dirUsages)));
                }
            }
        }
        myMoveDestination.analyzeModuleConflicts(Arrays.asList(myElementsToMove), conflicts,
                allUsages.toArray(new UsageInfo[allUsages.size()]));
        final UsageInfo[] usageInfos = allUsages.toArray(new UsageInfo[allUsages.size()]);
        detectPackageLocalsMoved(usageInfos, conflicts);
        detectPackageLocalsUsed(conflicts);
        if (!conflicts.isEmpty()) {
            for (PsiElement element : conflicts.keySet()) {
                allUsages.add(new ConflictsUsageInfo(element, conflicts.get(element)));
            }
        }

        return UsageViewUtil.removeDuplicatedUsages(allUsages.toArray(new UsageInfo[allUsages.size()]));
    }

    public List<PsiElement> getElements() {
        return Collections.unmodifiableList(Arrays.asList(myElementsToMove));
    }

    public PackageWrapper getTargetPackage() {
        return myMoveDestination.getTargetPackage();
    }

    protected static class ConflictsUsageInfo extends UsageInfo {
        private final Collection<String> myConflicts;

        public ConflictsUsageInfo(PsiElement pseudoElement, Collection<String> conflicts) {
            super(pseudoElement);
            myConflicts = conflicts;
        }

        public Collection<String> getConflicts() {
            return myConflicts;
        }
    }

    protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
        final UsageInfo[] usages = refUsages.get();
        final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
        ArrayList<UsageInfo> filteredUsages = new ArrayList<UsageInfo>();
        for (UsageInfo usage : usages) {
            if (usage instanceof ConflictsUsageInfo) {
                final ConflictsUsageInfo info = (ConflictsUsageInfo) usage;
                final PsiElement element = info.getElement();
                conflicts.putValues(element, info.getConflicts());
            } else {
                filteredUsages.add(usage);
            }
        }

        refUsages.set(filteredUsages.toArray(new UsageInfo[filteredUsages.size()]));
        return showConflicts(conflicts, usages);
    }

    private boolean isInsideMoved(PsiElement place) {
        for (PsiElement element : myElementsToMove) {
            if (element instanceof PsiClass) {
                if (PsiTreeUtil.isAncestor(element, place, false))
                    return true;
            }
        }
        return false;
    }

    private void detectPackageLocalsUsed(final MultiMap<PsiElement, String> conflicts) {
        PackageLocalsUsageCollector visitor = new PackageLocalsUsageCollector(myElementsToMove, myTargetPackage,
                conflicts);

        for (PsiElement element : myElementsToMove) {
            if (element instanceof PsiClass) {
                PsiClass aClass = (PsiClass) element;
                aClass.accept(visitor);
            }
        }
    }

    private void detectPackageLocalsMoved(final UsageInfo[] usages, final MultiMap<PsiElement, String> conflicts) {
        //    final HashSet reportedPackageLocalUsed = new HashSet();
        final HashSet<PsiClass> movedClasses = new HashSet<PsiClass>();
        final HashMap<PsiClass, HashSet<PsiElement>> reportedClassToContainers = new HashMap<PsiClass, HashSet<PsiElement>>();
        final PackageWrapper aPackage = myTargetPackage;
        for (UsageInfo usage : usages) {
            PsiElement element = usage.getElement();
            if (element == null)
                continue;
            if (usage instanceof MoveRenameUsageInfo && !(usage instanceof NonCodeUsageInfo)
                    && ((MoveRenameUsageInfo) usage).getReferencedElement() instanceof PsiClass) {
                PsiClass aClass = (PsiClass) ((MoveRenameUsageInfo) usage).getReferencedElement();
                if (!movedClasses.contains(aClass)) {
                    movedClasses.add(aClass);
                }
                String visibility = VisibilityUtil.getVisibilityModifier(aClass.getModifierList());
                if (PsiModifier.PACKAGE_LOCAL.equals(visibility)) {
                    if (PsiTreeUtil.getParentOfType(element, PsiImportStatement.class) != null)
                        continue;
                    PsiElement container = ConflictsUtil.getContainer(element);
                    HashSet<PsiElement> reported = reportedClassToContainers.get(aClass);
                    if (reported == null) {
                        reported = new HashSet<PsiElement>();
                        reportedClassToContainers.put(aClass, reported);
                    }

                    if (!reported.contains(container)) {
                        reported.add(container);
                        PsiFile containingFile = element.getContainingFile();
                        if (containingFile != null && !isInsideMoved(element)) {
                            PsiDirectory directory = containingFile.getContainingDirectory();
                            if (directory != null) {
                                PsiJavaPackage usagePackage = JavaDirectoryService.getInstance()
                                        .getPackage(directory);
                                if (aPackage != null && usagePackage != null
                                        && !aPackage.equalToPackage(usagePackage)) {

                                    final String message = RefactoringBundle.message(
                                            "a.package.local.class.0.will.no.longer.be.accessible.from.1",
                                            CommonRefactoringUtil.htmlEmphasize(aClass.getName()),
                                            RefactoringUIUtil.getDescription(container, true));
                                    conflicts.putValue(aClass, message);
                                }
                            }
                        }
                    }
                }
            }
        }

        final MyClassInstanceReferenceVisitor instanceReferenceVisitor = new MyClassInstanceReferenceVisitor(
                conflicts);
        for (final PsiClass aClass : movedClasses) {
            String visibility = VisibilityUtil.getVisibilityModifier(aClass.getModifierList());
            if (PsiModifier.PACKAGE_LOCAL.equals(visibility)) {
                findInstancesOfPackageLocal(aClass, usages, instanceReferenceVisitor);
            } else {
                // public classes
                findPublicClassConflicts(aClass, instanceReferenceVisitor);
            }
        }
    }

    static class ClassMemberWrapper {
        final PsiNamedElement myElement;
        final PsiModifierListOwner myMember;

        public ClassMemberWrapper(PsiNamedElement element) {
            myElement = element;
            myMember = (PsiModifierListOwner) element;
        }

        PsiModifierListOwner getMember() {
            return myMember;
        }

        public boolean equals(Object o) {
            if (this == o)
                return true;
            if (!(o instanceof ClassMemberWrapper))
                return false;

            ClassMemberWrapper wrapper = (ClassMemberWrapper) o;

            if (myElement instanceof PsiMethod) {
                return wrapper.myElement instanceof PsiMethod && MethodSignatureUtil
                        .areSignaturesEqual((PsiMethod) myElement, (PsiMethod) wrapper.myElement);
            }

            return Comparing.equal(myElement.getName(), wrapper.myElement.getName());
        }

        public int hashCode() {
            final String name = myElement.getName();
            if (name != null) {
                return name.hashCode();
            } else {
                return 0;
            }
        }
    }

    private static void findPublicClassConflicts(PsiClass aClass,
            final MyClassInstanceReferenceVisitor instanceReferenceVisitor) {
        //noinspection MismatchedQueryAndUpdateOfCollection
        NonPublicClassMemberWrappersSet members = new NonPublicClassMemberWrappersSet();

        members.addElements(aClass.getFields());
        members.addElements(aClass.getMethods());
        members.addElements(aClass.getInnerClasses());

        final RefactoringUtil.IsDescendantOf isDescendantOf = new RefactoringUtil.IsDescendantOf(aClass);
        final PsiJavaPackage aPackage = JavaDirectoryService.getInstance()
                .getPackage(aClass.getContainingFile().getContainingDirectory());
        final GlobalSearchScope packageScope = aPackage == null ? aClass.getResolveScope()
                : PackageScope.packageScopeWithoutLibraries(aPackage, false);
        for (final ClassMemberWrapper memberWrapper : members) {
            ReferencesSearch.search(memberWrapper.getMember(), packageScope, false)
                    .forEach(new Processor<PsiReference>() {
                        public boolean process(final PsiReference reference) {
                            final PsiElement element = reference.getElement();
                            if (element instanceof PsiReferenceExpression) {
                                final PsiReferenceExpression expression = (PsiReferenceExpression) element;
                                final PsiExpression qualifierExpression = expression.getQualifierExpression();
                                if (qualifierExpression != null) {
                                    final PsiType type = qualifierExpression.getType();
                                    if (type != null) {
                                        final PsiClass resolvedTypeClass = PsiUtil.resolveClassInType(type);
                                        if (isDescendantOf.value(resolvedTypeClass)) {
                                            instanceReferenceVisitor.visitMemberReference(memberWrapper.getMember(),
                                                    expression, isDescendantOf);
                                        }
                                    }
                                } else {
                                    instanceReferenceVisitor.visitMemberReference(memberWrapper.getMember(),
                                            expression, isDescendantOf);
                                }
                            }
                            return true;
                        }
                    });
        }
    }

    private static void findInstancesOfPackageLocal(final PsiClass aClass, final UsageInfo[] usages,
            final MyClassInstanceReferenceVisitor instanceReferenceVisitor) {
        ClassReferenceScanner referenceScanner = new ClassReferenceScanner(aClass) {
            public PsiReference[] findReferences() {
                ArrayList<PsiReference> result = new ArrayList<PsiReference>();
                for (UsageInfo usage : usages) {
                    if (usage instanceof MoveRenameUsageInfo
                            && ((MoveRenameUsageInfo) usage).getReferencedElement() == aClass) {
                        final PsiReference reference = usage.getReference();
                        if (reference != null) {
                            result.add(reference);
                        }
                    }
                }
                return result.toArray(new PsiReference[result.size()]);
            }
        };
        referenceScanner.processReferences(new ClassInstanceScanner(aClass, instanceReferenceVisitor));
    }

    @Nullable
    private String getNewQName(PsiElement element) {
        final String qualifiedName = myTargetPackage.getQualifiedName();
        final String newQName;
        final String oldQName;
        if (element instanceof PsiClass) {
            newQName = StringUtil.getQualifiedName(qualifiedName, ((PsiClass) element).getName());
            oldQName = ((PsiClass) element).getQualifiedName();
        } else if (element instanceof PsiJavaPackage) {
            newQName = StringUtil.getQualifiedName(qualifiedName, ((PsiJavaPackage) element).getName());
            oldQName = ((PsiJavaPackage) element).getQualifiedName();
        } else {
            LOG.assertTrue(false);
            newQName = null;
            oldQName = null;
        }
        if (Comparing.strEqual(newQName, oldQName))
            return null;
        return newQName;
    }

    protected void refreshElements(PsiElement[] elements) {
        LOG.assertTrue(elements.length == myElementsToMove.length);
        System.arraycopy(elements, 0, myElementsToMove, 0, elements.length);
    }

    protected boolean isPreviewUsages(UsageInfo[] usages) {
        if (UsageViewUtil.hasNonCodeUsages(usages)) {
            WindowManager.getInstance().getStatusBar(myProject)
                    .setInfo(RefactoringBundle.message("occurrences.found.in.comments.strings.and.non.java.files"));
            return true;
        } else {
            return super.isPreviewUsages(usages);
        }
    }

    protected void performRefactoring(UsageInfo[] usages) {
        // If files are being moved then I need to collect some information to delete these
        // filese from CVS. I need to know all common parents of the moved files and releative
        // paths.

        // Move files with correction of references.

        try {
            final Map<PsiClass, Boolean> allClasses = new HashMap<PsiClass, Boolean>();
            for (PsiElement element : myElementsToMove) {
                if (element instanceof PsiClass) {
                    final PsiClass psiClass = (PsiClass) element;
                    if (allClasses.containsKey(psiClass)) {
                        continue;
                    }
                    for (MoveAllClassesInFileHandler fileHandler : Extensions
                            .getExtensions(MoveAllClassesInFileHandler.EP_NAME)) {
                        fileHandler.processMoveAllClassesInFile(allClasses, psiClass, myElementsToMove);
                    }
                }
            }
            final Map<PsiElement, PsiElement> oldToNewElementsMapping = new HashMap<PsiElement, PsiElement>();
            for (int idx = 0; idx < myElementsToMove.length; idx++) {
                PsiElement element = myElementsToMove[idx];
                final RefactoringElementListener elementListener = getTransaction().getElementListener(element);
                if (element instanceof PsiJavaPackage) {
                    final PsiDirectory[] directories = ((PsiJavaPackage) element).getDirectories();
                    final PsiJavaPackage newElement = MoveClassesOrPackagesUtil
                            .doMovePackage((PsiJavaPackage) element, myMoveDestination);
                    LOG.assertTrue(newElement != null, element);
                    oldToNewElementsMapping.put(element, newElement);
                    int i = 0;
                    final PsiDirectory[] newDirectories = newElement.getDirectories();
                    if (newDirectories.length == 1) {//everything is moved in one directory
                        for (PsiDirectory directory : directories) {
                            oldToNewElementsMapping.put(directory, newDirectories[0]);
                        }
                    } else {
                        for (PsiDirectory directory : directories) {
                            oldToNewElementsMapping.put(directory, newDirectories[i++]);
                        }
                    }
                    element = newElement;
                } else if (element instanceof PsiClass) {
                    final PsiClass psiClass = (PsiClass) element;
                    MoveClassesOrPackagesUtil.prepareMoveClass(psiClass);
                    final PsiClass newElement = MoveClassesOrPackagesUtil.doMoveClass(psiClass,
                            myMoveDestination.getTargetDirectory(element.getContainingFile()),
                            allClasses.get(psiClass));
                    oldToNewElementsMapping.put(element, newElement);
                    element = newElement;
                } else {
                    LOG.error("Unexpected element to move: " + element);
                }
                elementListener.elementMoved(element);
                myElementsToMove[idx] = element;
            }

            for (PsiElement element : myElementsToMove) {
                if (element instanceof PsiClass) {
                    MoveClassesOrPackagesUtil.finishMoveClass((PsiClass) element);
                }
            }

            myNonCodeUsages = CommonMoveUtil.retargetUsages(usages, oldToNewElementsMapping);
        } catch (IncorrectOperationException e) {
            myNonCodeUsages = new NonCodeUsageInfo[0];
            RefactoringUIUtil.processIncorrectOperation(myProject, e);
        }
    }

    protected void performPsiSpoilingRefactoring() {
        RenameUtil.renameNonCodeUsages(myProject, myNonCodeUsages);
        if (myMoveCallback != null) {
            if (myMoveCallback instanceof MoveClassesOrPackagesCallback) {
                ((MoveClassesOrPackagesCallback) myMoveCallback).classesOrPackagesMoved(myMoveDestination);
            }
            myMoveCallback.refactoringCompleted();
        }
    }

    protected String getCommandName() {
        String elements = RefactoringUIUtil.calculatePsiElementDescriptionList(myElementsToMove);
        String target = myTargetPackage.getQualifiedName();
        return RefactoringBundle.message("move.classes.command", elements, target);
    }

    private class MyClassInstanceReferenceVisitor implements ClassInstanceScanner.ClassInstanceReferenceVisitor {
        private final MultiMap<PsiElement, String> myConflicts;
        private final HashMap<PsiModifierListOwner, HashSet<PsiElement>> myReportedElementToContainer = new HashMap<PsiModifierListOwner, HashSet<PsiElement>>();
        private final HashMap<PsiClass, RefactoringUtil.IsDescendantOf> myIsDescendantOfCache = new HashMap<PsiClass, RefactoringUtil.IsDescendantOf>();

        public MyClassInstanceReferenceVisitor(MultiMap<PsiElement, String> conflicts) {
            myConflicts = conflicts;
        }

        public void visitQualifier(PsiReferenceExpression qualified, PsiExpression instanceRef,
                PsiElement referencedInstance) {
            PsiElement resolved = qualified.resolve();

            if (resolved instanceof PsiMember) {
                final PsiMember member = (PsiMember) resolved;
                final PsiClass containingClass = member.getContainingClass();
                RefactoringUtil.IsDescendantOf isDescendantOf = myIsDescendantOfCache.get(containingClass);
                if (isDescendantOf == null) {
                    isDescendantOf = new RefactoringUtil.IsDescendantOf(containingClass);
                    myIsDescendantOfCache.put(containingClass, isDescendantOf);
                }
                visitMemberReference(member, qualified, isDescendantOf);
            }
        }

        private synchronized void visitMemberReference(final PsiModifierListOwner member,
                PsiReferenceExpression qualified, final RefactoringUtil.IsDescendantOf descendantOf) {
            if (member.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
                visitPackageLocalMemberReference(qualified, member);
            } else if (member.hasModifierProperty(PsiModifier.PROTECTED)) {
                final PsiExpression qualifier = qualified.getQualifierExpression();
                if (qualifier != null && !(qualifier instanceof PsiThisExpression)
                        && !(qualifier instanceof PsiSuperExpression)) {
                    visitPackageLocalMemberReference(qualified, member);
                } else {
                    if (!isInInheritor(qualified, descendantOf)) {
                        visitPackageLocalMemberReference(qualified, member);
                    }
                }
            }
        }

        private boolean isInInheritor(PsiReferenceExpression qualified,
                final RefactoringUtil.IsDescendantOf descendantOf) {
            PsiClass aClass = PsiTreeUtil.getParentOfType(qualified, PsiClass.class);
            while (aClass != null) {
                if (descendantOf.value(aClass))
                    return true;
                aClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class);
            }
            return false;
        }

        private void visitPackageLocalMemberReference(PsiJavaCodeReferenceElement qualified,
                PsiModifierListOwner member) {
            PsiElement container = ConflictsUtil.getContainer(qualified);
            HashSet<PsiElement> reportedContainers = myReportedElementToContainer.get(member);
            if (reportedContainers == null) {
                reportedContainers = new HashSet<PsiElement>();
                myReportedElementToContainer.put(member, reportedContainers);
            }

            if (!reportedContainers.contains(container)) {
                reportedContainers.add(container);
                if (!isInsideMoved(container)) {
                    PsiFile containingFile = container.getContainingFile();
                    if (containingFile != null) {
                        PsiDirectory directory = containingFile.getContainingDirectory();
                        if (directory != null) {
                            PsiJavaPackage aPackage = JavaDirectoryService.getInstance().getPackage(directory);
                            if (!myTargetPackage.equalToPackage(aPackage)) {
                                String message = RefactoringBundle.message("0.will.be.inaccessible.from.1",
                                        RefactoringUIUtil.getDescription(member, true),
                                        RefactoringUIUtil.getDescription(container, true));
                                myConflicts.putValue(member, CommonRefactoringUtil.capitalize(message));
                            }
                        }
                    }
                }
            }
        }

        public void visitTypeCast(PsiTypeCastExpression typeCastExpression, PsiExpression instanceRef,
                PsiElement referencedInstance) {
        }

        public void visitReadUsage(PsiExpression instanceRef, PsiType expectedType, PsiElement referencedInstance) {
        }

        public void visitWriteUsage(PsiExpression instanceRef, PsiType assignedType,
                PsiElement referencedInstance) {
        }
    }

    private static class NonPublicClassMemberWrappersSet extends HashSet<ClassMemberWrapper> {
        public void addElement(PsiMember member) {
            final PsiNamedElement namedElement = (PsiNamedElement) member;
            if (member.hasModifierProperty(PsiModifier.PUBLIC))
                return;
            if (member.hasModifierProperty(PsiModifier.PRIVATE))
                return;
            add(new ClassMemberWrapper(namedElement));
        }

        public void addElements(PsiMember[] members) {
            for (PsiMember member : members) {
                addElement(member);
            }
        }
    }
}