SafeDelete: support sealed classes (IDEA-243902)

GitOrigin-RevId: 1b2c6f68d91e519736787f8cfbd9e8be57a7ead0
This commit is contained in:
Artemiy Sartakov
2020-07-31 07:39:53 +00:00
committed by intellij-monorepo-bot
parent 6ca02a49fc
commit 895bf1829e
5 changed files with 84 additions and 2 deletions
@@ -572,11 +572,16 @@ public class JavaSafeDeleteProcessor extends SafeDeleteProcessorDelegateBase {
if (parent instanceof PsiReferenceList) {
final PsiElement pparent = parent.getParent();
if (pparent instanceof PsiClass && element instanceof PsiJavaCodeReferenceElement) {
PsiJavaCodeReferenceElement classRef = (PsiJavaCodeReferenceElement) element;
final PsiClass inheritor = (PsiClass) pparent;
if (parent.equals(inheritor.getPermitsList())) {
usages.add(new SafeDeletePermitsClassUsageInfo(classRef, psiClass, inheritor));
return true;
}
//If psiClass contains only private members, then it is safe to remove it and change inheritor's extends/implements accordingly
if (justPrivates) {
if (parent.equals(inheritor.getExtendsList()) || parent.equals(inheritor.getImplementsList())) {
usages.add(new SafeDeleteExtendsClassUsageInfo((PsiJavaCodeReferenceElement)element, psiClass, inheritor));
usages.add(new SafeDeleteExtendsClassUsageInfo(classRef, psiClass, inheritor));
return true;
}
}
@@ -0,0 +1,56 @@
// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.refactoring.safeDelete.usageInfo;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassType;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import com.intellij.psi.PsiReferenceList;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.containers.ContainerUtil;
import com.siyeh.ig.psiutils.ClassUtils;
import java.util.Objects;
public class SafeDeletePermitsClassUsageInfo extends SafeDeleteReferenceUsageInfo {
private final PsiClass myParentClass;
public SafeDeletePermitsClassUsageInfo(final PsiJavaCodeReferenceElement reference, PsiClass refClass, PsiClass parentClass) {
super(reference, refClass, true);
myParentClass = parentClass;
}
@Override
public PsiClass getReferencedElement() {
return (PsiClass)super.getReferencedElement();
}
@Override
public void deleteElement() throws IncorrectOperationException {
final PsiClass refClass = getReferencedElement();
ClassUtils.removeFromPermitsList(myParentClass, refClass);
}
@Override
public boolean isSafeDelete() {
if (getElement() != null) return true;
PsiReferenceList permitsList = myParentClass.getPermitsList();
if (permitsList == null) return false;
PsiJavaCodeReferenceElement[] childRefs = permitsList.getReferenceElements();
if (childRefs.length < 1) return false;
return ContainerUtil.exists(childRefs, ref -> ref.resolve() == getReferencedElement());
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
if (!super.equals(o)) return false;
SafeDeletePermitsClassUsageInfo info = (SafeDeletePermitsClassUsageInfo)o;
return Objects.equals(myParentClass, info.myParentClass);
}
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), myParentClass);
}
}
@@ -0,0 +1,9 @@
sealed interface GrandParent1 permits Parent, A {}
sealed class GrandParent2 permits Parent {}
sealed class <caret>Parent extends GrandParent2 implements GrandParent1 permits A, B {}
non-sealed class A extends Parent implements GrandParent1 {}
final class B extends Parent {}
@@ -0,0 +1,7 @@
sealed interface GrandParent1 permits A, B {}
sealed class GrandParent2 permits A, B {}
non-sealed class A extends GrandParent2 implements GrandParent1 {}
final class B extends GrandParent2 implements GrandParent1 {}
@@ -276,7 +276,7 @@ public class SafeDeleteTest extends MultiFileTestCase {
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
doSingleFileTest();
}
public void testLastResourceVariableConflictingVar() throws Exception {
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_1_7);
doSingleFileTest();
@@ -388,6 +388,11 @@ public class SafeDeleteTest extends MultiFileTestCase {
doSingleFileTest();
}
public void testSealedParent() throws Exception {
LanguageLevelProjectExtension.getInstance(getProject()).setLanguageLevel(LanguageLevel.JDK_15_PREVIEW);
doSingleFileTest();
}
private void doTest(@NonNls final String qClassName) {
doTest((rootDir, rootAfter) -> this.performAction(qClassName));
}