Reuse Java safe delete for Kotlin classes and objects
This commit is contained in:
@@ -372,14 +372,13 @@ public class JetPsiUtil {
|
|||||||
public static void deleteClass(@NotNull JetClassOrObject clazz) {
|
public static void deleteClass(@NotNull JetClassOrObject clazz) {
|
||||||
CheckUtil.checkWritable(clazz);
|
CheckUtil.checkWritable(clazz);
|
||||||
JetFile file = (JetFile) clazz.getContainingFile();
|
JetFile file = (JetFile) clazz.getContainingFile();
|
||||||
List<JetDeclaration> declarations = file.getDeclarations();
|
if (isLocal(clazz) || file.getDeclarations().size() > 1) {
|
||||||
if (declarations.size() == 1) {
|
|
||||||
file.delete();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PsiElement parent = clazz.getParent();
|
PsiElement parent = clazz.getParent();
|
||||||
CodeEditUtil.removeChild(parent.getNode(), clazz.getNode());
|
CodeEditUtil.removeChild(parent.getNode(), clazz.getNode());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
file.delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ import com.intellij.psi.search.SearchScope
|
|||||||
import com.intellij.psi.search.PsiSearchScopeUtil
|
import com.intellij.psi.search.PsiSearchScopeUtil
|
||||||
import org.jetbrains.jet.lang.psi.JetClassBody
|
import org.jetbrains.jet.lang.psi.JetClassBody
|
||||||
import org.jetbrains.jet.lang.psi.JetParameterList
|
import org.jetbrains.jet.lang.psi.JetParameterList
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration
|
||||||
|
import com.intellij.psi.PsiNamedElement
|
||||||
|
|
||||||
fun PsiElement.getParentByTypesAndPredicate<T: PsiElement>(
|
fun PsiElement.getParentByTypesAndPredicate<T: PsiElement>(
|
||||||
strict : Boolean = false, vararg parentClasses : Class<T>, predicate: (T) -> Boolean
|
strict : Boolean = false, vararg parentClasses : Class<T>, predicate: (T) -> Boolean
|
||||||
@@ -170,4 +172,7 @@ fun JetDeclaration.isOverridable(): Boolean {
|
|||||||
|
|
||||||
return klass.isTrait() ||
|
return klass.isTrait() ||
|
||||||
hasModifier(JetTokens.ABSTRACT_KEYWORD) || hasModifier(JetTokens.OPEN_KEYWORD) || hasModifier(JetTokens.OVERRIDE_KEYWORD)
|
hasModifier(JetTokens.ABSTRACT_KEYWORD) || hasModifier(JetTokens.OPEN_KEYWORD) || hasModifier(JetTokens.OVERRIDE_KEYWORD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val PsiElement.namedNavigationElement: PsiNamedElement?
|
||||||
|
get() = getNavigationElement()?.getParentByType(javaClass<PsiNamedElement>())
|
||||||
+9
-36
@@ -99,7 +99,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
|
|||||||
@NotNull PsiElement element, @NotNull PsiElement[] allElementsToDelete, @NotNull List<UsageInfo> result
|
@NotNull PsiElement element, @NotNull PsiElement[] allElementsToDelete, @NotNull List<UsageInfo> result
|
||||||
) {
|
) {
|
||||||
if (element instanceof JetClassOrObject) {
|
if (element instanceof JetClassOrObject) {
|
||||||
return findClassOrObjectUsages(element, (JetClassOrObject) element, allElementsToDelete, result);
|
return delegateToJavaProcessor(LightClassUtil.getPsiClass((JetClassOrObject) element), allElementsToDelete, result);
|
||||||
}
|
}
|
||||||
if (element instanceof JetNamedFunction) {
|
if (element instanceof JetNamedFunction) {
|
||||||
JetNamedFunction function = (JetNamedFunction) element;
|
JetNamedFunction function = (JetNamedFunction) element;
|
||||||
@@ -107,12 +107,12 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
|
|||||||
return findLocalDeclarationUsages(function, allElementsToDelete, result);
|
return findLocalDeclarationUsages(function, allElementsToDelete, result);
|
||||||
}
|
}
|
||||||
PsiMethod method = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
|
PsiMethod method = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
|
||||||
if (method != null) return findPsiMethodUsages(method, allElementsToDelete, result);
|
if (method != null) return delegateToJavaProcessor(method, allElementsToDelete, result);
|
||||||
|
|
||||||
return getSearchInfo(element, allElementsToDelete);
|
return getSearchInfo(element, allElementsToDelete);
|
||||||
}
|
}
|
||||||
if (element instanceof PsiMethod) {
|
if (element instanceof PsiMethod) {
|
||||||
return findPsiMethodUsages((PsiMethod) element, allElementsToDelete, result);
|
return delegateToJavaProcessor(element, allElementsToDelete, result);
|
||||||
}
|
}
|
||||||
if (element instanceof JetProperty) {
|
if (element instanceof JetProperty) {
|
||||||
JetProperty property = (JetProperty) element;
|
JetProperty property = (JetProperty) element;
|
||||||
@@ -160,42 +160,16 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
|
|||||||
return JavaSafeDeleteProcessor.isInside(place, ancestor);
|
return JavaSafeDeleteProcessor.isInside(place, ancestor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
protected static NonCodeUsageSearchInfo findClassOrObjectUsages(
|
|
||||||
@NotNull PsiElement referencedElement,
|
|
||||||
@NotNull final JetClassOrObject classOrObject,
|
|
||||||
@NotNull final PsiElement[] allElementsToDelete,
|
|
||||||
@NotNull final List<UsageInfo> result
|
|
||||||
) {
|
|
||||||
ReferencesSearch.search(referencedElement).forEach(new Processor<PsiReference>() {
|
|
||||||
@Override
|
|
||||||
public boolean process(PsiReference reference) {
|
|
||||||
PsiElement element = reference.getElement();
|
|
||||||
|
|
||||||
if (!isInside(element, allElementsToDelete)) {
|
|
||||||
JetImportDirective importDirective = PsiTreeUtil.getParentOfType(element, JetImportDirective.class, false);
|
|
||||||
if (importDirective != null) {
|
|
||||||
result.add(new SafeDeleteImportDirectiveUsageInfo(importDirective, classOrObject));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
result.add(new SafeDeleteReferenceSimpleDeleteUsageInfo(element, classOrObject, false));
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return getSearchInfo(referencedElement, allElementsToDelete);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected NonCodeUsageSearchInfo findPsiMethodUsages(
|
protected NonCodeUsageSearchInfo delegateToJavaProcessor(
|
||||||
@NotNull PsiMethod method,
|
@Nullable PsiElement element,
|
||||||
@NotNull PsiElement[] allElementsToDelete,
|
@NotNull PsiElement[] allElementsToDelete,
|
||||||
@NotNull List<UsageInfo> result
|
@NotNull List<UsageInfo> result
|
||||||
) {
|
) {
|
||||||
|
if (element == null) return null;
|
||||||
|
|
||||||
List<UsageInfo> javaUsages = new ArrayList<UsageInfo>();
|
List<UsageInfo> javaUsages = new ArrayList<UsageInfo>();
|
||||||
NonCodeUsageSearchInfo searchInfo = super.findUsages(method, allElementsToDelete, javaUsages);
|
NonCodeUsageSearchInfo searchInfo = super.findUsages(element, allElementsToDelete, javaUsages);
|
||||||
|
|
||||||
for (UsageInfo usageInfo : javaUsages) {
|
for (UsageInfo usageInfo : javaUsages) {
|
||||||
if (usageInfo instanceof SafeDeleteOverridingMethodUsageInfo) {
|
if (usageInfo instanceof SafeDeleteOverridingMethodUsageInfo) {
|
||||||
@@ -220,8 +194,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
|
|||||||
PsiElement usageElement = javaDeleteUsageInfo.getElement();
|
PsiElement usageElement = javaDeleteUsageInfo.getElement();
|
||||||
JetImportDirective importDirective = PsiTreeUtil.getParentOfType(usageElement, JetImportDirective.class, false);
|
JetImportDirective importDirective = PsiTreeUtil.getParentOfType(usageElement, JetImportDirective.class, false);
|
||||||
if (importDirective != null) {
|
if (importDirective != null) {
|
||||||
usageInfo = SafeDeleteImportDirectiveUsageInfo.object$.create(importDirective,
|
usageInfo = new SafeDeleteImportDirectiveUsageInfo(importDirective, (JetDeclaration) element.getNavigationElement());
|
||||||
(JetDeclaration) method.getNavigationElement());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (usageInfo != null) {
|
if (usageInfo != null) {
|
||||||
|
|||||||
@@ -27,10 +27,11 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PackageViewDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetNamedDeclaration;
|
||||||
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
import org.jetbrains.jet.lang.psi.JetReferenceExpression;
|
||||||
|
import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||||
import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod;
|
|
||||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -90,9 +91,13 @@ public abstract class JetPsiReference implements PsiPolyVariantReference {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isReferenceTo(PsiElement element) {
|
public boolean isReferenceTo(PsiElement element) {
|
||||||
PsiElement target = resolve();
|
PsiElement resolvedElement = resolve();
|
||||||
PsiElement mirrorElement = element instanceof KotlinLightMethod ? ((KotlinLightMethod) element).getOrigin() : null;
|
if (resolvedElement == null) return false;
|
||||||
return target == element || (mirrorElement != null && target == mirrorElement) || (target != null && target.getNavigationElement() == element);
|
|
||||||
|
PsiNamedElement namedDeclaration = PsiUtilPackage.getNamedNavigationElement(element);
|
||||||
|
PsiNamedElement namedResolvedDeclaration = PsiUtilPackage.getNamedNavigationElement(resolvedElement);
|
||||||
|
|
||||||
|
return namedDeclaration != null && namedDeclaration.equals(namedResolvedDeclaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo() {
|
||||||
|
class <caret>A {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
A()
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
class foo.A has 1 usage that is not safe to delete.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
class <caret>A {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fun foo() {
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun foo() {
|
||||||
|
object <caret>A {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
A
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
object foo.A has 1 usage that is not safe to delete.
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
fun foo() {
|
||||||
|
object <caret>A {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
fun foo() {
|
||||||
|
}
|
||||||
@@ -53,6 +53,16 @@ public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest {
|
|||||||
doClassTest("idea/testData/safeDelete/deleteClass/kotlinClass/classInString.kt");
|
doClassTest("idea/testData/safeDelete/deleteClass/kotlinClass/classInString.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClass1.kt")
|
||||||
|
public void testLocalClass1() throws Exception {
|
||||||
|
doClassTest("idea/testData/safeDelete/deleteClass/kotlinClass/localClass1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localClass2.kt")
|
||||||
|
public void testLocalClass2() throws Exception {
|
||||||
|
doClassTest("idea/testData/safeDelete/deleteClass/kotlinClass/localClass2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nestedClass1.kt")
|
@TestMetadata("nestedClass1.kt")
|
||||||
public void testNestedClass1() throws Exception {
|
public void testNestedClass1() throws Exception {
|
||||||
doClassTest("idea/testData/safeDelete/deleteClass/kotlinClass/nestedClass1.kt");
|
doClassTest("idea/testData/safeDelete/deleteClass/kotlinClass/nestedClass1.kt");
|
||||||
@@ -91,6 +101,16 @@ public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest {
|
|||||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/safeDelete/deleteObject/kotlinObject"), Pattern.compile("^(.+)\\.kt$"), true);
|
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("idea/testData/safeDelete/deleteObject/kotlinObject"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localObject1.kt")
|
||||||
|
public void testLocalObject1() throws Exception {
|
||||||
|
doObjectTest("idea/testData/safeDelete/deleteObject/kotlinObject/localObject1.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("localObject2.kt")
|
||||||
|
public void testLocalObject2() throws Exception {
|
||||||
|
doObjectTest("idea/testData/safeDelete/deleteObject/kotlinObject/localObject2.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("nestedObject1.kt")
|
@TestMetadata("nestedObject1.kt")
|
||||||
public void testNestedObject1() throws Exception {
|
public void testNestedObject1() throws Exception {
|
||||||
doObjectTest("idea/testData/safeDelete/deleteObject/kotlinObject/nestedObject1.kt");
|
doObjectTest("idea/testData/safeDelete/deleteObject/kotlinObject/nestedObject1.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user