diff --git a/ChangeLog.md b/ChangeLog.md index af3aa9f93f7..8bf8d33f80f 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -35,6 +35,7 @@ Issues fixed: - [KT-11617](https://youtrack.jetbrains.com/issue/KT-11617) Fixed title of Introduce Parameter declaration chooser - [KT-11817](https://youtrack.jetbrains.com/issue/KT-11817) Fixed rename of Kotlin enum constants through Java references - [KT-11816](https://youtrack.jetbrains.com/issue/KT-11816) Fixed usages search for Safe Delete on simple enum entries +- [KT-11282](https://youtrack.jetbrains.com/issue/KT-11282) Delete interface reference from super-type list when applying Safe Delete to Java interface #### Debugger diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtSuperTypeList.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtSuperTypeList.java index 07434485416..3165d39adb6 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtSuperTypeList.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtSuperTypeList.java @@ -17,7 +17,13 @@ package org.jetbrains.kotlin.psi; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiComment; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; import org.jetbrains.annotations.NotNull; +import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.psi.stubs.KotlinPlaceHolderStub; import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes; @@ -38,6 +44,20 @@ public class KtSuperTypeList extends KtElementImplStub getEntries() { return Arrays.asList(getStubOrPsiChildren(KtStubElementTypes.SUPER_TYPE_LIST_ENTRIES, KtSuperTypeListEntry.ARRAY_FACTORY)); } diff --git a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt index f60d34fba99..e1761a508d0 100644 --- a/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt +++ b/generators/src/org/jetbrains/kotlin/generators/tests/GenerateTests.kt @@ -531,6 +531,7 @@ fun main(args: Array) { testClass() { model("refactoring/safeDelete/deleteClass/kotlinClass", testMethod = "doClassTest") model("refactoring/safeDelete/deleteClass/kotlinClassWithJava", testMethod = "doClassTestWithJava") + model("refactoring/safeDelete/deleteClass/javaClassWithKotlin", extension = "java", testMethod = "doJavaClassTest") model("refactoring/safeDelete/deleteObject/kotlinObject", testMethod = "doObjectTest") model("refactoring/safeDelete/deleteFunction/kotlinFunction", testMethod = "doFunctionTest") model("refactoring/safeDelete/deleteFunction/kotlinFunctionWithJava", testMethod = "doFunctionTestWithJava") diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt index 4ee3140aa47..4d632622e0a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.search.usagesSearch.processDelegationCallConstr import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType +import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.utils.SmartSet import org.jetbrains.kotlin.utils.ifEmpty @@ -99,6 +100,8 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() { else -> { usageElement.getNonStrictParentOfType()?.let { importDirective -> SafeDeleteImportDirectiveUsageInfo(importDirective, element.unwrapped as KtDeclaration) + } ?: usageElement.getParentOfTypeAndBranch { typeReference }?.let { + if (element is PsiClass && element.isInterface) SafeDeleteSuperTypeUsageInfo(it, element) else usageInfo } ?: if (forceReferencedElementUnwrapping) { SafeDeleteReferenceJavaDeleteUsageInfo(usageElement, element.unwrapped, usageInfo.isSafeDelete) } else usageInfo @@ -214,6 +217,9 @@ class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() { is PsiMethod -> findUsagesByJavaProcessor(element, false) + is PsiClass -> + findUsagesByJavaProcessor(element, false) + is KtProperty -> { if (!LightClassUtil.canGenerateLightClass(element)) { findKotlinDeclarationUsages(element) diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteSuperTypeUsageInfo.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteSuperTypeUsageInfo.kt new file mode 100644 index 00000000000..fd6633cfa6b --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteSuperTypeUsageInfo.kt @@ -0,0 +1,19 @@ +package org.jetbrains.kotlin.idea.refactoring.safeDelete + +import com.intellij.psi.PsiElement +import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceUsageInfo +import org.jetbrains.kotlin.psi.KtSuperTypeEntry +import org.jetbrains.kotlin.psi.KtSuperTypeList + +class SafeDeleteSuperTypeUsageInfo( + entry: KtSuperTypeEntry, + referencedElement: PsiElement +) : SafeDeleteReferenceUsageInfo(entry, referencedElement, true) { + private val entry: KtSuperTypeEntry? + get() = element as? KtSuperTypeEntry + + override fun deleteElement() { + val entry = entry ?: return + (entry.parent as? KtSuperTypeList)?.removeEntry(entry) + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt index 1312aa8700a..3754829faa5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/safeDelete/utils.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.idea.refactoring.safeDelete +import com.intellij.psi.PsiClass import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.search.searches.OverridingMethodsSearch @@ -36,6 +37,7 @@ fun PsiElement.canDeleteElement(): Boolean { || this is KtSecondaryConstructor || this is KtNamedFunction || this is PsiMethod + || this is PsiClass || this is KtProperty || this is KtTypeParameter } diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java new file mode 100644 index 00000000000..c6831f27827 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java @@ -0,0 +1,11 @@ +public interface I { + +} + +public interface II { + +} + +public class J implements I, II { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java.after b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java.after new file mode 100644 index 00000000000..ba7c4efc646 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java.after @@ -0,0 +1,7 @@ +public interface II { + +} + +public class J implements II { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.kt b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.kt new file mode 100644 index 00000000000..b2be43d7b6d --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.kt @@ -0,0 +1,3 @@ +class K : I, II { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.kt.after b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.kt.after new file mode 100644 index 00000000000..0a51a6dac00 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.kt.after @@ -0,0 +1,3 @@ +class K : II { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java new file mode 100644 index 00000000000..148bfdc53af --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java @@ -0,0 +1,7 @@ +public interface I { + +} + +public class J implements I { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java.after b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java.after new file mode 100644 index 00000000000..c4e0bbd2817 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java.after @@ -0,0 +1,3 @@ +public class J { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.kt b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.kt new file mode 100644 index 00000000000..f5c0a293360 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.kt @@ -0,0 +1,3 @@ +class K : I { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.kt.after b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.kt.after new file mode 100644 index 00000000000..907ff90fef4 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.kt.after @@ -0,0 +1,3 @@ +class K { + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/kotlinClass/trait2.kt.after b/idea/testData/refactoring/safeDelete/deleteClass/kotlinClass/trait2.kt.after new file mode 100644 index 00000000000..74912886094 --- /dev/null +++ b/idea/testData/refactoring/safeDelete/deleteClass/kotlinClass/trait2.kt.after @@ -0,0 +1,5 @@ +package test + +class B{ + +} \ No newline at end of file diff --git a/idea/testData/refactoring/safeDelete/deleteClass/kotlinClass/trait2.kt.messages b/idea/testData/refactoring/safeDelete/deleteClass/kotlinClass/trait2.kt.messages deleted file mode 100644 index fbc0e43ed1c..00000000000 --- a/idea/testData/refactoring/safeDelete/deleteClass/kotlinClass/trait2.kt.messages +++ /dev/null @@ -1 +0,0 @@ -interface test.A has 1 usage that is not safe to delete. \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/AbstractSafeDeleteTest.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/AbstractSafeDeleteTest.java index 9d94e1c25a6..16ce58ae25d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/AbstractSafeDeleteTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/AbstractSafeDeleteTest.java @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.refactoring.safeDelete; import com.intellij.codeInsight.TargetElementUtilBase; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiClass; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiMethod; import com.intellij.psi.util.PsiTreeUtil; @@ -58,6 +59,10 @@ public abstract class AbstractSafeDeleteTest extends KotlinLightCodeInsightFixtu doTest(path, KtClass.class, true); } + public void doJavaClassTest(@NotNull String path) throws Exception { + doTest(path, PsiClass.class, true); + } + public void doObjectTest(@NotNull String path) throws Exception { doTest(path, KtObjectDeclaration.class, false); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteTestGenerated.java index c8958a297f7..77cc8399843 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/safeDelete/SafeDeleteTestGenerated.java @@ -137,6 +137,27 @@ public class SafeDeleteTestGenerated extends AbstractSafeDeleteTest { } } + @TestMetadata("idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class JavaClassWithKotlin extends AbstractSafeDeleteTest { + public void testAllFilesPresentInJavaClassWithKotlin() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin"), Pattern.compile("^(.+)\\.java$"), true); + } + + @TestMetadata("javaInterfaceInSuperTypeList.java") + public void testJavaInterfaceInSuperTypeList() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeList.java"); + doJavaClassTest(fileName); + } + + @TestMetadata("javaInterfaceInSuperTypeListLast.java") + public void testJavaInterfaceInSuperTypeListLast() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/refactoring/safeDelete/deleteClass/javaClassWithKotlin/javaInterfaceInSuperTypeListLast.java"); + doJavaClassTest(fileName); + } + } + @TestMetadata("idea/testData/refactoring/safeDelete/deleteObject/kotlinObject") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class)