diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java index a2cc05c2be2..c80493ae6e2 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java @@ -40,6 +40,7 @@ import com.intellij.util.Processor; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.asJava.AsJavaPackage; import org.jetbrains.jet.asJava.LightClassUtil; import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; @@ -101,7 +102,14 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { return findClassOrObjectUsages(element, (JetClassOrObject) element, allElementsToDelete, result); } if (element instanceof JetNamedFunction) { - return findFunctionUsages((JetNamedFunction) element, allElementsToDelete, result); + JetNamedFunction function = (JetNamedFunction) element; + if (function.isLocal()) { + return findLocalDeclarationUsages(function, allElementsToDelete, result); + } + PsiMethod method = LightClassUtil.getLightClassMethod((JetNamedFunction) element); + if (method != null) return findPsiMethodUsages(method, allElementsToDelete, result); + + return getSearchInfo(element, allElementsToDelete); } if (element instanceof PsiMethod) { return findPsiMethodUsages((PsiMethod) element, allElementsToDelete, result); @@ -110,7 +118,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { JetProperty property = (JetProperty) element; if (property.isLocal()) { - return findLocalVariableUsages(property, allElementsToDelete, result); + return findLocalDeclarationUsages(property, allElementsToDelete, result); } return findPropertyUsages(property, allElementsToDelete, result); } @@ -198,11 +206,27 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { } else if (usageInfo instanceof SafeDeleteOverrideAnnotation) { SafeDeleteOverrideAnnotation overrideAnnotationUsageInfo = (SafeDeleteOverrideAnnotation) usageInfo; - usageInfo = new KotlinSafeDeleteOverrideAnnotation( - overrideAnnotationUsageInfo.getSmartPointer().getElement(), overrideAnnotationUsageInfo.getReferencedElement() - ); + + PsiElement targetElement = overrideAnnotationUsageInfo.getSmartPointer().getElement(); + if (AsJavaPackage.getRepresentativeLightMethod(targetElement).findSuperMethods().length > 0) { + usageInfo = null; + } + else { + usageInfo = new KotlinSafeDeleteOverrideAnnotation(targetElement, overrideAnnotationUsageInfo.getReferencedElement()); + } + } + else if (usageInfo instanceof SafeDeleteReferenceJavaDeleteUsageInfo) { + SafeDeleteReferenceJavaDeleteUsageInfo javaDeleteUsageInfo = (SafeDeleteReferenceJavaDeleteUsageInfo) usageInfo; + PsiElement usageElement = javaDeleteUsageInfo.getElement(); + JetImportDirective importDirective = PsiTreeUtil.getParentOfType(usageElement, JetImportDirective.class, false); + if (importDirective != null) { + usageInfo = SafeDeleteImportDirectiveUsageInfo.object$.create(importDirective, + (JetDeclaration) method.getNavigationElement()); + } + } + if (usageInfo != null) { + result.add(usageInfo); } - result.add(usageInfo); } return searchInfo; @@ -236,32 +260,6 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { } } - @NotNull - protected static NonCodeUsageSearchInfo findFunctionUsages( - @NotNull JetNamedFunction function, - @NotNull PsiElement[] allElementsToDelete, - @NotNull List result - ) { - PsiMethod lightMethod = LightClassUtil.getLightClassMethod(function); - if (lightMethod == null) { - return getSearchInfo(function, allElementsToDelete); - } - - Collection references = ReferencesSearch.search(function).findAll(); - List overridingMethods = difference(OverridingMethodsSearch.search(lightMethod, true).findAll(), allElementsToDelete); - - processDeclarationUsages(function, allElementsToDelete, result, references, overridingMethods); - - Map> methodToReferences = getOverridingUsagesMap(overridingMethods); - Set safeOverriding = - filterSafeOverridingMethods(lightMethod, references, overridingMethods, methodToReferences, result, allElementsToDelete); - - List ignoredElements = new ArrayList(safeOverriding); - ContainerUtil.addAll(ignoredElements, allElementsToDelete); - return getSearchInfo(function, ignoredElements); - } - - @NotNull protected static NonCodeUsageSearchInfo findPropertyUsages( @NotNull JetProperty property, @NotNull PsiElement[] allElementsToDelete, @@ -316,23 +314,23 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { } @NotNull - protected static NonCodeUsageSearchInfo findLocalVariableUsages( - @NotNull final JetProperty property, + protected static NonCodeUsageSearchInfo findLocalDeclarationUsages( + @NotNull final JetDeclaration declaration, @NotNull final PsiElement[] allElementsToDelete, @NotNull final List result ) { - ReferencesSearch.search(property, property.getUseScope()).forEach(new Processor() { + ReferencesSearch.search(declaration, declaration.getUseScope()).forEach(new Processor() { @Override public boolean process(PsiReference reference) { PsiElement element = reference.getElement(); if (!isInside(element, allElementsToDelete)) { - result.add(new SafeDeleteReferenceSimpleDeleteUsageInfo(element, property, false)); + result.add(new SafeDeleteReferenceSimpleDeleteUsageInfo(element, declaration, false)); } return true; } }); - return getSearchInfo(property, allElementsToDelete); + return getSearchInfo(declaration, allElementsToDelete); } @NotNull diff --git a/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt new file mode 100644 index 00000000000..53a36ccf77d --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt @@ -0,0 +1,7 @@ +fun foo() { + fun bar() { + + } + + bar() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt.messages b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt.messages new file mode 100644 index 00000000000..32eb1cb56fe --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt.messages @@ -0,0 +1 @@ +function foo.bar has 1 usage that is not safe to delete. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt new file mode 100644 index 00000000000..40aea7b62f4 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt @@ -0,0 +1,7 @@ +fun foo() { + fun bar() { + + } + + println() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt.after b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt.after new file mode 100644 index 00000000000..e594a93598a --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt.after @@ -0,0 +1,4 @@ +fun foo() { + + println() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt b/idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt new file mode 100644 index 00000000000..b420fd5aee6 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt @@ -0,0 +1,15 @@ +open class A { + open fun foo() { + + } +} + +trait Z { + fun foo() +} + +class B: A, Z { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt.after b/idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt.after new file mode 100644 index 00000000000..06b7399d1dc --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt.after @@ -0,0 +1,14 @@ +open class A { + open fun foo() { + + } +} + +trait Z { +} + +class B: A, Z { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java b/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java index 8fb558dd2ed..82881662ae2 100644 --- a/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java @@ -149,6 +149,16 @@ public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest { doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/implement2.kt"); } + @TestMetadata("localFun1.kt") + public void testLocalFun1() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun1.kt"); + } + + @TestMetadata("localFun2.kt") + public void testLocalFun2() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/localFun2.kt"); + } + @TestMetadata("noUsages.kt") public void testNoUsages() throws Exception { doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/noUsages.kt"); @@ -174,6 +184,11 @@ public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest { doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement2.kt"); } + @TestMetadata("overrideAndImplement3.kt") + public void testOverrideAndImplement3() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideAndImplement3.kt"); + } + @TestMetadata("overrideWithUsages.kt") public void testOverrideWithUsages() throws Exception { doFunctionTest("idea/testData/safeDelete/deleteFunction/kotlinFunction/overrideWithUsages.kt");