diff --git a/annotations/com/intellij/openapi/util/annotations.xml b/annotations/com/intellij/openapi/util/annotations.xml index b11815b34e4..c04bb1a0672 100644 --- a/annotations/com/intellij/openapi/util/annotations.xml +++ b/annotations/com/intellij/openapi/util/annotations.xml @@ -1,4 +1,8 @@ + + + diff --git a/annotations/com/intellij/psi/annotations.xml b/annotations/com/intellij/psi/annotations.xml index 6fa70cb6668..9ebf450d9bf 100644 --- a/annotations/com/intellij/psi/annotations.xml +++ b/annotations/com/intellij/psi/annotations.xml @@ -11,6 +11,9 @@ + + + diff --git a/annotations/com/intellij/psi/search/searches/annotations.xml b/annotations/com/intellij/psi/search/searches/annotations.xml index 72806268982..9a49c51ad91 100644 --- a/annotations/com/intellij/psi/search/searches/annotations.xml +++ b/annotations/com/intellij/psi/search/searches/annotations.xml @@ -19,4 +19,29 @@ name='com.intellij.psi.search.searches.OverridingMethodsSearch com.intellij.util.Query<com.intellij.psi.PsiMethod> search(com.intellij.psi.PsiMethod, com.intellij.psi.search.SearchScope, boolean)'> + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/refactoring/safeDelete/annotations.xml b/annotations/com/intellij/refactoring/safeDelete/annotations.xml new file mode 100644 index 00000000000..364c50d8893 --- /dev/null +++ b/annotations/com/intellij/refactoring/safeDelete/annotations.xml @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/refactoring/safeDelete/usageInfo/annotations.xml b/annotations/com/intellij/refactoring/safeDelete/usageInfo/annotations.xml new file mode 100644 index 00000000000..9a79b9c84af --- /dev/null +++ b/annotations/com/intellij/refactoring/safeDelete/usageInfo/annotations.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/annotations/com/intellij/usageView/annotations.xml b/annotations/com/intellij/usageView/annotations.xml new file mode 100644 index 00000000000..ac5915627cc --- /dev/null +++ b/annotations/com/intellij/usageView/annotations.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/lightClassUtils.kt b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/lightClassUtils.kt index 130056eae0e..40df221c6bc 100644 --- a/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/lightClassUtils.kt +++ b/compiler/jet.as.java.psi/src/org/jetbrains/jet/asJava/lightClassUtils.kt @@ -39,6 +39,9 @@ import com.intellij.psi.PsiNamedElement import com.intellij.psi.PsiNamedElement import org.jetbrains.jet.lang.psi.JetCallableDeclaration import org.jetbrains.jet.lang.psi.psiUtil.isExtensionDeclaration +import com.intellij.psi.PsiClass + +fun JetClassOrObject.toLightClass(): PsiClass? = LightClassUtil.getPsiClass(this) fun JetDeclaration.toLightElements(): List = when (this) { diff --git a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/CallableMemberDescriptor.java b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/CallableMemberDescriptor.java index 149ed0878ef..c0152a6d21d 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/descriptors/CallableMemberDescriptor.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/descriptors/CallableMemberDescriptor.java @@ -16,11 +16,13 @@ package org.jetbrains.jet.lang.descriptors; +import jet.runtime.typeinfo.KotlinSignature; import org.jetbrains.annotations.NotNull; import java.util.Set; public interface CallableMemberDescriptor extends CallableDescriptor, MemberDescriptor { + @KotlinSignature("fun getOverriddenDescriptors(): MutableSet") @NotNull @Override Set getOverriddenDescriptors(); diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java index 735e46d3f57..ca278e52c8f 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java @@ -25,12 +25,12 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.plugin.refactoring.changeSignature.JetChangeSignatureHandler; import org.jetbrains.jet.plugin.refactoring.introduceVariable.JetIntroduceVariableHandler; -import org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinSafeDeleteProcessor; +import org.jetbrains.jet.plugin.refactoring.safeDelete.SafeDeletePackage; public class JetRefactoringSupportProvider extends RefactoringSupportProvider { @Override public boolean isSafeDeleteAvailable(@NotNull PsiElement element) { - return KotlinSafeDeleteProcessor.canDeleteElement(element); + return SafeDeletePackage.canDeleteElement(element); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java index 663f0ead4c5..8e3ed3becd8 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringUtil.java @@ -34,6 +34,7 @@ import com.intellij.psi.util.PsiFormatUtilBase; import com.intellij.ui.components.JBList; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; +import jet.runtime.typeinfo.KotlinSignature; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.asJava.AsJavaPackage; @@ -117,6 +118,8 @@ public class JetRefactoringUtil { return markAsJava ? "[Java] " + description : description; } + @KotlinSignature( + "fun checkSuperMethods(declaration: JetDeclaration, ignore: Collection?, actionStringKey: String): MutableList?") @Nullable public static List checkSuperMethods( @NotNull JetDeclaration declaration, @Nullable Collection ignore, @NotNull String actionStringKey @@ -287,6 +290,7 @@ public class JetRefactoringUtil { return "class " + classOrObject.getName(); } + @KotlinSignature("fun checkParametersInMethodHierarchy(parameter: PsiParameter): MutableCollection?") @Nullable public static Collection checkParametersInMethodHierarchy(@NotNull PsiParameter parameter) { PsiMethod method = (PsiMethod)parameter.getDeclarationScope(); diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinJavaSafeDeleteDelegate.java b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinJavaSafeDeleteDelegate.java index 0f97106267e..cd61515a0a1 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinJavaSafeDeleteDelegate.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinJavaSafeDeleteDelegate.java @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package org.jetbrains.jet.plugin.refactoring.safeDelete; import com.intellij.psi.PsiElement; diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingDialog.java b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingDialog.java index 382483264c0..33ac4bd6433 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingDialog.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingDialog.java @@ -30,6 +30,7 @@ import com.intellij.ui.ScrollPaneFactory; import com.intellij.ui.table.JBTable; import com.intellij.usageView.UsageInfo; import com.intellij.usages.impl.UsagePreviewPanel; +import jet.runtime.typeinfo.KotlinSignature; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor; import org.jetbrains.jet.lang.descriptors.ClassDescriptor; @@ -116,6 +117,7 @@ class KotlinOverridingDialog extends DialogWrapper { return "#org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinOverridingDialog"; } + @KotlinSignature("fun getSelected(): ArrayList") public ArrayList getSelected() { ArrayList result = new ArrayList(); for (int i = 0; i < myChecked.length; i++) { diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java deleted file mode 100644 index 698cbe423b8..00000000000 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright 2010-2013 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.jet.plugin.refactoring.safeDelete; - -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.module.Module; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Condition; -import com.intellij.openapi.util.Conditions; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiMethod; -import com.intellij.psi.PsiParameter; -import com.intellij.psi.PsiReference; -import com.intellij.psi.search.searches.ReferencesSearch; -import com.intellij.psi.util.PsiTreeUtil; -import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor; -import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo; -import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverrideAnnotation; -import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverridingMethodUsageInfo; -import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceJavaDeleteUsageInfo; -import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo; -import com.intellij.usageView.UsageInfo; -import com.intellij.util.IncorrectOperationException; -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; -import org.jetbrains.jet.lang.descriptors.Modality; -import org.jetbrains.jet.lang.psi.*; -import org.jetbrains.jet.lang.psi.psiUtil.PsiUtilPackage; -import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.java.jetAsJava.KotlinLightMethod; -import org.jetbrains.jet.lexer.JetTokens; -import org.jetbrains.jet.plugin.JetBundle; -import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; -import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil; -import org.jetbrains.jet.plugin.references.JetPsiReference; - -import java.util.*; - -public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { - public static boolean canDeleteElement(@NotNull PsiElement element) { - if (PsiUtilPackage.isObjectLiteral(element)) return false; - if (element instanceof JetParameter) { - JetDeclaration declaration = PsiTreeUtil.getParentOfType(element, JetDeclaration.class); - return declaration != null && !(declaration instanceof JetPropertyAccessor && ((JetPropertyAccessor) declaration).isSetter()); - } - return element instanceof JetClassOrObject - || element instanceof JetNamedFunction - || element instanceof PsiMethod - || element instanceof JetProperty - || element instanceof JetTypeParameter; - } - - @Override - public boolean handlesElement(@NotNull PsiElement element) { - return canDeleteElement(element); - } - - @NotNull - protected static NonCodeUsageSearchInfo getSearchInfo( - @NotNull PsiElement element, @NotNull Collection ignoredElements - ) { - - return new NonCodeUsageSearchInfo(getCondition(ignoredElements), element); - } - - private static Condition getCondition(final Collection ignoredElements) { - return new Condition() { - @Override - public boolean value(PsiElement usage) { - if (usage instanceof JetFile) return false; - return isInside(usage, ignoredElements); - } - }; - } - - @NotNull - protected static NonCodeUsageSearchInfo getSearchInfo(@NotNull PsiElement element, @NotNull PsiElement[] ignoredElements) { - return getSearchInfo(element, Arrays.asList(ignoredElements)); - } - - @Nullable - @Override - public NonCodeUsageSearchInfo findUsages( - @NotNull PsiElement element, @NotNull PsiElement[] allElementsToDelete, @NotNull List result - ) { - if (element instanceof JetClassOrObject) { - return delegateToJavaProcessor(LightClassUtil.getPsiClass((JetClassOrObject) element), allElementsToDelete, result); - } - if (element instanceof JetNamedFunction) { - JetNamedFunction function = (JetNamedFunction) element; - if (function.isLocal()) { - return findKotlinDeclarationUsages(function, allElementsToDelete, result); - } - PsiMethod method = LightClassUtil.getLightClassMethod((JetNamedFunction) element); - if (method != null) return delegateToJavaProcessor(method, allElementsToDelete, result); - - return getSearchInfo(element, allElementsToDelete); - } - if (element instanceof PsiMethod) { - return delegateToJavaProcessor(element, allElementsToDelete, result); - } - if (element instanceof JetProperty) { - JetProperty property = (JetProperty) element; - - if (property.isLocal()) return findKotlinDeclarationUsages(property, allElementsToDelete, result); - return delegateToJavaProcessor(property, allElementsToDelete, result); - } - if (element instanceof JetTypeParameter) { - JetTypeParameter typeParameter = (JetTypeParameter) element; - - findTypeParameterUsages(typeParameter, result); - return delegateToJavaProcessor(typeParameter, allElementsToDelete, result); - } - if (element instanceof JetParameter) { - return delegateToJavaProcessor((JetParameter) element, allElementsToDelete, result); - } - - return getSearchInfo(element, allElementsToDelete); - } - - private NonCodeUsageSearchInfo delegateToJavaProcessor( - JetDeclaration jetDeclaration, - PsiElement[] allElementsToDelete, - List result - ) { - return new NonCodeUsageSearchInfo( - delegateToJavaProcessorAndCombineConditions( - AsJavaPackage.toLightElements(jetDeclaration), - getCondition(Arrays.asList(allElementsToDelete)), - allElementsToDelete, - result - ), - jetDeclaration - ); - } - - private Condition delegateToJavaProcessorAndCombineConditions( - Iterable elements, - Condition insideDeleted, - PsiElement[] allElementsToDelete, - List result - ) { - for (PsiElement element: elements) { - NonCodeUsageSearchInfo accessorSearchInfo = delegateToJavaProcessor(element, allElementsToDelete, result); - if (accessorSearchInfo == null) continue; - - insideDeleted = Conditions.or(insideDeleted, accessorSearchInfo.getInsideDeletedCondition()); - } - return insideDeleted; - } - - @SuppressWarnings("MethodOverridesPrivateMethodOfSuperclass") - protected static boolean isInside(@NotNull PsiElement place, @NotNull PsiElement[] ancestors) { - return isInside(place, Arrays.asList(ancestors)); - } - - @SuppressWarnings("MethodOverridesPrivateMethodOfSuperclass") - protected static boolean isInside(@NotNull PsiElement place, @NotNull Collection ancestors) { - for (PsiElement element : ancestors) { - if (isInside(place, element)) return true; - } - return false; - } - - @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") - public static boolean isInside(@NotNull PsiElement place, @NotNull PsiElement ancestor) { - return JavaSafeDeleteProcessor.isInside(place, AsJavaPackage.getUnwrapped(ancestor)); - } - - @Nullable - protected NonCodeUsageSearchInfo delegateToJavaProcessor( - @Nullable PsiElement element, - @NotNull PsiElement[] allElementsToDelete, - @NotNull List result - ) { - if (element == null) return null; - - List javaUsages = new ArrayList(); - NonCodeUsageSearchInfo searchInfo = super.findUsages(element, allElementsToDelete, javaUsages); - - for (UsageInfo usageInfo : javaUsages) { - if (usageInfo instanceof SafeDeleteOverridingMethodUsageInfo) { - SafeDeleteOverridingMethodUsageInfo overrideUsageInfo = (SafeDeleteOverridingMethodUsageInfo) usageInfo; - - PsiElement usageElement = overrideUsageInfo.getSmartPointer().getElement(); - usageInfo = (usageElement != null) - ? new KotlinSafeDeleteOverridingUsageInfo(usageElement, overrideUsageInfo.getReferencedElement()) - : null; - } - else if (usageInfo instanceof SafeDeleteOverrideAnnotation) { - SafeDeleteOverrideAnnotation overrideAnnotationUsageInfo = (SafeDeleteOverrideAnnotation) usageInfo; - - PsiElement targetElement = overrideAnnotationUsageInfo.getSmartPointer().getElement(); - if (targetElement != null) { - boolean noSuperMethods = ContainerUtil.and( - AsJavaPackage.toLightMethods(targetElement), - new Condition() { - @Override - public boolean value(PsiMethod method) { - return method.findSuperMethods().length == 0; - } - } - ); - - usageInfo = noSuperMethods - ? new KotlinSafeDeleteOverrideAnnotation(targetElement, overrideAnnotationUsageInfo.getReferencedElement()) - : null; - } - else { - usageInfo = null; - } - } - 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 = new SafeDeleteImportDirectiveUsageInfo( - importDirective, (JetDeclaration) AsJavaPackage.getUnwrapped(element) - ); - } - } - if (usageInfo != null) { - result.add(usageInfo); - } - } - - return searchInfo; - } - - @NotNull - protected static NonCodeUsageSearchInfo findKotlinDeclarationUsages( - @NotNull final JetDeclaration declaration, - @NotNull final PsiElement[] allElementsToDelete, - @NotNull final List result - ) { - ReferencesSearch.search(declaration, declaration.getUseScope()).forEach(new Processor() { - @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, declaration)); - } - else { - result.add(new SafeDeleteReferenceSimpleDeleteUsageInfo(element, declaration, false)); - } - } - return true; - } - }); - - return getSearchInfo(declaration, allElementsToDelete); - } - - protected static void findTypeParameterUsages( - @NotNull final JetTypeParameter parameter, - @NotNull final List result - ) { - JetTypeParameterListOwner owner = PsiTreeUtil.getParentOfType(parameter, JetTypeParameterListOwner.class); - if (owner == null) return; - - List parameterList = owner.getTypeParameters(); - final int parameterIndex = parameterList.indexOf(parameter); - - ReferencesSearch.search(owner).forEach( - new Processor() { - @Override - public boolean process(PsiReference reference) { - if (reference instanceof JetPsiReference) { - processKotlinTypeArgumentListCandidate(reference, parameterIndex, result, parameter); - } - return true; - } - } - ); - } - - private static void processKotlinTypeArgumentListCandidate( - @NotNull PsiReference reference, - int parameterIndex, - @NotNull List result, - @NotNull JetTypeParameter parameter - ) { - PsiElement referencedElement = reference.getElement(); - - JetTypeArgumentList argList = null; - - JetUserType type = PsiTreeUtil.getParentOfType(referencedElement, JetUserType.class); - if (type != null) { - argList = type.getTypeArgumentList(); - } - else { - JetCallExpression callExpression = PsiTreeUtil.getParentOfType(referencedElement, JetCallExpression.class); - if (callExpression != null) { - argList = callExpression.getTypeArgumentList(); - } - } - - if (argList != null) { - List projections = argList.getArguments(); - if (parameterIndex < projections.size()) { - result.add(new SafeDeleteTypeArgumentListUsageInfo(projections.get(parameterIndex), parameter)); - } - } - } - - @Override - @Nullable - public Collection findConflicts(@NotNull PsiElement element, @NotNull PsiElement[] allElementsToDelete) { - if (element instanceof JetNamedFunction || element instanceof JetProperty) { - JetClass jetClass = PsiTreeUtil.getParentOfType(element, JetClass.class); - if (jetClass == null || jetClass.getBody() != element.getParent()) return null; - - JetModifierList modifierList = jetClass.getModifierList(); - if (modifierList != null && modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) return null; - - BindingContext bindingContext = - AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) element.getContainingFile()).getBindingContext(); - - DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); - if (!(declarationDescriptor instanceof CallableMemberDescriptor)) return null; - - List messages = new ArrayList(); - CallableMemberDescriptor callableDescriptor = (CallableMemberDescriptor) declarationDescriptor; - for (CallableMemberDescriptor overridenDescriptor : callableDescriptor.getOverriddenDescriptors()) { - if (overridenDescriptor.getModality() == Modality.ABSTRACT) { - String message = JetBundle.message( - "x.implements.y", - JetRefactoringUtil.formatFunction(callableDescriptor, bindingContext, true), - JetRefactoringUtil.formatClass(callableDescriptor.getContainingDeclaration(), bindingContext, true), - JetRefactoringUtil.formatFunction(overridenDescriptor, bindingContext, true), - JetRefactoringUtil.formatClass(overridenDescriptor.getContainingDeclaration(), bindingContext, true) - ); - messages.add(message); - } - } - - if (!messages.isEmpty()) return messages; - } - return super.findConflicts(element, allElementsToDelete); - } - - /* - * Mostly copied from JavaSafeDeleteProcessor.preprocessUsages - * Revision: d4fc033 - * (replaced original dialog) - */ - @Nullable - @Override - public UsageInfo[] preprocessUsages(@NotNull Project project, @NotNull UsageInfo[] usages) { - ArrayList result = new ArrayList(); - ArrayList overridingMethodUsages = new ArrayList(); - - for (UsageInfo usage : usages) { - if (usage instanceof KotlinSafeDeleteOverridingUsageInfo) { - overridingMethodUsages.add(usage); - } - else { - result.add(usage); - } - } - - if (!overridingMethodUsages.isEmpty()) { - if (ApplicationManager.getApplication().isUnitTestMode()) { - result.addAll(overridingMethodUsages); - } - else { - KotlinOverridingDialog dialog = new KotlinOverridingDialog(project, overridingMethodUsages); - dialog.show(); - if (!dialog.isOK()) return null; - result.addAll(dialog.getSelected()); - } - } - - return result.toArray(new UsageInfo[result.size()]); - } - - @Override - public void prepareForDeletion(@NotNull PsiElement element) throws IncorrectOperationException { - if (element instanceof PsiMethod) { - SafeDeletePackage.cleanUpOverrides((PsiMethod) element); - } - else if (element instanceof JetNamedFunction) { - PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) element); - if (lightMethod == null) { - return; - } - - SafeDeletePackage.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) { - SafeDeletePackage.cleanUpOverrides(getter); - } - if (setter != null) { - SafeDeletePackage.cleanUpOverrides(setter); - } - } - else if (element instanceof JetTypeParameter) { - PsiUtilPackage.deleteElementAndCleanParent(element); - } - else if (element instanceof JetParameter) { - JetPsiUtil.deleteElementWithDelimiters(element); - } - } - - @Nullable - @Override - public Collection getElementsToSearch( - @NotNull PsiElement element, @Nullable Module module, @NotNull Collection allElementsToDelete - ) { - if (element instanceof JetParameter) { - PsiParameter psiParameter = AsJavaPackage.toPsiParameter((JetParameter) element); - if (psiParameter != null) return JetRefactoringUtil.checkParametersInMethodHierarchy(psiParameter); - } - - if (element instanceof PsiParameter) { - return JetRefactoringUtil.checkParametersInMethodHierarchy((PsiParameter) element); - } - - if (ApplicationManager.getApplication().isUnitTestMode()) { - return Collections.singletonList(element); - } - - if (element instanceof JetNamedFunction || element instanceof JetProperty) { - return JetRefactoringUtil.checkSuperMethods( - (JetDeclaration) element, allElementsToDelete, "super.methods.delete.with.usage.search" - ); - } - - return super.getElementsToSearch(element, module, allElementsToDelete); - } -} diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt new file mode 100644 index 00000000000..a82689fda38 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.kt @@ -0,0 +1,310 @@ +/* + * Copyright 2010-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.plugin.refactoring.safeDelete + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Condition +import com.intellij.openapi.util.Conditions +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiMethod +import com.intellij.psi.PsiParameter +import com.intellij.psi.search.searches.ReferencesSearch +import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor +import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo +import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverrideAnnotation +import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverridingMethodUsageInfo +import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceJavaDeleteUsageInfo +import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo +import com.intellij.usageView.UsageInfo +import org.jetbrains.jet.asJava.* +import org.jetbrains.jet.lang.descriptors.CallableMemberDescriptor +import org.jetbrains.jet.lang.descriptors.Modality +import org.jetbrains.jet.lang.psi.* +import org.jetbrains.jet.lang.resolve.BindingContext +import org.jetbrains.jet.lexer.JetTokens +import org.jetbrains.jet.plugin.JetBundle +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache +import org.jetbrains.jet.plugin.refactoring.JetRefactoringUtil +import org.jetbrains.jet.plugin.references.JetPsiReference +import java.util.* +import org.jetbrains.jet.lang.psi.psiUtil.getParentByType +import org.jetbrains.jet.lang.psi.psiUtil.deleteElementAndCleanParent + +public class KotlinSafeDeleteProcessor : JavaSafeDeleteProcessor() { + override fun handlesElement(element: PsiElement): Boolean = element.canDeleteElement() + + override fun findUsages( + element: PsiElement, allElementsToDelete: Array, usages: MutableList + ): NonCodeUsageSearchInfo { + val deleteList = allElementsToDelete.toList() + + fun getIgnoranceCondition(): Condition { + return object : Condition { + override fun value(t: PsiElement?): Boolean { + if (t is JetFile) return false + return deleteList.any { element -> JavaSafeDeleteProcessor.isInside(t, element.unwrapped) } + } + } + } + + fun getSearchInfo(element: PsiElement): NonCodeUsageSearchInfo { + return NonCodeUsageSearchInfo(getIgnoranceCondition(), element) + } + + fun findUsagesByJavaProcessor(element: PsiElement): NonCodeUsageSearchInfo? { + val javaUsages = ArrayList() + val searchInfo = super.findUsages(element, allElementsToDelete, javaUsages) + + javaUsages.map { usageInfo -> + when (usageInfo) { + is SafeDeleteOverridingMethodUsageInfo -> + usageInfo.getSmartPointer().getElement()?.let { usageElement -> + KotlinSafeDeleteOverridingUsageInfo(usageElement, usageInfo.getReferencedElement()) + } + + is SafeDeleteOverrideAnnotation -> + usageInfo.getSmartPointer().getElement()?.let { usageElement -> + if (usageElement.toLightMethods().all { method -> method.findSuperMethods().size == 0 }) { + KotlinSafeDeleteOverrideAnnotation(usageElement, usageInfo.getReferencedElement()) + } + else null + } + + is SafeDeleteReferenceJavaDeleteUsageInfo -> + usageInfo.getElement()?.let { usageElement -> + if (usageElement.getParentByType(javaClass()) != null) null + else { + usageElement.getParentByType(javaClass())?.let { importDirective -> + SafeDeleteImportDirectiveUsageInfo(importDirective, element.unwrapped as JetDeclaration) + } ?: usageInfo + } + } + + else -> usageInfo + } + }.filterNotNull().toCollection(usages) + + return searchInfo + } + + fun findUsagesByJavaProcessor(elements: Iterator, insideDeleted: Condition): Condition = + elements + .map { element -> findUsagesByJavaProcessor(element)?.getInsideDeletedCondition() } + .filterNotNull() + .fold(insideDeleted) {(condition1, condition2) -> Conditions.or(condition1, condition2) } + + fun findUsagesByJavaProcessor(jetDeclaration: JetDeclaration): NonCodeUsageSearchInfo { + return NonCodeUsageSearchInfo( + findUsagesByJavaProcessor( + jetDeclaration.toLightElements().iterator(), + getIgnoranceCondition() + ), + jetDeclaration + ) + } + + fun findKotlinDeclarationUsages(declaration: JetDeclaration): NonCodeUsageSearchInfo { + ReferencesSearch.search(declaration, declaration.getUseScope()) + .iterator() + .filterNot { reference -> getIgnoranceCondition().value(reference.getElement()) } + .mapTo(usages) { reference -> + reference.getElement().getParentByType(javaClass())?.let { importDirective -> + SafeDeleteImportDirectiveUsageInfo(importDirective, element.unwrapped as JetDeclaration) + } ?: SafeDeleteReferenceSimpleDeleteUsageInfo(element, declaration, false) + } + + return getSearchInfo(declaration) + } + + fun findTypeParameterUsages(parameter: JetTypeParameter) { + val owner = parameter.getParentByType(javaClass()) + if (owner == null) return + + val parameterList = owner.getTypeParameters() + val parameterIndex = parameterList.indexOf(parameter) + + for (reference in ReferencesSearch.search(owner)) { + if (reference !is JetPsiReference) continue + + val referencedElement = reference.getElement() + + val argList = referencedElement.getParentByType(javaClass())?.let { jetType -> + jetType.getTypeArgumentList() + } ?: referencedElement.getParentByType(javaClass())?.let { callExpression -> + callExpression.getTypeArgumentList() + } ?: null + + if (argList != null) { + val projections = argList.getArguments() + if (parameterIndex < projections.size()) { + usages.add(SafeDeleteTypeArgumentListUsageInfo(projections.get(parameterIndex), parameter)) + } + } + } + } + + val searchInfo = when (element) { + is JetClassOrObject -> + element.toLightClass()?.let { klass -> findUsagesByJavaProcessor(klass) } + + is JetNamedFunction -> { + if (element.isLocal()) { + findKotlinDeclarationUsages(element) + } + else { + element.getRepresentativeLightMethod()?.let { method -> findUsagesByJavaProcessor(method) } + } + } + + is PsiMethod -> + findUsagesByJavaProcessor(element) + + is JetProperty -> { + if (element.isLocal()) { + findKotlinDeclarationUsages(element) + } + else { + findUsagesByJavaProcessor(element) + } + } + + is JetTypeParameter -> { + findTypeParameterUsages(element) + findUsagesByJavaProcessor(element) + } + + is JetParameter -> + findUsagesByJavaProcessor(element) + + else -> null + } + + return if (searchInfo != null) searchInfo else getSearchInfo(element) + } + + override fun findConflicts(element: PsiElement, allElementsToDelete: Array): MutableCollection? { + if (element is JetNamedFunction || element is JetProperty) { + val jetClass = element.getParentByType(javaClass()) + if (jetClass == null || jetClass.getBody() != element.getParent()) return null + + val modifierList = jetClass.getModifierList() + if (modifierList != null && modifierList.hasModifier(JetTokens.ABSTRACT_KEYWORD)) return null + + val bindingContext = AnalyzerFacadeWithCache.getContextForElement(element as JetElement) + + val declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element) + if (declarationDescriptor !is CallableMemberDescriptor) return null + + return declarationDescriptor.getOverriddenDescriptors() + .iterator() + .filter { overridenDescriptor -> overridenDescriptor.getModality() == Modality.ABSTRACT } + .mapTo(ArrayList()) { overridenDescriptor -> + JetBundle.message( + "x.implements.y", + JetRefactoringUtil.formatFunction(declarationDescriptor, bindingContext, true), + JetRefactoringUtil.formatClass(declarationDescriptor.getContainingDeclaration(), bindingContext, true), + JetRefactoringUtil.formatFunction(overridenDescriptor, bindingContext, true), + JetRefactoringUtil.formatClass(overridenDescriptor.getContainingDeclaration(), bindingContext, true) + ) + } + } + + return super.findConflicts(element, allElementsToDelete) + } + + /* + * Mostly copied from JavaSafeDeleteProcessor.preprocessUsages + * Revision: d4fc033 + * (replaced original dialog) + */ + override fun preprocessUsages(project: Project, usages: Array): Array? { + val result = ArrayList() + val overridingMethodUsages = ArrayList() + + for (usage in usages) { + if (usage is KotlinSafeDeleteOverridingUsageInfo) { + overridingMethodUsages.add(usage) + } else { + result.add(usage) + } + } + + if (!overridingMethodUsages.isEmpty()) { + if (ApplicationManager.getApplication()!!.isUnitTestMode()) { + result.addAll(overridingMethodUsages) + } else { + val dialog = KotlinOverridingDialog(project, overridingMethodUsages) + dialog.show() + + if (!dialog.isOK()) return null + + result.addAll(dialog.getSelected()) + } + } + + return result.copyToArray() + } + + override fun prepareForDeletion(element: PsiElement) { + when (element) { + is PsiMethod -> element.cleanUpOverrides() + + is JetNamedFunction -> + if (!element.isLocal()) { + element.getRepresentativeLightMethod()?.cleanUpOverrides() + } + + is JetProperty -> + if (!element.isLocal()) { + element.toLightMethods().forEach { method -> method.cleanUpOverrides() } + } + + is JetTypeParameter -> + element.deleteElementAndCleanParent() + + is JetParameter -> + JetPsiUtil.deleteElementWithDelimiters(element) + } + } + + override fun getElementsToSearch( + element: PsiElement, module: Module?, allElementsToDelete: Collection + ): Collection? { + when (element) { + is JetParameter -> + return element.toPsiParameter()?.let { psiParameter -> + JetRefactoringUtil.checkParametersInMethodHierarchy(psiParameter) + } ?: Collections.singletonList(element) + + is PsiParameter -> + return JetRefactoringUtil.checkParametersInMethodHierarchy(element) + } + + if (ApplicationManager.getApplication()!!.isUnitTestMode()) return Collections.singletonList(element) + + return when (element) { + is JetNamedFunction, is JetProperty -> + JetRefactoringUtil.checkSuperMethods( + element as JetDeclaration, allElementsToDelete, "super.methods.delete.with.usage.search" + ) + + else -> super.getElementsToSearch(element, module, allElementsToDelete) + } + } +} diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/utils.kt b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/utils.kt index 2836c0b3292..d1892819d4d 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/utils.kt +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/utils.kt @@ -26,6 +26,27 @@ import org.jetbrains.jet.lang.psi.JetPsiUtil import com.intellij.psi.search.searches.OverridingMethodsSearch import org.jetbrains.jet.asJava.unwrapped import java.util.ArrayList +import org.jetbrains.jet.lang.psi.JetParameter +import org.jetbrains.jet.lang.psi.JetDeclaration +import org.jetbrains.jet.lang.psi.JetPropertyAccessor +import org.jetbrains.jet.lang.psi.JetClassOrObject +import org.jetbrains.jet.lang.psi.JetTypeParameter +import org.jetbrains.jet.lang.psi.psiUtil.* + +public fun PsiElement.canDeleteElement(): Boolean { + if (isObjectLiteral()) return false + + if (this is JetParameter) { + val declaration = getParentByType(javaClass(), true) + return declaration != null && !(declaration is JetPropertyAccessor && declaration.isSetter()) + } + + return this is JetClassOrObject + || this is JetNamedFunction + || this is PsiMethod + || this is JetProperty + || this is JetTypeParameter +} fun PsiElement.removeOverrideModifier() { val modifier = when (this) {