Reuse Java safe delete for non-local functions in Kotlin

This commit is contained in:
Alexey Sedunov
2014-01-20 14:32:48 +04:00
parent e70af5d372
commit d432c10251
8 changed files with 98 additions and 37 deletions
@@ -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<UsageInfo> result
) {
PsiMethod lightMethod = LightClassUtil.getLightClassMethod(function);
if (lightMethod == null) {
return getSearchInfo(function, allElementsToDelete);
}
Collection<PsiReference> references = ReferencesSearch.search(function).findAll();
List<PsiMethod> overridingMethods = difference(OverridingMethodsSearch.search(lightMethod, true).findAll(), allElementsToDelete);
processDeclarationUsages(function, allElementsToDelete, result, references, overridingMethods);
Map<PsiMethod, Collection<PsiReference>> methodToReferences = getOverridingUsagesMap(overridingMethods);
Set<PsiMethod> safeOverriding =
filterSafeOverridingMethods(lightMethod, references, overridingMethods, methodToReferences, result, allElementsToDelete);
List<PsiElement> ignoredElements = new ArrayList<PsiElement>(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<UsageInfo> result
) {
ReferencesSearch.search(property, property.getUseScope()).forEach(new Processor<PsiReference>() {
ReferencesSearch.search(declaration, declaration.getUseScope()).forEach(new Processor<PsiReference>() {
@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
@@ -0,0 +1,7 @@
fun foo() {
fun <caret>bar() {
}
bar()
}
@@ -0,0 +1 @@
function foo.bar has 1 usage that is not safe to delete.
@@ -0,0 +1,7 @@
fun foo() {
fun <caret>bar() {
}
println()
}
@@ -0,0 +1,4 @@
fun foo() {
println()
}
@@ -0,0 +1,15 @@
open class A {
open fun foo() {
}
}
trait Z {
fun <caret>foo()
}
class B: A, Z {
override fun foo() {
}
}
@@ -0,0 +1,14 @@
open class A {
open fun foo() {
}
}
trait Z {
}
class B: A, Z {
override fun foo() {
}
}
@@ -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");