mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
Move Member conflict analysis delegated into handler
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
@@ -24,6 +23,7 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.refactoring.util.FieldConflictsResolver;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class ChangeContextUtil {
|
||||
@@ -112,28 +112,28 @@ public class ChangeContextUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static PsiElement decodeContextInfo(PsiElement scope,
|
||||
PsiClass thisClass,
|
||||
public static PsiElement decodeContextInfo(@NotNull PsiElement scope,
|
||||
@Nullable PsiClass thisClass,
|
||||
@Nullable PsiExpression thisAccessExpr) throws IncorrectOperationException {
|
||||
if (scope.getCopyableUserData(ENCODED_KEY) != null){
|
||||
if (scope.getCopyableUserData(ENCODED_KEY) != null) {
|
||||
scope.putCopyableUserData(ENCODED_KEY, null);
|
||||
|
||||
if (scope instanceof PsiThisExpression){
|
||||
if (scope instanceof PsiThisExpression) {
|
||||
PsiThisExpression thisExpr = (PsiThisExpression)scope;
|
||||
scope = decodeThisExpression(thisExpr, thisClass, thisAccessExpr);
|
||||
}
|
||||
else if (scope instanceof PsiReferenceExpression){
|
||||
else if (scope instanceof PsiReferenceExpression) {
|
||||
scope = decodeReferenceExpression((PsiReferenceExpression)scope, thisAccessExpr, thisClass);
|
||||
}
|
||||
else {
|
||||
PsiClass refClass = scope.getCopyableUserData(REF_CLASS_KEY);
|
||||
scope.putCopyableUserData(REF_CLASS_KEY, null);
|
||||
|
||||
if (refClass != null && refClass.isValid()){
|
||||
if (refClass != null && refClass.isValid()) {
|
||||
PsiReference ref = scope.getReference();
|
||||
if (ref != null) {
|
||||
final String qualifiedName = refClass.getQualifiedName();
|
||||
if (qualifiedName != null){
|
||||
if (qualifiedName != null) {
|
||||
if (JavaPsiFacade.getInstance(refClass.getProject()).findClass(qualifiedName, scope.getResolveScope()) != null) {
|
||||
scope = ref.bindToElement(refClass);
|
||||
}
|
||||
@@ -143,14 +143,15 @@ public class ChangeContextUtil {
|
||||
}
|
||||
}
|
||||
|
||||
if (scope instanceof PsiClass){
|
||||
if (thisAccessExpr != null){
|
||||
if (scope instanceof PsiClass) {
|
||||
if (thisAccessExpr != null) {
|
||||
thisAccessExpr = (PsiExpression)qualifyThis(thisAccessExpr, thisClass);
|
||||
}
|
||||
}
|
||||
|
||||
for(PsiElement child = scope.getFirstChild(); child != null; child = child.getNextSibling()){
|
||||
child = decodeContextInfo(child, thisClass, thisAccessExpr);
|
||||
PsiElement child = scope.getFirstChild();
|
||||
while (child != null) {
|
||||
child = decodeContextInfo(child, thisClass, thisAccessExpr).getNextSibling();
|
||||
}
|
||||
|
||||
return scope;
|
||||
|
||||
+124
-28
@@ -16,16 +16,21 @@
|
||||
package com.intellij.refactoring.move.moveMembers;
|
||||
|
||||
import com.intellij.codeInsight.ChangeContextUtil;
|
||||
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
|
||||
import com.intellij.psi.search.LocalSearchScope;
|
||||
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.PsiUtilBase;
|
||||
import com.intellij.refactoring.util.EnumConstantsUtil;
|
||||
import com.intellij.refactoring.util.RefactoringHierarchyUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.*;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.intellij.util.VisibilityUtil;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
@@ -33,12 +38,13 @@ import java.util.*;
|
||||
/**
|
||||
* @author Maxim.Medvedev
|
||||
*/
|
||||
|
||||
public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
public MoveMembersProcessor.MoveMembersUsageInfo getUsage(PsiMember member,
|
||||
PsiReference psiReference,
|
||||
Set<PsiMember> membersToMove,
|
||||
PsiClass targetClass) {
|
||||
@Override
|
||||
@Nullable
|
||||
public MoveMembersProcessor.MoveMembersUsageInfo getUsage(@NotNull PsiMember member,
|
||||
@NotNull PsiReference psiReference,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull PsiClass targetClass) {
|
||||
PsiElement ref = psiReference.getElement();
|
||||
if (ref instanceof PsiReferenceExpression) {
|
||||
PsiReferenceExpression refExpr = (PsiReferenceExpression)ref;
|
||||
@@ -70,15 +76,102 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isInMovedElement(PsiElement element, Set<PsiMember> membersToMove) {
|
||||
protected static boolean isInMovedElement(PsiElement element, Set<PsiMember> membersToMove) {
|
||||
for (PsiMember member : membersToMove) {
|
||||
if (PsiTreeUtil.isAncestor(member, element, false)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean changeExternalUsage(MoveMembersOptions options, MoveMembersProcessor.MoveMembersUsageInfo usage) {
|
||||
if (!usage.getElement().isValid()) return true;
|
||||
@Override
|
||||
public void checkConflictsOnUsage(@NotNull MoveMembersProcessor.MoveMembersUsageInfo usageInfo,
|
||||
@Nullable String newVisibility,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@NotNull PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
final PsiElement element = usageInfo.getElement();
|
||||
if (element == null) return;
|
||||
|
||||
final PsiMember member = usageInfo.member;
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
|
||||
PsiClass accessObjectClass = null;
|
||||
if (qualifier != null) {
|
||||
accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
|
||||
}
|
||||
|
||||
if (!JavaResolveUtil.isAccessible(member, targetClass, modifierListCopy, element, accessObjectClass, null)) {
|
||||
String visibility = newVisibility != null ? newVisibility : VisibilityUtil.getVisibilityStringToDisplay(member);
|
||||
String message = RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2",
|
||||
RefactoringUIUtil.getDescription(member, false),
|
||||
visibility,
|
||||
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true));
|
||||
conflicts.putValue(member, CommonRefactoringUtil.capitalize(message));
|
||||
}
|
||||
}
|
||||
|
||||
if (member instanceof PsiField && targetClass.isInterface()) {
|
||||
ReadWriteAccessDetector accessDetector = ReadWriteAccessDetector.findDetector(member);
|
||||
if (accessDetector != null) {
|
||||
ReadWriteAccessDetector.Access access = accessDetector.getExpressionAccess(element);
|
||||
if (access != ReadWriteAccessDetector.Access.Read) {
|
||||
String message = RefactoringUIUtil.getDescription(member, true) + " has write access but is moved to an interface";
|
||||
conflicts.putValue(element, CommonRefactoringUtil.capitalize(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PsiReference reference = usageInfo.getReference();
|
||||
if (reference != null) {
|
||||
RefactoringConflictsUtil.checkAccessibilityConflicts(reference, member, modifierListCopy, targetClass, membersToMove, conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkConflictsOnMember(@NotNull PsiMember member,
|
||||
@Nullable String newVisibility,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@NotNull PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
if (member instanceof PsiMethod && hasMethod(targetClass, (PsiMethod)member) ||
|
||||
member instanceof PsiField && hasField(targetClass, (PsiField)member)) {
|
||||
String message = RefactoringBundle.message("0.already.exists.in.the.target.class", RefactoringUIUtil.getDescription(member, false));
|
||||
conflicts.putValue(member, CommonRefactoringUtil.capitalize(message));
|
||||
}
|
||||
|
||||
RefactoringConflictsUtil.checkUsedElements(member, member, membersToMove, null, targetClass, targetClass, conflicts);
|
||||
}
|
||||
|
||||
protected static boolean hasMethod(PsiClass targetClass, PsiMethod method) {
|
||||
PsiMethod[] targetClassMethods = targetClass.getMethods();
|
||||
for (PsiMethod candidate : targetClassMethods) {
|
||||
if (candidate != method &&
|
||||
MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY),
|
||||
candidate.getSignature(PsiSubstitutor.EMPTY))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected static boolean hasField(PsiClass targetClass, PsiField field) {
|
||||
String fieldName = field.getName();
|
||||
PsiField[] targetClassFields = targetClass.getFields();
|
||||
for (PsiField candidate : targetClassFields) {
|
||||
if (candidate != field &&
|
||||
fieldName.equals(candidate.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean changeExternalUsage(@NotNull MoveMembersOptions options, @NotNull MoveMembersProcessor.MoveMembersUsageInfo usage) {
|
||||
final PsiElement element = usage.getElement();
|
||||
if (element == null || !element.isValid()) return true;
|
||||
|
||||
if (usage.reference instanceof PsiReferenceExpression) {
|
||||
PsiReferenceExpression refExpr = (PsiReferenceExpression)usage.reference;
|
||||
@@ -101,14 +194,24 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
public PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass) {
|
||||
protected static void changeQualifier(PsiReferenceExpression refExpr, PsiClass aClass, PsiMember member) throws IncorrectOperationException {
|
||||
if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) {
|
||||
refExpr.setQualifierExpression(null);
|
||||
}
|
||||
else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)){
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory();
|
||||
refExpr.setQualifierExpression(factory.createReferenceExpression(aClass));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public PsiMember doMove(@NotNull MoveMembersOptions options, @NotNull PsiMember member, PsiElement anchor, @NotNull PsiClass targetClass) {
|
||||
if (member instanceof PsiVariable) {
|
||||
((PsiVariable)member).normalizeDeclaration();
|
||||
}
|
||||
|
||||
ChangeContextUtil.encodeContextInfo(member, true);
|
||||
if (targetClass == null) return null;
|
||||
|
||||
|
||||
final PsiMember memberCopy;
|
||||
if (options.makeEnumConstant() &&
|
||||
@@ -118,8 +221,9 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
}
|
||||
else {
|
||||
memberCopy = (PsiMember)member.copy();
|
||||
if (member.getContainingClass().isInterface() && !targetClass.isInterface()) {
|
||||
//might need to make modifiers explicit, see IDEADEV-11416
|
||||
final PsiClass containingClass = member.getContainingClass();
|
||||
if (containingClass != null && containingClass.isInterface() && !targetClass.isInterface()) {
|
||||
// might need to make modifiers explicit, see IDEADEV-11416
|
||||
final PsiModifierList list = memberCopy.getModifierList();
|
||||
assert list != null;
|
||||
list.setModifierProperty(PsiModifier.STATIC, member.hasModifierProperty(PsiModifier.STATIC));
|
||||
@@ -131,22 +235,14 @@ public class MoveJavaMemberHandler implements MoveMemberHandler {
|
||||
return anchor != null ? (PsiMember)targetClass.addAfter(memberCopy, anchor) : (PsiMember)targetClass.add(memberCopy);
|
||||
}
|
||||
|
||||
public void decodeContextInfo(PsiElement scope) {
|
||||
@Override
|
||||
public void decodeContextInfo(@NotNull PsiElement scope) {
|
||||
ChangeContextUtil.decodeContextInfo(scope, null, null);
|
||||
}
|
||||
|
||||
private static void changeQualifier(PsiReferenceExpression refExpr, PsiClass aClass, PsiMember member) throws IncorrectOperationException {
|
||||
if (RefactoringUtil.hasOnDemandStaticImport(refExpr, aClass)) {
|
||||
refExpr.setQualifierExpression(null);
|
||||
}
|
||||
else if (!RefactoringUtil.hasStaticImportOn(refExpr, member)){
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(refExpr.getProject()).getElementFactory();
|
||||
refExpr.setQualifierExpression(factory.createReferenceExpression(aClass));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiElement getAnchor(final PsiMember member, final PsiClass targetClass) {
|
||||
public PsiElement getAnchor(@NotNull final PsiMember member, @NotNull final PsiClass targetClass) {
|
||||
if (member instanceof PsiField && member.hasModifierProperty(PsiModifier.STATIC)) {
|
||||
final List<PsiField> afterFields = new ArrayList<PsiField>();
|
||||
final PsiExpression psiExpression = ((PsiField)member).getInitializer();
|
||||
|
||||
+31
-13
@@ -16,10 +16,9 @@
|
||||
package com.intellij.refactoring.move.moveMembers;
|
||||
|
||||
import com.intellij.lang.LanguageExtension;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiMember;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
@@ -30,17 +29,36 @@ import java.util.Set;
|
||||
public interface MoveMemberHandler {
|
||||
LanguageExtension<MoveMemberHandler> EP_NAME = new LanguageExtension<MoveMemberHandler>("com.intellij.refactoring.moveMemberHandler");
|
||||
|
||||
MoveMembersProcessor.MoveMembersUsageInfo getUsage(PsiMember member,
|
||||
PsiReference ref,
|
||||
Set<PsiMember> membersToMove,
|
||||
PsiClass targetClass);
|
||||
@Nullable
|
||||
MoveMembersProcessor.MoveMembersUsageInfo getUsage(@NotNull PsiMember member,
|
||||
@NotNull PsiReference ref,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull PsiClass targetClass);
|
||||
|
||||
boolean changeExternalUsage(MoveMembersOptions options, MoveMembersProcessor.MoveMembersUsageInfo usage);
|
||||
void checkConflictsOnUsage(@NotNull MoveMembersProcessor.MoveMembersUsageInfo usageInfo,
|
||||
@Nullable String newVisibility,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@NotNull PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts);
|
||||
|
||||
PsiMember doMove(MoveMembersOptions options, PsiMember member, PsiElement anchor, PsiClass targetClass);
|
||||
|
||||
void decodeContextInfo(PsiElement scope);
|
||||
void checkConflictsOnMember(@NotNull PsiMember member,
|
||||
@Nullable String newVisibility,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@NotNull PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts);
|
||||
|
||||
@Nullable
|
||||
PsiElement getAnchor(PsiMember member, PsiClass targetClass);
|
||||
PsiElement getAnchor(@NotNull PsiMember member, @NotNull PsiClass targetClass);
|
||||
|
||||
boolean changeExternalUsage(@NotNull MoveMembersOptions options, @NotNull MoveMembersProcessor.MoveMembersUsageInfo usage);
|
||||
|
||||
@NotNull
|
||||
PsiMember doMove(@NotNull MoveMembersOptions options,
|
||||
@NotNull PsiMember member,
|
||||
@Nullable PsiElement anchor,
|
||||
@NotNull PsiClass targetClass);
|
||||
|
||||
void decodeContextInfo(@NotNull PsiElement scope);
|
||||
}
|
||||
|
||||
+61
-109
@@ -15,17 +15,13 @@
|
||||
*/
|
||||
package com.intellij.refactoring.move.moveMembers;
|
||||
|
||||
import com.intellij.codeInsight.highlighting.ReadWriteAccessDetector;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
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.PsiUtilBase;
|
||||
import com.intellij.refactoring.BaseRefactoringProcessor;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
@@ -34,7 +30,9 @@ import com.intellij.refactoring.listeners.RefactoringElementListener;
|
||||
import com.intellij.refactoring.move.MoveCallback;
|
||||
import com.intellij.refactoring.move.MoveHandler;
|
||||
import com.intellij.refactoring.move.MoveMemberViewDescriptor;
|
||||
import com.intellij.refactoring.util.*;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.MoveRenameUsageInfo;
|
||||
import com.intellij.refactoring.util.RefactoringConflictsUtil;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.usageView.UsageViewUtil;
|
||||
@@ -44,6 +42,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -61,16 +60,16 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
private String myCommandName = MoveMembersImpl.REFACTORING_NAME;
|
||||
private MoveMembersOptions myOptions;
|
||||
|
||||
public MoveMembersProcessor(Project project, MoveCallback moveCallback, MoveMembersOptions options) {
|
||||
public MoveMembersProcessor(Project project, MoveMembersOptions options) {
|
||||
this(project, null, options);
|
||||
}
|
||||
|
||||
public MoveMembersProcessor(Project project, @Nullable MoveCallback moveCallback, MoveMembersOptions options) {
|
||||
super(project);
|
||||
myMoveCallback = moveCallback;
|
||||
setOptions(options);
|
||||
}
|
||||
|
||||
public MoveMembersProcessor(Project project, MoveMembersOptions options) {
|
||||
this(project, null, options);
|
||||
}
|
||||
|
||||
protected String getCommandName() {
|
||||
return myCommandName;
|
||||
}
|
||||
@@ -152,10 +151,11 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
|
||||
protected void performRefactoring(final UsageInfo[] usages) {
|
||||
try {
|
||||
// correct references to moved members from the outside
|
||||
PsiClass targetClass = JavaPsiFacade.getInstance(myProject).findClass(myOptions.getTargetClassName(),
|
||||
GlobalSearchScope.projectScope(myProject));
|
||||
if (targetClass == null) return;
|
||||
|
||||
// collect anchors to place moved members at
|
||||
final Map<PsiMember, PsiElement> anchors = new HashMap<PsiMember, PsiElement>();
|
||||
for (PsiMember member : myMembersToMove) {
|
||||
final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage());
|
||||
@@ -163,12 +163,14 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
anchors.put(member, handler.getAnchor(member, targetClass));
|
||||
}
|
||||
}
|
||||
|
||||
// correct references to moved members from the outside
|
||||
ArrayList<MoveMembersUsageInfo> otherUsages = new ArrayList<MoveMembersUsageInfo>();
|
||||
for (UsageInfo usageInfo : usages) {
|
||||
MoveMembersUsageInfo usage = (MoveMembersUsageInfo)usageInfo;
|
||||
if (!usage.reference.isValid()) continue;
|
||||
final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(usageInfo.getElement().getLanguage());
|
||||
if (handler!=null) {
|
||||
if (handler != null) {
|
||||
if (handler.changeExternalUsage(myOptions, usage)) continue;
|
||||
}
|
||||
otherUsages.add(usage);
|
||||
@@ -190,7 +192,7 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
final RefactoringElementListener elementListener = getTransaction().getElementListener(member);
|
||||
final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage());
|
||||
if (handler != null) {
|
||||
PsiMember newMember=handler.doMove(myOptions, member, anchors.get(member), targetClass);
|
||||
PsiMember newMember = handler.doMove(myOptions, member, anchors.get(member), targetClass);
|
||||
elementListener.elementMoved(newMember);
|
||||
|
||||
fixModifierList(newMember, usages);
|
||||
@@ -201,7 +203,6 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
}
|
||||
|
||||
// qualifier info must be decoded after members are moved
|
||||
//ChangeContextUtil.decodeContextInfo(myTargetClass, null, null);
|
||||
final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(myTargetClass.getLanguage());
|
||||
if (handler != null) handler.decodeContextInfo(myTargetClass);
|
||||
|
||||
@@ -236,65 +237,63 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
|
||||
final MultiMap<PsiElement, String> conflicts = new MultiMap<PsiElement, String>();
|
||||
final UsageInfo[] usages = refUsages.get();
|
||||
try {
|
||||
addInaccessibleConflicts(conflicts, usages);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
analyzeMoveConflicts(myMembersToMove, myTargetClass, myNewVisibility, conflicts);
|
||||
RefactoringConflictsUtil.analyzeModuleConflicts(myProject, myMembersToMove, usages, myTargetClass, conflicts);
|
||||
return showConflicts(conflicts, usages);
|
||||
}
|
||||
|
||||
private void addInaccessibleConflicts(final MultiMap<PsiElement, String> conflicts, final UsageInfo[] usages) throws IncorrectOperationException {
|
||||
String newVisibility = myNewVisibility;
|
||||
if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object
|
||||
if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { // still need to check for access object
|
||||
newVisibility = PsiModifier.PUBLIC;
|
||||
}
|
||||
|
||||
Map<PsiMember, PsiModifierList> modifierListCopies = new HashMap<PsiMember, PsiModifierList>();
|
||||
final Map<PsiMember, PsiModifierList> modifierListCopies = new HashMap<PsiMember, PsiModifierList>();
|
||||
for (PsiMember member : myMembersToMove) {
|
||||
PsiModifierList copy = member.getModifierList();
|
||||
if (copy != null) copy = (PsiModifierList)copy.copy();
|
||||
if (newVisibility != null) {
|
||||
if (copy != null) VisibilityUtil.setVisibility(copy, newVisibility);
|
||||
PsiModifierList modifierListCopy = member.getModifierList();
|
||||
if (modifierListCopy != null) {
|
||||
modifierListCopy = (PsiModifierList)modifierListCopy.copy();
|
||||
}
|
||||
modifierListCopies.put(member, copy);
|
||||
if (modifierListCopy != null && newVisibility != null) {
|
||||
try {
|
||||
VisibilityUtil.setVisibility(modifierListCopy, newVisibility);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
LOG.error(e);
|
||||
}
|
||||
}
|
||||
modifierListCopies.put(member, modifierListCopy);
|
||||
}
|
||||
|
||||
analyzeConflictsOnUsages(usages, myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts);
|
||||
analyzeConflictsOnMembers(myMembersToMove, newVisibility, myTargetClass, modifierListCopies, conflicts);
|
||||
|
||||
RefactoringConflictsUtil.analyzeModuleConflicts(myProject, myMembersToMove, usages, myTargetClass, conflicts);
|
||||
|
||||
return showConflicts(conflicts, usages);
|
||||
}
|
||||
|
||||
private static void analyzeConflictsOnUsages(UsageInfo[] usages,
|
||||
Set<PsiMember> membersToMove,
|
||||
String newVisibility,
|
||||
PsiClass targetClass,
|
||||
Map<PsiMember, PsiModifierList> modifierListCopies,
|
||||
MultiMap<PsiElement, String> conflicts) {
|
||||
for (UsageInfo usage : usages) {
|
||||
if (usage instanceof MoveMembersUsageInfo) {
|
||||
final MoveMembersUsageInfo usageInfo = (MoveMembersUsageInfo)usage;
|
||||
PsiElement element = usage.getElement();
|
||||
if (element != null) {
|
||||
final PsiMember member = usageInfo.member;
|
||||
if (element instanceof PsiReferenceExpression) {
|
||||
PsiExpression qualifier = ((PsiReferenceExpression)element).getQualifierExpression();
|
||||
PsiClass accessObjectClass = null;
|
||||
if (qualifier != null) {
|
||||
accessObjectClass = (PsiClass)PsiUtil.getAccessObjectClass(qualifier).getElement();
|
||||
}
|
||||
if (!(usage instanceof MoveMembersUsageInfo)) continue;
|
||||
final MoveMembersUsageInfo usageInfo = (MoveMembersUsageInfo)usage;
|
||||
final PsiMember member = usageInfo.member;
|
||||
final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage());
|
||||
if (handler != null) {
|
||||
handler.checkConflictsOnUsage(usageInfo, newVisibility, modifierListCopies.get(member), targetClass, membersToMove, conflicts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!JavaResolveUtil.isAccessible(member, myTargetClass, modifierListCopies.get(member), element, accessObjectClass, null)) {
|
||||
newVisibility = newVisibility == null ? VisibilityUtil.getVisibilityStringToDisplay(member) : newVisibility;
|
||||
String message =
|
||||
CommonRefactoringUtil.capitalize(RefactoringBundle.message("0.with.1.visibility.is.not.accessible.from.2", RefactoringUIUtil.getDescription(member, false),
|
||||
newVisibility, RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(element), true)));
|
||||
conflicts.putValue(member, message);
|
||||
}
|
||||
}
|
||||
|
||||
if (member instanceof PsiField && myTargetClass.isInterface()) {
|
||||
final ReadWriteAccessDetector accessDetector = ReadWriteAccessDetector.findDetector(member);
|
||||
if (accessDetector != null) {
|
||||
final ReadWriteAccessDetector.Access access = accessDetector.getExpressionAccess(element);
|
||||
if (access != ReadWriteAccessDetector.Access.Read) {
|
||||
conflicts.putValue(element, CommonRefactoringUtil.capitalize(RefactoringUIUtil.getDescription(member, true)) + " has write access but is moved to an interface");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void analyzeConflictsOnMembers(Set<PsiMember> membersToMove,
|
||||
String newVisibility,
|
||||
PsiClass targetClass,
|
||||
Map<PsiMember, PsiModifierList> modifierListCopies,
|
||||
MultiMap<PsiElement, String> conflicts) {
|
||||
for (final PsiMember member : membersToMove) {
|
||||
final MoveMemberHandler handler = MoveMemberHandler.EP_NAME.forLanguage(member.getLanguage());
|
||||
if (handler != null) {
|
||||
handler.checkConflictsOnMember(member, newVisibility, modifierListCopies.get(member), targetClass, membersToMove, conflicts);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,53 +307,6 @@ public class MoveMembersProcessor extends BaseRefactoringProcessor {
|
||||
super.doRun();
|
||||
}
|
||||
|
||||
private static void analyzeMoveConflicts(@NotNull Set<PsiMember> membersToMove, final PsiClass targetClass, final String newVisibility,
|
||||
MultiMap<PsiElement, String> conflicts) {
|
||||
for (final PsiMember member : membersToMove) {
|
||||
if (member instanceof PsiMethod) {
|
||||
PsiMethod method = (PsiMethod)member;
|
||||
if (hasMethod(targetClass, method)) {
|
||||
String message = RefactoringBundle.message("0.already.exists.in.the.target.class", RefactoringUIUtil.getDescription(method, false));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(method, message);
|
||||
}
|
||||
}
|
||||
else if (member instanceof PsiField) {
|
||||
PsiField field = (PsiField)member;
|
||||
if (hasField(targetClass, field)) {
|
||||
String message = RefactoringBundle.message("0.already.exists.in.the.target.class", RefactoringUIUtil.getDescription(field, false));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(field, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
RefactoringConflictsUtil.analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility);
|
||||
}
|
||||
|
||||
private static boolean hasMethod(PsiClass targetClass, PsiMethod method) {
|
||||
PsiMethod[] targetClassMethods = targetClass.getMethods();
|
||||
for (PsiMethod candidate : targetClassMethods) {
|
||||
if (candidate != method &&
|
||||
MethodSignatureUtil.areSignaturesEqual(method.getSignature(PsiSubstitutor.EMPTY),
|
||||
candidate.getSignature(PsiSubstitutor.EMPTY))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean hasField(PsiClass targetClass, PsiField field) {
|
||||
String fieldName = field.getName();
|
||||
PsiField[] targetClassFields = targetClass.getFields();
|
||||
for (PsiField candidate : targetClassFields) {
|
||||
if (candidate != field &&
|
||||
fieldName.equals(candidate.getName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public List<PsiElement> getMembers() {
|
||||
return new ArrayList<PsiElement>(myMembersToMove);
|
||||
}
|
||||
|
||||
@@ -48,13 +48,16 @@ public class RefactoringConflictsUtil {
|
||||
private RefactoringConflictsUtil() { }
|
||||
|
||||
public static void analyzeAccessibilityConflicts(@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull final PsiClass targetClass,
|
||||
final MultiMap<PsiElement, String> conflicts, String newVisibility) {
|
||||
@NotNull PsiClass targetClass,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts,
|
||||
@Nullable String newVisibility) {
|
||||
analyzeAccessibilityConflicts(membersToMove, targetClass, conflicts, newVisibility, targetClass, null);
|
||||
}
|
||||
|
||||
public static void analyzeAccessibilityConflicts(@NotNull Set<PsiMember> membersToMove, @Nullable final PsiClass targetClass, final MultiMap<PsiElement, String> conflicts,
|
||||
String newVisibility,
|
||||
public static void analyzeAccessibilityConflicts(@NotNull Set<PsiMember> membersToMove,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts,
|
||||
@Nullable String newVisibility,
|
||||
@NotNull PsiElement context,
|
||||
@Nullable Set<PsiMethod> abstractMethods) {
|
||||
if (VisibilityUtil.ESCALATE_VISIBILITY.equals(newVisibility)) { //Still need to check for access object
|
||||
@@ -63,41 +66,65 @@ public class RefactoringConflictsUtil {
|
||||
|
||||
for (PsiMember member : membersToMove) {
|
||||
checkUsedElements(member, member, membersToMove, abstractMethods, targetClass, context, conflicts);
|
||||
checkAccessibilityConflicts(member, newVisibility, targetClass, membersToMove, conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
PsiModifierList modifierList = member.getModifierList();
|
||||
if (modifierList != null) modifierList = (PsiModifierList)modifierList.copy();
|
||||
|
||||
if (newVisibility != null) {
|
||||
try {
|
||||
if (modifierList != null) VisibilityUtil.setVisibility(modifierList, newVisibility);
|
||||
}
|
||||
catch (IncorrectOperationException ex) {
|
||||
/* do nothing and hope for the best */
|
||||
}
|
||||
public static void checkAccessibilityConflicts(@NotNull PsiMember member,
|
||||
@Nullable String newVisibility,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
PsiModifierList modifierListCopy = member.getModifierList();
|
||||
if (modifierListCopy != null) {
|
||||
modifierListCopy = (PsiModifierList)modifierListCopy.copy();
|
||||
}
|
||||
if (newVisibility != null && modifierListCopy != null) {
|
||||
try {
|
||||
VisibilityUtil.setVisibility(modifierListCopy, newVisibility);
|
||||
}
|
||||
JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject());
|
||||
for (PsiReference psiReference : ReferencesSearch.search(member)) {
|
||||
PsiElement ref = psiReference.getElement();
|
||||
if (!RefactoringHierarchyUtil.willBeInTargetClass(ref, membersToMove, targetClass, false)) {
|
||||
//Check for target class accessibility
|
||||
if (targetClass != null && !manager.getResolveHelper().isAccessible(targetClass, targetClass.getModifierList(), ref, null, null)) {
|
||||
String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class",
|
||||
RefactoringUIUtil.getDescription(targetClass, true),
|
||||
VisibilityUtil.getVisibilityStringToDisplay(targetClass),
|
||||
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(targetClass, message);
|
||||
}
|
||||
//check for member accessibility
|
||||
else if (!manager.getResolveHelper().isAccessible(member, modifierList, ref, null, null)) {
|
||||
String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class",
|
||||
RefactoringUIUtil.getDescription(member, true),
|
||||
VisibilityUtil.getVisibilityStringToDisplay(member),
|
||||
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(member, message);
|
||||
}
|
||||
}
|
||||
catch (IncorrectOperationException ignore) { } // do nothing and hope for the best
|
||||
}
|
||||
|
||||
checkAccessibilityConflicts(member, modifierListCopy, targetClass, membersToMove, conflicts);
|
||||
}
|
||||
|
||||
public static void checkAccessibilityConflicts(@NotNull PsiMember member,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
for (PsiReference psiReference : ReferencesSearch.search(member)) {
|
||||
checkAccessibilityConflicts(psiReference, member, modifierListCopy, targetClass, membersToMove, conflicts);
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkAccessibilityConflicts(@NotNull PsiReference reference,
|
||||
@NotNull PsiMember member,
|
||||
@Nullable PsiModifierList modifierListCopy,
|
||||
@Nullable PsiClass targetClass,
|
||||
@NotNull Set<PsiMember> membersToMove,
|
||||
@NotNull MultiMap<PsiElement, String> conflicts) {
|
||||
JavaPsiFacade manager = JavaPsiFacade.getInstance(member.getProject());
|
||||
PsiElement ref = reference.getElement();
|
||||
if (!RefactoringHierarchyUtil.willBeInTargetClass(ref, membersToMove, targetClass, false)) {
|
||||
// check for target class accessibility
|
||||
if (targetClass != null && !manager.getResolveHelper().isAccessible(targetClass, targetClass.getModifierList(), ref, null, null)) {
|
||||
String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class",
|
||||
RefactoringUIUtil.getDescription(targetClass, true),
|
||||
VisibilityUtil.getVisibilityStringToDisplay(targetClass),
|
||||
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(targetClass, message);
|
||||
}
|
||||
// check for member accessibility
|
||||
else if (!manager.getResolveHelper().isAccessible(member, modifierListCopy, ref, null, null)) {
|
||||
String message = RefactoringBundle.message("0.is.1.and.will.not.be.accessible.from.2.in.the.target.class",
|
||||
RefactoringUIUtil.getDescription(member, true),
|
||||
VisibilityUtil.getVisibilityStringToDisplay(member),
|
||||
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(ref), true));
|
||||
message = CommonRefactoringUtil.capitalize(message);
|
||||
conflicts.putValue(member, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -155,7 +182,7 @@ public class RefactoringConflictsUtil {
|
||||
|
||||
public static void checkAccessibility(PsiMember refMember,
|
||||
@NotNull PsiElement newContext,
|
||||
PsiClass accessClass,
|
||||
@Nullable PsiClass accessClass,
|
||||
PsiMember member,
|
||||
MultiMap<PsiElement, String> conflicts) {
|
||||
if (!PsiUtil.isAccessible(refMember, newContext, accessClass)) {
|
||||
@@ -176,24 +203,24 @@ public class RefactoringConflictsUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void analyzeModuleConflicts(Project project,
|
||||
Collection<? extends PsiElement> scope,
|
||||
public static void analyzeModuleConflicts(final Project project,
|
||||
final Collection<? extends PsiElement> scopes,
|
||||
final UsageInfo[] usages,
|
||||
PsiElement target,
|
||||
final PsiElement target,
|
||||
final MultiMap<PsiElement,String> conflicts) {
|
||||
if (scope == null) return;
|
||||
if (scopes == null) return;
|
||||
final VirtualFile vFile = PsiUtilBase.getVirtualFile(target);
|
||||
if (vFile == null) return;
|
||||
analyzeModuleConflicts(project, scope, usages, vFile, conflicts);
|
||||
|
||||
analyzeModuleConflicts(project, scopes, usages, vFile, conflicts);
|
||||
}
|
||||
|
||||
public static void analyzeModuleConflicts(Project project,
|
||||
public static void analyzeModuleConflicts(final Project project,
|
||||
final Collection<? extends PsiElement> scopes,
|
||||
final UsageInfo[] usages,
|
||||
final VirtualFile vFile,
|
||||
final MultiMap<PsiElement, String> conflicts) {
|
||||
if (scopes == null) return;
|
||||
|
||||
for (final PsiElement scope : scopes) {
|
||||
if (scope instanceof PsiPackage || scope instanceof PsiDirectory) return;
|
||||
}
|
||||
@@ -207,16 +234,16 @@ public class RefactoringConflictsUtil {
|
||||
@Override public void visitReferenceElement(PsiJavaCodeReferenceElement reference) {
|
||||
super.visitReferenceElement(reference);
|
||||
final PsiElement resolved = reference.resolve();
|
||||
if (resolved != null && !reported.contains(resolved) && !CommonRefactoringUtil.isAncestor(resolved, scopes) &&
|
||||
if (resolved != null &&
|
||||
!reported.contains(resolved) &&
|
||||
!CommonRefactoringUtil.isAncestor(resolved, scopes) &&
|
||||
!PsiSearchScopeUtil.isInScope(resolveScope, resolved)) {
|
||||
final String scopeDescription =
|
||||
RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true);
|
||||
final String scopeDescription = RefactoringUIUtil.getDescription(ConflictsUtil.getContainer(reference), true);
|
||||
final String message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.in.module.2",
|
||||
CommonRefactoringUtil.capitalize(
|
||||
RefactoringUIUtil.getDescription(resolved, true)), scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(
|
||||
targetModule.getName()));
|
||||
conflicts.putValue(resolved, message);
|
||||
RefactoringUIUtil.getDescription(resolved, true),
|
||||
scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(targetModule.getName()));
|
||||
conflicts.putValue(resolved, CommonRefactoringUtil.capitalize(message));
|
||||
reported.add(resolved);
|
||||
}
|
||||
}
|
||||
@@ -255,19 +282,17 @@ public class RefactoringConflictsUtil {
|
||||
assert referencedElement != null : moveRenameUsageInfo;
|
||||
if (module == targetModule && isInTestSources) {
|
||||
message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.from.production.of.module.2",
|
||||
CommonRefactoringUtil.capitalize(
|
||||
RefactoringUIUtil.getDescription(referencedElement, true)),
|
||||
RefactoringUIUtil.getDescription(referencedElement, true),
|
||||
scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(module.getName()));
|
||||
}
|
||||
else {
|
||||
message = RefactoringBundle.message("0.referenced.in.1.will.not.be.accessible.from.module.2",
|
||||
CommonRefactoringUtil.capitalize(
|
||||
RefactoringUIUtil.getDescription(referencedElement, true)),
|
||||
RefactoringUIUtil.getDescription(referencedElement, true),
|
||||
scopeDescription,
|
||||
CommonRefactoringUtil.htmlEmphasize(module.getName()));
|
||||
}
|
||||
conflicts.putValue(referencedElement, message);
|
||||
conflicts.putValue(referencedElement, CommonRefactoringUtil.capitalize(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,4 +300,4 @@ public class RefactoringConflictsUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user