use of com.intellij.refactoring.util.classMembers.ClassMemberReferencesVisitor in project intellij-community by JetBrains.
the class PullUpConflictsUtil method checkConflicts.
public static MultiMap<PsiElement, String> checkConflicts(final MemberInfoBase<? extends PsiMember>[] infos, @NotNull final PsiClass subclass, @Nullable PsiClass superClass, @NotNull final PsiPackage targetPackage, @NotNull PsiDirectory targetDirectory, final InterfaceContainmentVerifier interfaceContainmentVerifier, boolean movedMembers2Super) {
final Set<PsiMember> movedMembers = new HashSet<>();
final Set<PsiMethod> abstractMethods = new HashSet<>();
final boolean isInterfaceTarget;
final PsiElement targetRepresentativeElement;
if (superClass != null) {
isInterfaceTarget = superClass.isInterface();
targetRepresentativeElement = superClass;
} else {
isInterfaceTarget = false;
targetRepresentativeElement = targetDirectory;
}
for (MemberInfoBase<? extends PsiMember> info : infos) {
PsiMember member = info.getMember();
if (member instanceof PsiMethod) {
if (!info.isToAbstract()) {
movedMembers.add(member);
} else {
abstractMethods.add((PsiMethod) member);
}
} else {
movedMembers.add(member);
}
}
final MultiMap<PsiElement, String> conflicts = new MultiMap<>();
final Set<PsiMethod> abstrMethods = new HashSet<>(abstractMethods);
if (superClass != null) {
for (PsiMethod method : subclass.getMethods()) {
if (!movedMembers.contains(method) && !method.hasModifierProperty(PsiModifier.PRIVATE)) {
if (method.findSuperMethods(superClass).length > 0) {
abstrMethods.add(method);
}
}
}
if (newAbstractMethodInSuper(infos)) {
final PsiAnnotation annotation = AnnotationUtil.findAnnotation(superClass, CommonClassNames.JAVA_LANG_FUNCTIONAL_INTERFACE);
if (annotation != null) {
conflicts.putValue(annotation, RefactoringBundle.message("functional.interface.broken"));
} else {
final PsiFunctionalExpression functionalExpression = FunctionalExpressionSearch.search(superClass).findFirst();
if (functionalExpression != null) {
conflicts.putValue(functionalExpression, RefactoringBundle.message("functional.interface.broken"));
}
}
}
}
RefactoringConflictsUtil.analyzeAccessibilityConflicts(movedMembers, superClass, conflicts, VisibilityUtil.ESCALATE_VISIBILITY, targetRepresentativeElement, abstrMethods);
if (superClass != null) {
if (movedMembers2Super) {
checkSuperclassMembers(superClass, infos, conflicts);
if (isInterfaceTarget) {
checkInterfaceTarget(infos, conflicts);
}
} else {
final String qualifiedName = superClass.getQualifiedName();
assert qualifiedName != null;
if (superClass.hasModifierProperty(PsiModifier.PACKAGE_LOCAL)) {
if (!Comparing.strEqual(StringUtil.getPackageName(qualifiedName), targetPackage.getQualifiedName())) {
conflicts.putValue(superClass, RefactoringUIUtil.getDescription(superClass, true) + " won't be accessible from " + RefactoringUIUtil.getDescription(targetPackage, true));
}
}
}
}
// check if moved methods use other members in the classes between Subclass and Superclass
List<PsiElement> checkModuleConflictsList = new ArrayList<>();
for (PsiMember member : movedMembers) {
if (member instanceof PsiMethod || member instanceof PsiClass && !(member instanceof PsiCompiledElement)) {
ClassMemberReferencesVisitor visitor = movedMembers2Super ? new ConflictingUsagesOfSubClassMembers(member, movedMembers, abstractMethods, subclass, superClass, superClass != null ? null : targetPackage, conflicts, interfaceContainmentVerifier) : new ConflictingUsagesOfSuperClassMembers(member, subclass, targetPackage, movedMembers, conflicts);
member.accept(visitor);
}
ContainerUtil.addIfNotNull(checkModuleConflictsList, member);
}
for (final PsiMethod method : abstractMethods) {
ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getParameterList());
ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getReturnTypeElement());
ContainerUtil.addIfNotNull(checkModuleConflictsList, method.getTypeParameterList());
}
RefactoringConflictsUtil.analyzeModuleConflicts(subclass.getProject(), checkModuleConflictsList, UsageInfo.EMPTY_ARRAY, targetDirectory, conflicts);
final PsiFile psiFile = PsiTreeUtil.getParentOfType(subclass, PsiClassOwner.class);
final boolean toDifferentPackage = !Comparing.strEqual(targetPackage.getQualifiedName(), psiFile != null ? ((PsiClassOwner) psiFile).getPackageName() : null);
for (final PsiMethod abstractMethod : abstractMethods) {
abstractMethod.accept(new ClassMemberReferencesVisitor(subclass) {
@Override
protected void visitClassMemberReferenceElement(PsiMember classMember, PsiJavaCodeReferenceElement classMemberReference) {
if (classMember != null && willBeMoved(classMember, movedMembers)) {
boolean isAccessible = false;
if (classMember.hasModifierProperty(PsiModifier.PRIVATE)) {
isAccessible = true;
} else if (classMember.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && toDifferentPackage) {
isAccessible = true;
}
if (isAccessible) {
String message = RefactoringUIUtil.getDescription(abstractMethod, false) + " uses " + RefactoringUIUtil.getDescription(classMember, true) + " which won't be accessible from the subclass.";
message = CommonRefactoringUtil.capitalize(message);
conflicts.putValue(classMember, message);
}
}
}
});
if (abstractMethod.hasModifierProperty(PsiModifier.PACKAGE_LOCAL) && toDifferentPackage) {
if (!isInterfaceTarget) {
String message = "Can't make " + RefactoringUIUtil.getDescription(abstractMethod, false) + " abstract as it won't be accessible from the subclass.";
message = CommonRefactoringUtil.capitalize(message);
conflicts.putValue(abstractMethod, message);
}
}
}
return conflicts;
}
Aggregations