Implement "Safe Delete" refactoring for properties

This commit is contained in:
Alexey Sedunov
2013-07-19 19:01:34 +04:00
parent 9c60637ef3
commit 639336b2f5
109 changed files with 1287 additions and 85 deletions
@@ -910,4 +910,11 @@ public class JetPsiUtil {
return (names.size() > partIndex) ? names.get(partIndex) : header.getLastPartExpression();
}
public static PsiElement ascendIfPropertyAccessor(PsiElement element) {
if (element instanceof JetPropertyAccessor) {
return element.getParent();
}
return element;
}
}
@@ -410,20 +410,23 @@ public class GenerateTests {
"idea/tests/",
"JetSafeDeleteTestGenerated",
AbstractJetSafeDeleteTest.class,
testModel("idea/testData/safeDelete/deleteClass", "doClassTest"),
testModel("idea/testData/safeDelete/deleteObject", "doObjectTest"),
testModel("idea/testData/safeDelete/deleteFunction", "doFunctionTest"),
testModel("idea/testData/safeDelete/deleteFunctionWithJavaUsages", "doFunctionTestWithJava")
// TODO fix -- disabled because doesn't work in Idea 130.1335
// testModel("idea/testData/safeDelete/deleteJavaMethod", "doJavaMethodTest")
testModel("idea/testData/safeDelete/deleteClass/kotlinClass", "doClassTest"),
testModel("idea/testData/safeDelete/deleteObject/kotlinObject", "doObjectTest"),
testModel("idea/testData/safeDelete/deleteFunction/kotlinFunction", "doFunctionTest"),
testModel("idea/testData/safeDelete/deleteFunction/kotlinFunctionWithJava", "doFunctionTestWithJava"),
testModel("idea/testData/safeDelete/deleteFunction/javaFunctionWithKotlin", "doJavaMethodTest"),
testModel("idea/testData/safeDelete/deleteProperty/kotlinProperty", "doPropertyTest"),
testModel("idea/testData/safeDelete/deleteProperty/kotlinPropertyWithJava", "doPropertyTestWithJava"),
testModel("idea/testData/safeDelete/deleteProperty/javaPropertyWithKotlin", "doJavaPropertyTest"),
testModel("idea/testData/safeDelete/deleteTypeParameter/kotlinTypeParameter", "doTypeParameterTest"),
testModel("idea/testData/safeDelete/deleteValueParameter/kotlinValueParameter", "doValueParameterTest")
);
generateTest(
"idea/tests/",
"ReferenceResolveTestGenerated",
AbstractResolveBaseTest.class,
testModel("idea/testData/resolve/references", "doTest")
);
testModel("idea/testData/resolve/references", "doTest") );
}
private static SimpleTestClassModel testModel(@NotNull String rootPath) {
@@ -258,4 +258,7 @@ usageType.selector = Selector
x.in.y={0} in {1}
x.implements.y={0} in {1} implements {2} in {3}.
x.overrides.y.in.class.list={0} in {1} overrides functions in the following classes/traits: {2} Do you want to delete (with usage search) the base methods?
unused.overriding.methods.title=Unused Overriding Methods
unused.overriding.methods.title=Unused Overriding Members
there.are.unused.methods.that.override.methods.you.delete=There are unused members that override methods you delete.
choose.the.ones.you.want.to.be.deleted=Choose the ones you want to be deleted.
method.column=Member
@@ -22,22 +22,20 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Splitter;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.HelpID;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.ui.BooleanTableCellRenderer;
import com.intellij.ui.ScrollPaneFactory;
import com.intellij.ui.table.JBTable;
import com.intellij.usageView.UsageInfo;
import com.intellij.usages.impl.UsagePreviewPanel;
import com.intellij.ui.table.JBTable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.JetFile;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.java.JetClsMethod;
import org.jetbrains.jet.plugin.JetBundle;
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache;
import org.jetbrains.jet.renderer.DescriptorRenderer;
@@ -78,22 +76,21 @@ class KotlinOverridingMethodsDialog extends DialogWrapper {
myMethodText = new String[myOverridingMethods.size()];
for (int i = 0; i < myMethodText.length; i++) {
myMethodText[i] = formatMethod(((KotlinSafeDeleteOverridingMethodUsageInfo) myOverridingMethods.get(i)).getOverridingMethod());
myMethodText[i] = formatElement(((KotlinSafeDeleteOverridingUsageInfo) myOverridingMethods.get(i)).getOverridingElement());
}
myUsagePreviewPanel = new UsagePreviewPanel(project);
setTitle(JetBundle.message("unused.overriding.methods.title"));
init();
}
private static String formatMethod(PsiMethod method) {
if (method instanceof JetClsMethod) {
JetNamedFunction function = (JetNamedFunction) ((JetClsMethod) method).getOrigin();
private static String formatElement(PsiElement element) {
element = JetPsiUtil.ascendIfPropertyAccessor(element);
if (element instanceof JetNamedFunction || element instanceof JetProperty) {
BindingContext bindingContext =
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) function.getContainingFile()).getBindingContext();
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext();
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
if (declarationDescriptor instanceof FunctionDescriptor) {
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
if (declarationDescriptor instanceof CallableMemberDescriptor) {
DeclarationDescriptor containingDescriptor = declarationDescriptor.getContainingDeclaration();
if (containingDescriptor instanceof ClassDescriptor) {
return JetBundle.message(
@@ -105,7 +102,8 @@ class KotlinOverridingMethodsDialog extends DialogWrapper {
}
}
return KotlinSafeDeleteProcessor.formatPsiMethod(method, true, false);
assert element instanceof PsiMethod;
return KotlinSafeDeleteProcessor.formatPsiMethod((PsiMethod) element, true, false);
}
@Override
@@ -138,8 +136,8 @@ class KotlinOverridingMethodsDialog extends DialogWrapper {
protected JComponent createNorthPanel() {
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
panel.add(new JLabel(RefactoringBundle.message("there.are.unused.methods.that.override.methods.you.delete")));
panel.add(new JLabel(RefactoringBundle.message("choose.the.ones.you.want.to.be.deleted")));
panel.add(new JLabel(JetBundle.message("there.are.unused.methods.that.override.methods.you.delete")));
panel.add(new JLabel(JetBundle.message("choose.the.ones.you.want.to.be.deleted")));
return panel;
}
@@ -245,7 +243,7 @@ class KotlinOverridingMethodsDialog extends DialogWrapper {
case CHECK_COLUMN:
return " ";
default:
return RefactoringBundle.message("method.column");
return JetBundle.message("method.column");
}
}
@@ -17,32 +17,23 @@
package org.jetbrains.jet.plugin.refactoring.safeDelete;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiMethod;
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteCustomUsageInfo;
import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteUsageInfo;
import com.intellij.util.IncorrectOperationException;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.psi.JetNamedFunction;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
public class KotlinSafeDeleteOverridingMethodUsageInfo extends SafeDeleteUsageInfo implements SafeDeleteCustomUsageInfo {
public KotlinSafeDeleteOverridingMethodUsageInfo(PsiElement overridingMethod, PsiElement method) {
super(toPsiMethod(overridingMethod), toPsiMethod(method));
public class KotlinSafeDeleteOverridingUsageInfo extends SafeDeleteUsageInfo implements SafeDeleteCustomUsageInfo {
public KotlinSafeDeleteOverridingUsageInfo(PsiElement overridingElement, PsiElement superElement) {
super(overridingElement, superElement);
}
protected static PsiMethod toPsiMethod(PsiElement element) {
if (element instanceof JetNamedFunction) {
element = LightClassUtil.getLightClassMethod((JetNamedFunction) element);
}
return element instanceof PsiMethod ? (PsiMethod) element : null;
}
public PsiMethod getOverridingMethod() {
return toPsiMethod(getElement());
public PsiElement getOverridingElement() {
return getElement();
}
@Override
public void performRefactoring() throws IncorrectOperationException {
PsiElement element = getElement();
PsiElement element = JetPsiUtil.ascendIfPropertyAccessor(getElement());
if (element != null) {
element.delete();
}
@@ -26,7 +26,6 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.search.searches.OverridingMethodsSearch;
import com.intellij.psi.search.searches.ReferencesSearch;
import com.intellij.psi.search.searches.SuperMethodsSearch;
import com.intellij.psi.util.*;
import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor;
import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo;
@@ -39,9 +38,7 @@ import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.asJava.LightClassUtil;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.Modality;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
@@ -58,7 +55,8 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
return element instanceof JetClassOrObject
|| element instanceof JetObjectDeclarationName
|| element instanceof JetNamedFunction
|| element instanceof PsiMethod;
|| element instanceof PsiMethod
|| element instanceof JetProperty;
}
@Override
@@ -88,6 +86,14 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
if (element instanceof PsiMethod) {
return findPsiMethodUsages((PsiMethod) element, allElementsToDelete, result);
}
if (element instanceof JetProperty) {
JetProperty property = (JetProperty) element;
if (property.isLocal()) {
return findLocalPropertyUsages(property, allElementsToDelete, result);
}
return findNonLocalPropertyUsages(property, allElementsToDelete, result);
}
return getDefaultNonCodeUsageSearchInfo(element, allElementsToDelete);
}
@@ -156,7 +162,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
for (UsageInfo usageInfo : javaUsages) {
if (usageInfo instanceof SafeDeleteOverridingMethodUsageInfo) {
SafeDeleteOverridingMethodUsageInfo overrideUsageInfo = (SafeDeleteOverridingMethodUsageInfo) usageInfo;
usageInfo = new KotlinSafeDeleteOverridingMethodUsageInfo(
usageInfo = new KotlinSafeDeleteOverridingUsageInfo(
overrideUsageInfo.getSmartPointer().getElement(), overrideUsageInfo.getReferencedElement()
);
}
@@ -221,6 +227,86 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
);
}
protected static NonCodeUsageSearchInfo findNonLocalPropertyUsages(
JetProperty property,
final PsiElement[] allElementsToDelete,
List<UsageInfo> result
) {
LightClassUtil.PropertyAccessorsPsiMethods propertyMethods = LightClassUtil.getLightClassPropertyMethods(property);
PsiMethod getter = propertyMethods.getGetter();
PsiMethod setter = propertyMethods.getSetter();
Collection<PsiReference> references = ReferencesSearch.search(property).findAll();
Collection<PsiMethod> getterOverriding =
(getter != null) ? OverridingMethodsSearch.search(getter, true).findAll() : Collections.<PsiMethod>emptyList();
Collection<PsiMethod> setterOverriding =
(setter != null) ? OverridingMethodsSearch.search(setter, true).findAll() : Collections.<PsiMethod>emptyList();
List<PsiMethod> overridingMethods = new ArrayList<PsiMethod>();
overridingMethods.addAll(getterOverriding);
overridingMethods.addAll(setterOverriding);
overridingMethods = difference(overridingMethods, allElementsToDelete);
for (PsiReference reference : references) {
PsiElement element = reference.getElement();
if (!isInside(element, allElementsToDelete) && !isInside(element, overridingMethods)) {
JetImportDirective importDirective = PsiTreeUtil.getParentOfType(element, JetImportDirective.class, false);
if (importDirective != null) {
result.add(new SafeDeleteImportDirectiveUsageInfo(importDirective, property));
}
else {
result.add(new SafeDeleteReferenceSimpleDeleteUsageInfo(element, property, false));
}
}
}
HashMap<PsiMethod, Collection<PsiReference>> methodToReferences = new HashMap<PsiMethod, Collection<PsiReference>>();
for (PsiMethod overridingMethod : overridingMethods) {
Collection<PsiReference> overridingReferences =
ReferencesSearch.search(
overridingMethod instanceof JetClsMethod ? ((JetClsMethod) overridingMethod).getOrigin() : overridingMethod
).findAll();
methodToReferences.put(overridingMethod, overridingReferences);
}
final Set<PsiMethod> safeGetterOverriding =
filterSafeOverridingMethods(getter, references, getterOverriding, methodToReferences, result, allElementsToDelete);
final Set<PsiMethod> safeSetterOverriding =
filterSafeOverridingMethods(setter, references, setterOverriding, methodToReferences, result, allElementsToDelete);
return new NonCodeUsageSearchInfo(
new Condition<PsiElement>() {
@Override
public boolean value(PsiElement usage) {
if (usage instanceof JetFile) return false;
return isInside(usage, allElementsToDelete)
|| isInside(usage, safeGetterOverriding)
|| isInside(usage, safeSetterOverriding) ;
}
},
property
);
}
protected static NonCodeUsageSearchInfo findLocalPropertyUsages(
final JetProperty property,
final PsiElement[] allElementsToDelete,
final List<UsageInfo> result
) {
ReferencesSearch.search(property, property.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));
}
return true;
}
});
return getDefaultNonCodeUsageSearchInfo(property, allElementsToDelete);
}
/*
* Mostly copied from JavaSafeDeleteProcessor.validateOverridingMethods
* Revision: d4fc033
@@ -270,7 +356,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
for (PsiMethod method : validOverriding) {
if (method != originalMethod) {
usages.add(new KotlinSafeDeleteOverridingMethodUsageInfo(method, originalMethod));
usages.add(new KotlinSafeDeleteOverridingUsageInfo(method, originalMethod));
}
}
@@ -282,6 +368,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
PsiMethod[] methods = method.findSuperMethods();
for (PsiMethod superMethod: methods) {
PsiElement relevantElement = superMethod instanceof JetClsMethod ? ((JetClsMethod) superMethod).getOrigin() : superMethod;
relevantElement = JetPsiUtil.ascendIfPropertyAccessor(relevantElement);
if (ArrayUtilRt.find(ignore, relevantElement) < 0 && !MethodSignatureUtil.isSuperMethod(originalMethod, superMethod)) {
return true;
}
@@ -289,7 +376,6 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
return false;
}
private static String wrapOrSkip(String s, boolean inCode) {
return inCode ? "<code>" + s + "</code>" : s;
}
@@ -339,6 +425,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
public static String formatPsiMethod(PsiMethod psiMethod, boolean showContainingClass, boolean inCode) {
int options = PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS | PsiFormatUtilBase.SHOW_TYPE;
if (showContainingClass) {
//noinspection ConstantConditions
options |= PsiFormatUtilBase.SHOW_CONTAINING_CLASS;
}
@@ -350,7 +437,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
@Override
public Collection<String> findConflicts(PsiElement element, PsiElement[] allElementsToDelete) {
if (element instanceof JetNamedFunction) {
if (element instanceof JetNamedFunction || element instanceof JetProperty) {
JetClass jetClass = PsiTreeUtil.getParentOfType(element, JetClass.class);
if (jetClass == null || jetClass.getBody() != element.getParent()) return null;
@@ -361,16 +448,16 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext();
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
if (!(declarationDescriptor instanceof FunctionDescriptor)) return null;
if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return null;
List<String> messages = new ArrayList<String>();
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
for (FunctionDescriptor overridenDescriptor : functionDescriptor.getOverriddenDescriptors()) {
CallableMemberDescriptor callableDescriptor = (CallableMemberDescriptor) declarationDescriptor;
for (CallableMemberDescriptor overridenDescriptor : callableDescriptor.getOverriddenDescriptors()) {
if (overridenDescriptor.getModality() == Modality.ABSTRACT) {
String message = JetBundle.message(
"x.implements.y",
formatFunction(functionDescriptor, bindingContext, true),
formatClass(functionDescriptor.getContainingDeclaration(), bindingContext, true),
formatFunction(callableDescriptor, bindingContext, true),
formatClass(callableDescriptor.getContainingDeclaration(), bindingContext, true),
formatFunction(overridenDescriptor, bindingContext, true),
formatClass(overridenDescriptor.getContainingDeclaration(), bindingContext, true)
);
@@ -395,7 +482,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
ArrayList<UsageInfo> overridingMethodUsages = new ArrayList<UsageInfo>();
for (UsageInfo usage : usages) {
if (usage instanceof KotlinSafeDeleteOverridingMethodUsageInfo) {
if (usage instanceof KotlinSafeDeleteOverridingUsageInfo) {
overridingMethodUsages.add(usage);
}
else {
@@ -419,8 +506,8 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
}
private static void removeOverrideModifier(@NotNull PsiElement element) {
if (element instanceof JetNamedFunction) {
JetModifierList modifierList = ((JetNamedFunction) element).getModifierList();
if (element instanceof JetNamedFunction || element instanceof JetProperty) {
JetModifierList modifierList = ((JetModifierListOwner) element).getModifierList();
if (modifierList == null) return;
PsiElement overrideModifier = modifierList.getModifier(JetTokens.OVERRIDE_KEYWORD);
@@ -458,21 +545,41 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
cleanUpOverrides(lightMethod);
}
else if (element instanceof JetProperty) {
LightClassUtil.PropertyAccessorsPsiMethods propertyMethods =
LightClassUtil.getLightClassPropertyMethods((JetProperty) element);
PsiMethod getter = propertyMethods.getGetter();
PsiMethod setter = propertyMethods.getSetter();
if (getter != null) {
cleanUpOverrides(getter);
}
if (setter != null) {
cleanUpOverrides(setter);
}
}
}
private static boolean checkPsiMethodEquality(PsiMethod method1, PsiMethod method2) {
if (method1 instanceof JetClsMethod && method2 instanceof JetClsMethod) {
return ((JetClsMethod) method1).getOrigin() == ((JetClsMethod) method2).getOrigin();
}
return method1 == method2;
}
private static void cleanUpOverrides(PsiMethod method) {
Collection<MethodSignatureBackedByPsiMethod> superMethods =
SuperMethodsSearch.search(method, null, true, false).findAll();
Collection<PsiMethod> overridingMethods = OverridingMethodsSearch.search(method, false).findAll();
Collection<PsiMethod> superMethods = Arrays.asList(method.findSuperMethods(true));
Collection<PsiMethod> overridingMethods = OverridingMethodsSearch.search(method, true).findAll();
overrideLoop: for (PsiMethod overridingMethod : overridingMethods) {
PsiElement overridingElement = overridingMethod instanceof JetClsMethod
? ((JetClsMethod) overridingMethod).getOrigin()
: overridingMethod;
Collection<MethodSignatureBackedByPsiMethod> currentSuperMethods =
SuperMethodsSearch.search(overridingMethod, null, true, false).findAll();
Collection<PsiMethod> currentSuperMethods = new ArrayList<PsiMethod>();
ContainerUtil.addAll(currentSuperMethods, overridingMethod.findSuperMethods(true));
currentSuperMethods.addAll(superMethods);
for (MethodSignatureBackedByPsiMethod superMethod: currentSuperMethods) {
if (superMethod.getMethod() != method) continue overrideLoop;
for (PsiMethod superMethod: currentSuperMethods) {
if (!checkPsiMethodEquality(superMethod, method)) continue overrideLoop;
}
removeOverrideModifier(overridingElement);
@@ -481,22 +588,22 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
@Nullable
private static Collection<? extends PsiElement> checkSuperMethods(
@NotNull JetNamedFunction function, @Nullable Collection<PsiElement> ignore
@NotNull JetDeclaration declaration, @Nullable Collection<PsiElement> ignore
) {
final BindingContext bindingContext =
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) function.getContainingFile()).getBindingContext();
AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) declaration.getContainingFile()).getBindingContext();
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function);
if (!(declarationDescriptor instanceof FunctionDescriptor)) return null;
DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration);
if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return null;
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
Set<? extends FunctionDescriptor> overridenDescriptors = functionDescriptor.getOverriddenDescriptors();
CallableMemberDescriptor callableDescriptor = (CallableMemberDescriptor) declarationDescriptor;
Set<? extends CallableMemberDescriptor> overridenDescriptors = callableDescriptor.getOverriddenDescriptors();
Collection<? extends PsiElement> superMethods = ContainerUtil.map(
overridenDescriptors,
new Function<FunctionDescriptor, PsiElement>() {
new Function<CallableMemberDescriptor, PsiElement>() {
@Override
public PsiElement fun(FunctionDescriptor descriptor) {
public PsiElement fun(CallableMemberDescriptor descriptor) {
return BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
}
}
@@ -505,7 +612,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
superMethods.removeAll(ignore);
}
if (superMethods.isEmpty()) return Collections.singletonList(function);
if (superMethods.isEmpty()) return Collections.singletonList(declaration);
List<String> superClasses = ContainerUtil.map(
superMethods,
@@ -514,7 +621,7 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
public String fun(PsiElement element) {
String description;
if (element instanceof JetNamedFunction) {
if (element instanceof JetNamedFunction || element instanceof JetProperty) {
DeclarationDescriptor descriptor =
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
assert descriptor != null;
@@ -541,19 +648,19 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
String superClassesStr = "\n" + StringUtil.join(superClasses, "");
String message = JetBundle.message(
"x.overrides.y.in.class.list",
DescriptorRenderer.COMPACT.render(functionDescriptor),
DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(functionDescriptor.getContainingDeclaration()),
DescriptorRenderer.COMPACT.render(callableDescriptor),
DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(callableDescriptor.getContainingDeclaration()),
superClassesStr
);
int exitCode = Messages.showYesNoCancelDialog(
function.getProject(), message, IdeBundle.message("title.warning"), Messages.getQuestionIcon()
declaration.getProject(), message, IdeBundle.message("title.warning"), Messages.getQuestionIcon()
);
switch (exitCode) {
case Messages.YES:
return superMethods;
case Messages.NO:
return Collections.singletonList(function);
return Collections.singletonList(declaration);
default:
return Collections.emptyList();
}
@@ -568,8 +675,8 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
return Collections.singletonList(element);
}
if (element instanceof JetNamedFunction) {
return checkSuperMethods((JetNamedFunction) element, allElementsToDelete);
if (element instanceof JetNamedFunction || element instanceof JetProperty) {
return checkSuperMethods((JetDeclaration) element, allElementsToDelete);
}
return super.getElementsToSearch(element, module, allElementsToDelete);
}
@@ -583,4 +690,4 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor {
}
return super.getAdditionalElementsToDelete(element, allElementsToDelete, askUser);
}
}
}
@@ -0,0 +1,6 @@
abstract class C implements B {
@Override
public String <caret>getFoo() {
return "C";
}
}
@@ -0,0 +1,2 @@
abstract class C implements B {
}
@@ -0,0 +1,10 @@
trait B {
public val foo: String
}
class D: B {
public override val foo: String
get() {
return "D"
}
}
@@ -0,0 +1,10 @@
trait B {
public val foo: String
}
class D: B {
public override val foo: String
get() {
return "D"
}
}
@@ -0,0 +1,6 @@
class C implements B {
@Override
public String <caret>getFoo() {
return "C";
}
}
@@ -0,0 +1,10 @@
trait B {
public val foo: String
}
class D: B {
public override val foo: String
get() {
return "D"
}
}
@@ -0,0 +1 @@
method C.getFoo() implements method B.getFoo().
@@ -0,0 +1,11 @@
abstract class C implements B {
@Override
public String <caret>getFoo() {
return "C";
}
@Override
public void setFoo(String value) {
}
}
@@ -0,0 +1,7 @@
abstract class C implements B {
@Override
public void setFoo(String value) {
}
}
@@ -0,0 +1,13 @@
trait B {
public var foo: String
}
class D: B {
public override var foo: String
get() {
return "D"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,13 @@
trait B {
public var foo: String
}
class D: B {
public override var foo: String
get() {
return "D"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,11 @@
class C implements B {
@Override
public String <caret>getFoo() {
return "C";
}
@Override
public void setFoo(String value) {
}
}
@@ -0,0 +1,13 @@
trait B {
public var foo: String
}
class D: B {
public override var foo: String
get() {
return "D"
}
set(value: String) {
println()
}
}
@@ -0,0 +1 @@
method C.getFoo() implements method B.getFoo().
@@ -0,0 +1,11 @@
abstract class C implements B {
@Override
public String getFoo() {
return "C";
}
@Override
public void <caret>setFoo(String value) {
}
}
@@ -0,0 +1,7 @@
abstract class C implements B {
@Override
public String getFoo() {
return "C";
}
}
@@ -0,0 +1,13 @@
trait B {
public var foo: String
}
class D: B {
public override var foo: String
get() {
return "D"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,13 @@
trait B {
public var foo: String
}
class D: B {
public override var foo: String
get() {
return "D"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,11 @@
class C implements B {
@Override
public String getFoo() {
return "C";
}
@Override
public void <caret>setFoo(String value) {
}
}
@@ -0,0 +1,13 @@
trait B {
public var foo: String
}
class D: B {
public override var foo: String
get() {
return "D"
}
set(value: String) {
println()
}
}
@@ -0,0 +1 @@
method C.setFoo(String) implements method B.setFoo(String).
@@ -0,0 +1,10 @@
trait A {
val foo: String
}
class B: A {
override val <caret>foo: String
get() {
return "B"
}
}
@@ -0,0 +1 @@
val foo: jet.String in final class B : A implements val foo: jet.String in trait A.
@@ -0,0 +1,14 @@
trait A {
val foo: String
}
trait Z {
val foo: String
}
class B: A, Z {
override val <caret>foo: String
get() {
return "B"
}
}
@@ -0,0 +1,2 @@
val foo: jet.String in final class B : A, Z implements val foo: jet.String in trait A.
val foo: jet.String in final class B : A, Z implements val foo: jet.String in trait Z.
@@ -0,0 +1,13 @@
trait A {
var foo: String
}
class B: A {
override var <caret>foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1 @@
var foo: jet.String in final class B : A implements var foo: jet.String in trait A.
@@ -0,0 +1,17 @@
trait A {
var foo: String
}
trait Z {
var foo: String
}
class B: A, Z {
override var <caret>foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,2 @@
var foo: jet.String in final class B : A, Z implements var foo: jet.String in trait A.
var foo: jet.String in final class B : A, Z implements var foo: jet.String in trait Z.
@@ -0,0 +1,10 @@
trait A {
val <caret>foo: String
}
class B: A {
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,5 @@
trait A {
}
class B: A {
}
@@ -0,0 +1,13 @@
trait A {
var <caret>foo: String
}
class B: A {
override val foo: String
get() {
return "B"
}
set(value: String) {
}
}
@@ -0,0 +1,5 @@
trait A {
}
class B: A {
}
@@ -0,0 +1,14 @@
trait A {
val <caret>foo: String
}
trait Z {
val foo: String
}
class B: A, Z {
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,13 @@
trait A {
}
trait Z {
val foo: String
}
class B: A, Z {
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,17 @@
trait A {
var <caret>foo: String
}
trait Z {
var foo: String
}
class B: A, Z {
override val foo: String
get() {
return "B"
}
set(value: String) {
}
}
@@ -0,0 +1,16 @@
trait A {
}
trait Z {
var foo: String
}
class B: A, Z {
override val foo: String
get() {
return "B"
}
set(value: String) {
}
}
@@ -0,0 +1,9 @@
class C {
val <caret>foo: String
get() {
return "foo"
}
}
class B {
}
@@ -0,0 +1,5 @@
class C {
}
class B {
}
@@ -0,0 +1,13 @@
open class A {
open val foo: String
get() {
return "A"
}
}
class B: A() {
override val <caret>foo: String
get() {
return "B"
}
}
@@ -0,0 +1,9 @@
open class A {
open val foo: String
get() {
return "A"
}
}
class B: A() {
}
@@ -0,0 +1,13 @@
open class A {
open val <caret>foo: String
get() {
return "A"
}
}
class B: A() {
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,5 @@
open class A {
}
class B: A() {
}
@@ -0,0 +1,19 @@
open class A {
open var foo: String
get() {
return "A"
}
set(value: String) {
println()
}
}
class B: A() {
override var <caret>foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,12 @@
open class A {
open var foo: String
get() {
return "A"
}
set(value: String) {
println()
}
}
class B: A() {
}
@@ -0,0 +1,19 @@
open class A {
open var <caret>foo: String
get() {
return "A"
}
set(value: String) {
println()
}
}
class B: A() {
override var foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,5 @@
open class A {
}
class B: A() {
}
@@ -0,0 +1,17 @@
open class A {
open val foo: String
get() {
return "A"
}
}
trait Z {
val foo: String
}
class B: A(), Z {
override val <caret>foo: String
get() {
return "B"
}
}
@@ -0,0 +1 @@
val foo: jet.String in final class B : A, Z implements val foo: jet.String in trait Z.
@@ -0,0 +1,17 @@
open class A {
open val <caret>foo: String
get() {
return "A"
}
}
trait Z {
val foo: String
}
class B: A(), Z {
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,13 @@
open class A {
}
trait Z {
val foo: String
}
class B: A(), Z {
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,23 @@
open class A {
open var foo: String
get() {
return "A"
}
set(value: String) {
println()
}
}
trait Z {
var foo: String
}
class B: A(), Z {
override var <caret>foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1 @@
var foo: jet.String in final class B : A, Z implements var foo: jet.String in trait Z.
@@ -0,0 +1,23 @@
open class A {
open var <caret>foo: String
get() {
return "A"
}
set(value: String) {
println()
}
}
trait Z {
var foo: String
}
class B: A(), Z {
override var foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,16 @@
open class A {
}
trait Z {
var foo: String
}
class B: A(), Z {
override var foo: String
get() {
return "B"
}
set(value: String) {
println()
}
}
@@ -0,0 +1,17 @@
open class A {
val <caret>foo: String
get() {
return "A"
}
}
class B: A {
fun bar() {
println(foo)
}
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,13 @@
open class A {
}
class B: A {
fun bar() {
println(foo)
}
override val foo: String
get() {
return "B"
}
}
@@ -0,0 +1,9 @@
package test
import test.foo
val <caret>foo = "foo"
class B {
}
@@ -0,0 +1,5 @@
package test
class B {
}
@@ -0,0 +1,9 @@
package test
import test.foo
val <caret>foo = "foo"
class B {
val ref = foo
}
@@ -0,0 +1,2 @@
Property foo has 1 usage that is not safe to delete.
Of those 0 usages are in strings, comments, or non-code files.
@@ -0,0 +1,6 @@
class B implements A, Z {
@Override
public String getFoo() {
return "foo";
}
}
@@ -0,0 +1,6 @@
class B implements A, Z {
@Override
public String getFoo() {
return "foo";
}
}
@@ -0,0 +1,7 @@
trait A {
val <caret>foo: String
}
trait Z {
val foo: String
}
@@ -0,0 +1,6 @@
trait A {
}
trait Z {
val foo: String
}
@@ -0,0 +1,6 @@
class B implements A {
@Override
public String getFoo() {
return "foo";
}
}
@@ -0,0 +1,2 @@
class B implements A {
}
@@ -0,0 +1,3 @@
trait A {
val <caret>foo: String
}
@@ -0,0 +1,2 @@
trait A {
}
@@ -0,0 +1,11 @@
class B implements A, Z {
@Override
public String getFoo() {
return "foo";
}
@Override
public void getFoo(String value) {
}
}
@@ -0,0 +1,11 @@
class B implements A, Z {
@Override
public String getFoo() {
return "foo";
}
@Override
public void getFoo(String value) {
}
}
@@ -0,0 +1,7 @@
trait A {
var <caret>foo: String
}
trait Z {
var foo: String
}
@@ -0,0 +1,6 @@
trait A {
}
trait Z {
var foo: String
}
@@ -0,0 +1,11 @@
class B implements A {
@Override
public String getFoo() {
return "foo";
}
@Override
public void setFoo(String value) {
}
}
@@ -0,0 +1,3 @@
class B implements A {
}
@@ -0,0 +1,3 @@
trait A {
var <caret>foo: String
}
@@ -0,0 +1,2 @@
trait A {
}
@@ -0,0 +1,10 @@
class B extends A {
void bar() {
System.out.println(getFoo());
}
@Override
public String getFoo() {
return "foo";
}
}
@@ -0,0 +1,9 @@
class B extends A {
void bar() {
System.out.println(getFoo());
}
public String getFoo() {
return "foo";
}
}
@@ -0,0 +1,3 @@
open class A {
open val <caret>foo: String = ""
}
@@ -0,0 +1,2 @@
open class A {
}
@@ -0,0 +1,6 @@
class B extends A {
@Override
String getFoo() {
return "foo";
}
}
@@ -0,0 +1,2 @@
class B extends A {
}
@@ -0,0 +1,3 @@
open class A {
open val <caret>foo: String = ""
}
@@ -0,0 +1,2 @@
open class A {
}
@@ -0,0 +1,16 @@
class B extends A {
void bar() {
setFoo("");
System.out.println(getFoo());
}
@Override
public String getFoo() {
return "foo";
}
@Override
public void setFoo(String value) {
}
}
@@ -0,0 +1,14 @@
class B extends A {
void bar() {
setFoo("");
System.out.println(getFoo());
}
public String getFoo() {
return "foo";
}
public void setFoo(String value) {
}
}
@@ -0,0 +1,3 @@
open class A {
open var <caret>foo: String = ""
}
@@ -0,0 +1,2 @@
open class A {
}
@@ -0,0 +1,11 @@
class B extends A {
@Override
String getFoo() {
return "foo";
}
@Override
void setFoo(String value) {
}
}
@@ -0,0 +1,3 @@
class B extends A {
}
@@ -0,0 +1,3 @@
open class A {
open var <caret>foo: String = ""
}
@@ -0,0 +1,2 @@
open class A {
}
@@ -0,0 +1,6 @@
class B extends A implements Z {
@Override
public String getFoo() {
return "foo";
}
}

Some files were not shown because too many files have changed in this diff Show More