diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifierList.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifierList.java index 9109d52cc7b..963e37911d4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifierList.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetModifierList.java @@ -18,6 +18,7 @@ package org.jetbrains.jet.lang.psi; import com.google.common.collect.Lists; import com.intellij.lang.ASTNode; +import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; @@ -62,6 +63,11 @@ public class JetModifierList extends JetElementImpl { return getModifierNode(token) != null; } + @Nullable + public PsiElement getModifier(JetToken token) { + return findChildByType(token); + } + @Nullable public ASTNode getModifierNode(JetToken token) { ASTNode node = getNode().getFirstChildNode(); @@ -71,4 +77,6 @@ public class JetModifierList extends JetElementImpl { } return null; } + + } diff --git a/generators/org/jetbrains/jet/generators/tests/GenerateTests.java b/generators/org/jetbrains/jet/generators/tests/GenerateTests.java index 97c4d158a39..f2ec4c9a962 100644 --- a/generators/org/jetbrains/jet/generators/tests/GenerateTests.java +++ b/generators/org/jetbrains/jet/generators/tests/GenerateTests.java @@ -402,7 +402,10 @@ public class GenerateTests { "JetSafeDeleteTestGenerated", AbstractJetSafeDeleteTest.class, testModel("idea/testData/safeDelete/deleteClass", "doClassTest"), - testModel("idea/testData/safeDelete/deleteObject", "doObjectTest") + testModel("idea/testData/safeDelete/deleteObject", "doObjectTest"), + testModel("idea/testData/safeDelete/deleteFunction", "doFunctionTest"), + testModel("idea/testData/safeDelete/deleteFunctionWithJavaUsages", "doFunctionTestWithJava"), + testModel("idea/testData/safeDelete/deleteJavaMethod", "doJavaMethodTest") ); } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 77ba08121c1..9e8fd2c469c 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -227,7 +227,10 @@ - + diff --git a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties index 47bb855cc04..b2d2d9f78db 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetBundle.properties +++ b/idea/src/org/jetbrains/jet/plugin/JetBundle.properties @@ -253,4 +253,9 @@ usageType.function.call = Function call usageType.extension.receiver.type = Extension receiver type usageType.super.type.qualifier = Super type qualifier usageType.receiver = Receiver -usageType.selector = Selector \ No newline at end of file +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 \ No newline at end of file diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java index b814bc4086a..4e976396942 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/JetRefactoringSupportProvider.java @@ -33,7 +33,7 @@ import org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinSafeDeleteProcessor public class JetRefactoringSupportProvider extends RefactoringSupportProvider { @Override public boolean isSafeDeleteAvailable(PsiElement element) { - return KotlinSafeDeleteProcessor.checkElement(element); + return KotlinSafeDeleteProcessor.canDeleteElement(element); } @Override diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingMethodsDialog.java b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingMethodsDialog.java new file mode 100644 index 00000000000..f8016dbafce --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinOverridingMethodsDialog.java @@ -0,0 +1,295 @@ +/* + * 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.Disposable; +import com.intellij.openapi.help.HelpManager; +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.PsiMethod; +import com.intellij.refactoring.HelpID; +import com.intellij.refactoring.RefactoringBundle; +import com.intellij.ui.BooleanTableCellRenderer; +import com.intellij.ui.ScrollPaneFactory; +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.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.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; + +import javax.swing.*; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.table.AbstractTableModel; +import javax.swing.table.TableColumnModel; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.KeyEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/* +* Mostly copied from com.intellij.refactoring.safeDelete.OverridingMethodsDialog +* Revision: 14aa2e2 +* (replace PsiMethod formatting) +*/ +class KotlinOverridingMethodsDialog extends DialogWrapper { + private final List myOverridingMethods; + private final String[] myMethodText; + private final boolean[] myChecked; + + private static final int CHECK_COLUMN = 0; + private JBTable myTable; + private final UsagePreviewPanel myUsagePreviewPanel; + + public KotlinOverridingMethodsDialog(Project project, List overridingMethods) { + super(project, true); + myOverridingMethods = overridingMethods; + myChecked = new boolean[myOverridingMethods.size()]; + for (int i = 0; i < myChecked.length; i++) { + myChecked[i] = true; + } + + myMethodText = new String[myOverridingMethods.size()]; + for (int i = 0; i < myMethodText.length; i++) { + myMethodText[i] = formatMethod(((KotlinSafeDeleteOverridingMethodUsageInfo) myOverridingMethods.get(i)).getOverridingMethod()); + } + 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(); + + BindingContext bindingContext = + AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) function.getContainingFile()).getBindingContext(); + + DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function); + if (declarationDescriptor instanceof FunctionDescriptor) { + DeclarationDescriptor containingDescriptor = declarationDescriptor.getContainingDeclaration(); + if (containingDescriptor instanceof ClassDescriptor) { + return JetBundle.message( + "x.in.y", + DescriptorRenderer.COMPACT.render(declarationDescriptor), + DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(containingDescriptor) + ); + } + } + } + + return KotlinSafeDeleteProcessor.formatPsiMethod(method, true, false); + } + + @Override + protected String getDimensionServiceKey() { + return "#org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinOverridingMethodsDialog"; + } + + public ArrayList getSelected() { + ArrayList result = new ArrayList(); + for (int i = 0; i < myChecked.length; i++) { + if (myChecked[i]) { + result.add(myOverridingMethods.get(i)); + } + } + return result; + } + + @NotNull + @Override + protected Action[] createActions() { + return new Action[] {getOKAction(), getCancelAction()}; + } + + @Override + protected void doHelpAction() { + HelpManager.getInstance().invokeHelp(HelpID.SAFE_DELETE_OVERRIDING); + } + + @Override + 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"))); + return panel; + } + + @Override + public JComponent getPreferredFocusedComponent() { + return myTable; + } + + @Override + protected void dispose() { + Disposer.dispose(myUsagePreviewPanel); + super.dispose(); + } + + @Override + protected JComponent createCenterPanel() { + JPanel panel = new JPanel(new BorderLayout()); + panel.setBorder(BorderFactory.createEmptyBorder(8, 0, 4, 0)); + final MyTableModel tableModel = new MyTableModel(); + myTable = new JBTable(tableModel); + myTable.setShowGrid(false); + + TableColumnModel columnModel = myTable.getColumnModel(); + int checkBoxWidth = new JCheckBox().getPreferredSize().width; + columnModel.getColumn(CHECK_COLUMN).setCellRenderer(new BooleanTableCellRenderer()); + columnModel.getColumn(CHECK_COLUMN).setMaxWidth(checkBoxWidth); + columnModel.getColumn(CHECK_COLUMN).setMinWidth(checkBoxWidth); + + + // make SPACE check/uncheck selected rows + InputMap inputMap = myTable.getInputMap(); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "enable_disable"); + ActionMap actionMap = myTable.getActionMap(); + actionMap.put("enable_disable", new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + if (myTable.isEditing()) return; + int[] rows = myTable.getSelectedRows(); + if (rows.length > 0) { + boolean valueToBeSet = false; + for (int row : rows) { + if (!myChecked[row]) { + valueToBeSet = true; + break; + } + } + for (int row : rows) { + myChecked[row] = valueToBeSet; + } + + tableModel.updateData(); + } + } + }); + + panel.setLayout(new BorderLayout()); + + JScrollPane scrollPane = ScrollPaneFactory.createScrollPane(myTable); + + panel.add(scrollPane, BorderLayout.CENTER); + ListSelectionListener selectionListener = new ListSelectionListener() { + @Override + public void valueChanged(ListSelectionEvent e) { + int index = myTable.getSelectionModel().getLeadSelectionIndex(); + if (index != -1) { + UsageInfo usageInfo = myOverridingMethods.get(index); + myUsagePreviewPanel.updateLayout(Collections.singletonList(usageInfo)); + } + else { + myUsagePreviewPanel.updateLayout(null); + } + } + }; + myTable.getSelectionModel().addListSelectionListener(selectionListener); + + final Splitter splitter = new Splitter(true, 0.3f); + splitter.setFirstComponent(panel); + splitter.setSecondComponent(myUsagePreviewPanel); + myUsagePreviewPanel.updateLayout(null); + + Disposer.register(myDisposable, new Disposable() { + @Override + public void dispose() { + splitter.dispose(); + } + }); + + if (tableModel.getRowCount() != 0) { + myTable.getSelectionModel().addSelectionInterval(0, 0); + } + return splitter; + } + + class MyTableModel extends AbstractTableModel { + @Override + public int getRowCount() { + return myChecked.length; + } + + @Override + public String getColumnName(int column) { + switch (column) { + case CHECK_COLUMN: + return " "; + default: + return RefactoringBundle.message("method.column"); + } + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case CHECK_COLUMN: + return Boolean.class; + default: + return String.class; + } + } + + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + if (columnIndex == CHECK_COLUMN) { + return Boolean.valueOf(myChecked[rowIndex]); + } + else { + return myMethodText[rowIndex]; + } + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + if (columnIndex == CHECK_COLUMN) { + myChecked[rowIndex] = ((Boolean) aValue).booleanValue(); + } + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return columnIndex == CHECK_COLUMN; + } + + void updateData() { + fireTableDataChanged(); + } + } +} + diff --git a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteOverridingMethodUsageInfo.java b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteOverridingMethodUsageInfo.java new file mode 100644 index 00000000000..77e48b30ca6 --- /dev/null +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteOverridingMethodUsageInfo.java @@ -0,0 +1,50 @@ +/* + * 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.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; + +public class KotlinSafeDeleteOverridingMethodUsageInfo extends SafeDeleteUsageInfo implements SafeDeleteCustomUsageInfo { + public KotlinSafeDeleteOverridingMethodUsageInfo(PsiElement overridingMethod, PsiElement method) { + super(toPsiMethod(overridingMethod), toPsiMethod(method)); + } + + 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()); + } + + @Override + public void performRefactoring() throws IncorrectOperationException { + PsiElement element = getElement(); + if (element != null) { + element.delete(); + } + } +} 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 1921af9663f..6109a9426e7 100644 --- a/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java +++ b/idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java @@ -16,37 +16,54 @@ package org.jetbrains.jet.plugin.refactoring.safeDelete; +import com.intellij.ide.IdeBundle; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiReference; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Condition; +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.util.PsiTreeUtil; +import com.intellij.psi.search.searches.SuperMethodsSearch; +import com.intellij.psi.util.*; import com.intellij.refactoring.safeDelete.JavaSafeDeleteProcessor; import com.intellij.refactoring.safeDelete.NonCodeUsageSearchInfo; import com.intellij.refactoring.safeDelete.SafeDeleteProcessor; +import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteOverridingMethodUsageInfo; import com.intellij.refactoring.safeDelete.usageInfo.SafeDeleteReferenceSimpleDeleteUsageInfo; import com.intellij.usageView.UsageInfo; -import com.intellij.util.Processor; +import com.intellij.util.*; +import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.jet.lang.psi.JetClassOrObject; -import org.jetbrains.jet.lang.psi.JetImportDirective; -import org.jetbrains.jet.lang.psi.JetObjectDeclaration; -import org.jetbrains.jet.lang.psi.JetObjectDeclarationName; +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.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.BindingContextUtils; +import org.jetbrains.jet.lang.resolve.java.JetClsMethod; +import org.jetbrains.jet.lexer.JetTokens; +import org.jetbrains.jet.plugin.JetBundle; +import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache; +import org.jetbrains.jet.renderer.DescriptorRenderer; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; +import java.util.*; public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { - public static boolean checkElement(PsiElement element) { + public static boolean canDeleteElement(PsiElement element) { return element instanceof JetClassOrObject - || element instanceof JetObjectDeclarationName; + || element instanceof JetObjectDeclarationName + || element instanceof JetNamedFunction + || element instanceof PsiMethod; } @Override public boolean handlesElement(PsiElement element) { - return checkElement(element); + return canDeleteElement(element); } protected static NonCodeUsageSearchInfo getDefaultNonCodeUsageSearchInfo( @@ -61,12 +78,25 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { if (element instanceof JetClassOrObject) { return findClassOrObjectUsages(element, (JetClassOrObject) element, allElementsToDelete, result); } - if (element instanceof JetObjectDeclarationName && element.getParent() instanceof JetObjectDeclaration) { - return findClassOrObjectUsages(element, (JetObjectDeclaration) element.getParent(), allElementsToDelete, result); + if (element instanceof JetObjectDeclarationName) { + PsiElement parent = getObjectDeclarationOrFail(element); + return findClassOrObjectUsages(element, (JetObjectDeclaration) parent, allElementsToDelete, result); + } + if (element instanceof JetNamedFunction) { + return findFunctionUsages((JetNamedFunction) element, allElementsToDelete, result); + } + if (element instanceof PsiMethod) { + return findPsiMethodUsages((PsiMethod) element, allElementsToDelete, result); } return getDefaultNonCodeUsageSearchInfo(element, allElementsToDelete); } + private static PsiElement getObjectDeclarationOrFail(PsiElement element) { + PsiElement parent = element.getParent(); + assert parent instanceof JetObjectDeclaration; + return parent; + } + @SuppressWarnings("MethodOverridesPrivateMethodOfSuperclass") protected static boolean isInside(PsiElement place, PsiElement[] ancestors) { return isInside(place, Arrays.asList(ancestors)); @@ -80,6 +110,14 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { return false; } + @SuppressWarnings("MethodOverridesStaticMethodOfSuperclass") + public static boolean isInside(PsiElement place, PsiElement ancestor) { + if (ancestor instanceof JetClsMethod) { + ancestor = ((JetClsMethod) ancestor).getOrigin(); + } + return JavaSafeDeleteProcessor.isInside(place, ancestor); + } + protected static NonCodeUsageSearchInfo findClassOrObjectUsages( PsiElement referencedElement, final JetClassOrObject classOrObject, @@ -107,18 +145,441 @@ public class KotlinSafeDeleteProcessor extends JavaSafeDeleteProcessor { return getDefaultNonCodeUsageSearchInfo(referencedElement, allElementsToDelete); } + protected NonCodeUsageSearchInfo findPsiMethodUsages( + PsiMethod method, + PsiElement[] allElementsToDelete, + List result + ) { + List javaUsages = new ArrayList(); + NonCodeUsageSearchInfo searchInfo = super.findUsages(method, allElementsToDelete, javaUsages); + + for (UsageInfo usageInfo : javaUsages) { + if (usageInfo instanceof SafeDeleteOverridingMethodUsageInfo) { + SafeDeleteOverridingMethodUsageInfo overrideUsageInfo = (SafeDeleteOverridingMethodUsageInfo) usageInfo; + usageInfo = new KotlinSafeDeleteOverridingMethodUsageInfo( + overrideUsageInfo.getSmartPointer().getElement(), overrideUsageInfo.getReferencedElement() + ); + } + result.add(usageInfo); + } + + return searchInfo; + } + + private static List difference(Collection from, T[] a) { + List list = new ArrayList(from); + list.removeAll(Arrays.asList(a)); + return list; + } + + protected static NonCodeUsageSearchInfo findFunctionUsages( + JetNamedFunction function, + final PsiElement[] allElementsToDelete, + List result + ) { + PsiMethod lightMethod = LightClassUtil.getLightClassMethod(function); + if (lightMethod == null) { + return getDefaultNonCodeUsageSearchInfo(function, allElementsToDelete); + } + + Collection references = ReferencesSearch.search(function).findAll(); + List overridingMethods = difference(OverridingMethodsSearch.search(lightMethod, true).findAll(), 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, function)); + } + else { + result.add(new SafeDeleteReferenceSimpleDeleteUsageInfo(element, function, false)); + } + } + } + + HashMap> methodToReferences = new HashMap>(); + for (PsiMethod overridingMethod : overridingMethods) { + Collection overridingReferences = + ReferencesSearch.search( + overridingMethod instanceof JetClsMethod ? ((JetClsMethod) overridingMethod).getOrigin() : overridingMethod + ).findAll(); + methodToReferences.put(overridingMethod, overridingReferences); + } + final Set safeOverriding = + filterSafeOverridingMethods(lightMethod, references, overridingMethods, methodToReferences, result, allElementsToDelete); + + return new NonCodeUsageSearchInfo( + new Condition() { + @Override + public boolean value(PsiElement usage) { + if (usage instanceof JetFile) return false; + return isInside(usage, allElementsToDelete) || isInside(usage, safeOverriding); + } + }, + function + ); + } + + /* + * Mostly copied from JavaSafeDeleteProcessor.validateOverridingMethods + * Revision: d4fc033 + * (simplified and implemented proper treatment of light methods) + */ + private static Set filterSafeOverridingMethods( + PsiMethod originalMethod, Collection originalReferences, + Collection overridingMethods, HashMap> methodToReferences, + List usages, + PsiElement[] allElementsToDelete + ) { + Set validOverriding = new LinkedHashSet(overridingMethods); + boolean anyNewBadRefs; + do { + anyNewBadRefs = false; + for (PsiMethod overridingMethod : overridingMethods) { + if (validOverriding.contains(overridingMethod)) { + Collection overridingReferences = methodToReferences.get(overridingMethod); + boolean anyOverridingRefs = false; + for (PsiReference overridingReference : overridingReferences) { + PsiElement element = overridingReference.getElement(); + if (!isInside(element, allElementsToDelete) && !isInside(element, validOverriding)) { + anyOverridingRefs = true; + break; + } + } + + if (!anyOverridingRefs && isMultipleInterfacesImplementation(overridingMethod, originalMethod, allElementsToDelete)) { + anyOverridingRefs = true; + } + + if (anyOverridingRefs) { + validOverriding.remove(overridingMethod); + anyNewBadRefs = true; + + for (PsiReference reference : originalReferences) { + PsiElement element = reference.getElement(); + if (!isInside(element, allElementsToDelete) && !isInside(element, overridingMethods)) { + validOverriding.clear(); + } + } + } + } + } + } + while (anyNewBadRefs && !validOverriding.isEmpty()); + + for (PsiMethod method : validOverriding) { + if (method != originalMethod) { + usages.add(new KotlinSafeDeleteOverridingMethodUsageInfo(method, originalMethod)); + } + } + + return validOverriding; + } + + @SuppressWarnings("MethodOverridesPrivateMethodOfSuperclass") + private static boolean isMultipleInterfacesImplementation(PsiMethod method, PsiMethod originalMethod, PsiElement[] ignore) { + PsiMethod[] methods = method.findSuperMethods(); + for (PsiMethod superMethod: methods) { + PsiElement relevantElement = superMethod instanceof JetClsMethod ? ((JetClsMethod) superMethod).getOrigin() : superMethod; + if (ArrayUtilRt.find(ignore, relevantElement) < 0 && !MethodSignatureUtil.isSuperMethod(originalMethod, superMethod)) { + return true; + } + } + return false; + } + + + private static String wrapOrSkip(String s, boolean inCode) { + return inCode ? "" + s + "" : s; + } + + private static String formatClass(DeclarationDescriptor classDescriptor, BindingContext bindingContext, boolean inCode) { + PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, classDescriptor); + if (element instanceof PsiClass) { + return formatPsiClass((PsiClass) element, false, inCode); + } + + return wrapOrSkip(formatClassDescriptor(classDescriptor), inCode); + } + + private static String formatFunction(DeclarationDescriptor functionDescriptor, BindingContext bindingContext, boolean inCode) { + PsiElement element = BindingContextUtils.descriptorToDeclaration(bindingContext, functionDescriptor); + if (element instanceof PsiMethod) { + return formatPsiMethod((PsiMethod) element, false, inCode); + } + + return wrapOrSkip(formatFunctionDescriptor(functionDescriptor), inCode); + } + + private static String formatClassDescriptor(DeclarationDescriptor classDescriptor) { + return DescriptorRenderer.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(classDescriptor); + } + + private static String formatFunctionDescriptor(DeclarationDescriptor functionDescriptor) { + return DescriptorRenderer.COMPACT.render(functionDescriptor); + } + + public static String formatPsiClass(PsiClass psiClass, boolean markAsJava, boolean inCode) { + String description; + + String kind = psiClass.isInterface() ? "interface " : "class "; + description = kind + PsiFormatUtil.formatClass( + psiClass, + PsiFormatUtilBase.SHOW_CONTAINING_CLASS + | PsiFormatUtilBase.SHOW_NAME + | PsiFormatUtilBase.SHOW_PARAMETERS + | PsiFormatUtilBase.SHOW_TYPE + ); + description = wrapOrSkip(description, inCode); + + return markAsJava ? "[Java] " + description : description; + } + + public static String formatPsiMethod(PsiMethod psiMethod, boolean showContainingClass, boolean inCode) { + int options = PsiFormatUtilBase.SHOW_NAME | PsiFormatUtilBase.SHOW_PARAMETERS | PsiFormatUtilBase.SHOW_TYPE; + if (showContainingClass) { + options |= PsiFormatUtilBase.SHOW_CONTAINING_CLASS; + } + + String description = PsiFormatUtil.formatMethod(psiMethod, PsiSubstitutor.EMPTY, options, PsiFormatUtilBase.SHOW_TYPE); + description = wrapOrSkip(description, inCode); + + return "[Java] " + description; + } + + @Override + public Collection findConflicts(PsiElement element, PsiElement[] allElementsToDelete) { + if (element instanceof JetNamedFunction) { + 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 FunctionDescriptor)) return null; + + List messages = new ArrayList(); + FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; + for (FunctionDescriptor overridenDescriptor : functionDescriptor.getOverriddenDescriptors()) { + if (overridenDescriptor.getModality() == Modality.ABSTRACT) { + String message = JetBundle.message( + "x.implements.y", + formatFunction(functionDescriptor, bindingContext, true), + formatClass(functionDescriptor.getContainingDeclaration(), bindingContext, true), + formatFunction(overridenDescriptor, bindingContext, true), + 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(Project project, UsageInfo[] usages) { - return usages; + ArrayList result = new ArrayList(); + ArrayList overridingMethodUsages = new ArrayList(); + + for (UsageInfo usage : usages) { + if (usage instanceof KotlinSafeDeleteOverridingMethodUsageInfo) { + overridingMethodUsages.add(usage); + } + else { + result.add(usage); + } + } + + if (!overridingMethodUsages.isEmpty()) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + result.addAll(overridingMethodUsages); + } + else { + KotlinOverridingMethodsDialog dialog = new KotlinOverridingMethodsDialog(project, overridingMethodUsages); + dialog.show(); + if (!dialog.isOK()) return null; + result.addAll(dialog.getSelected()); + } + } + + return result.toArray(new UsageInfo[result.size()]); + } + + private static void removeOverrideModifier(@NotNull PsiElement element) { + if (element instanceof JetNamedFunction) { + JetModifierList modifierList = ((JetNamedFunction) element).getModifierList(); + if (modifierList == null) return; + + PsiElement overrideModifier = modifierList.getModifier(JetTokens.OVERRIDE_KEYWORD); + if (overrideModifier != null) { + overrideModifier.delete(); + } + } + else if (element instanceof PsiMethod) { + PsiMethod method = (PsiMethod) element; + + PsiAnnotation overrideAnnotation = null; + for (PsiAnnotation annotation : method.getModifierList().getAnnotations()) { + if ("java.lang.Override".equals(annotation.getQualifiedName())) { + overrideAnnotation = annotation; + break; + } + } + + if (overrideAnnotation != null) { + overrideAnnotation.delete(); + } + } + } + + @Override + public void prepareForDeletion(PsiElement element) throws IncorrectOperationException { + if (element instanceof PsiMethod) { + cleanUpOverrides((PsiMethod) element); + } + else if (element instanceof JetNamedFunction) { + PsiMethod lightMethod = LightClassUtil.getLightClassMethod((JetNamedFunction) element); + if (lightMethod == null) { + return; + } + + cleanUpOverrides(lightMethod); + } + } + + private static void cleanUpOverrides(PsiMethod method) { + Collection superMethods = + SuperMethodsSearch.search(method, null, true, false).findAll(); + Collection overridingMethods = OverridingMethodsSearch.search(method, false).findAll(); + overrideLoop: for (PsiMethod overridingMethod : overridingMethods) { + PsiElement overridingElement = overridingMethod instanceof JetClsMethod + ? ((JetClsMethod) overridingMethod).getOrigin() + : overridingMethod; + Collection currentSuperMethods = + SuperMethodsSearch.search(overridingMethod, null, true, false).findAll(); + currentSuperMethods.addAll(superMethods); + for (MethodSignatureBackedByPsiMethod superMethod: currentSuperMethods) { + if (superMethod.getMethod() != method) continue overrideLoop; + } + + removeOverrideModifier(overridingElement); + } + } + + @Nullable + private static Collection checkSuperMethods( + @NotNull JetNamedFunction function, @Nullable Collection ignore + ) { + final BindingContext bindingContext = + AnalyzerFacadeWithCache.analyzeFileWithCache((JetFile) function.getContainingFile()).getBindingContext(); + + DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, function); + if (!(declarationDescriptor instanceof FunctionDescriptor)) return null; + + FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor; + Set overridenDescriptors = functionDescriptor.getOverriddenDescriptors(); + + Collection superMethods = ContainerUtil.map( + overridenDescriptors, + new Function() { + @Override + public PsiElement fun(FunctionDescriptor descriptor) { + return BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor); + } + } + ); + if (ignore != null) { + superMethods.removeAll(ignore); + } + + if (superMethods.isEmpty()) return Collections.singletonList(function); + + List superClasses = ContainerUtil.map( + superMethods, + new Function() { + @Override + public String fun(PsiElement element) { + String description; + + if (element instanceof JetNamedFunction) { + DeclarationDescriptor descriptor = + bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, element); + assert descriptor != null; + + DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration(); + assert containingDescriptor != null; + + description = formatClassDescriptor(containingDescriptor); + } + else { + assert element instanceof PsiMethod; + + PsiClass psiClass = ((PsiMethod) element).getContainingClass(); + assert psiClass != null; + + description = formatPsiClass(psiClass, true, false); + } + + return " " + description + "\n"; + } + } + ); + + 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()), + superClassesStr + ); + + int exitCode = Messages.showYesNoCancelDialog( + function.getProject(), message, IdeBundle.message("title.warning"), Messages.getQuestionIcon() + ); + switch (exitCode) { + case Messages.YES: + return superMethods; + case Messages.NO: + return Collections.singletonList(function); + default: + return Collections.emptyList(); + } + } + + @Nullable + @Override + public Collection getElementsToSearch( + PsiElement element, @Nullable Module module, Collection allElementsToDelete + ) { + if (ApplicationManager.getApplication().isUnitTestMode()) { + return Collections.singletonList(element); + } + + if (element instanceof JetNamedFunction) { + return checkSuperMethods((JetNamedFunction) element, allElementsToDelete); + } + return super.getElementsToSearch(element, module, allElementsToDelete); } @Override public Collection getAdditionalElementsToDelete( PsiElement element, Collection allElementsToDelete, boolean askUser ) { - if (element instanceof JetObjectDeclarationName && element.getParent() instanceof JetObjectDeclaration) { - return Arrays.asList(element.getParent()); + if (element instanceof JetObjectDeclarationName) { + return Arrays.asList(getObjectDeclarationOrFail(element)); } return super.getAdditionalElementsToDelete(element, allElementsToDelete, askUser); } diff --git a/idea/testData/safeDelete/deleteFunction/fun1.kt b/idea/testData/safeDelete/deleteFunction/fun1.kt new file mode 100644 index 00000000000..bd48ff9ec5a --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/fun1.kt @@ -0,0 +1,11 @@ +package test + +import test.foo + +fun foo() { + +} + +class B { + +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/fun1.kt.after b/idea/testData/safeDelete/deleteFunction/fun1.kt.after new file mode 100644 index 00000000000..191deddb2f8 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/fun1.kt.after @@ -0,0 +1,5 @@ +package test + +class B { + +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/fun2.kt b/idea/testData/safeDelete/deleteFunction/fun2.kt new file mode 100644 index 00000000000..8bd92224aa2 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/fun2.kt @@ -0,0 +1,11 @@ +package test + +import test.foo + +fun foo() { + +} + +class B { + val ref = ::foo +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/fun2.kt.messages b/idea/testData/safeDelete/deleteFunction/fun2.kt.messages new file mode 100644 index 00000000000..7d36bd30109 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/fun2.kt.messages @@ -0,0 +1,2 @@ +Function foo has 1 usage that is not safe to delete. +Of those 0 usages are in strings, comments, or non-code files. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/implement1.kt b/idea/testData/safeDelete/deleteFunction/implement1.kt new file mode 100644 index 00000000000..d682b537116 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/implement1.kt @@ -0,0 +1,9 @@ +trait A { + fun foo() +} + +class B: A { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/implement1.kt.messages b/idea/testData/safeDelete/deleteFunction/implement1.kt.messages new file mode 100644 index 00000000000..faf8f3ae2c0 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/implement1.kt.messages @@ -0,0 +1 @@ +fun foo(): jet.Unit in final class B : A implements fun foo(): jet.Unit in trait A. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/implement2.kt b/idea/testData/safeDelete/deleteFunction/implement2.kt new file mode 100644 index 00000000000..d45ab2c6785 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/implement2.kt @@ -0,0 +1,13 @@ +trait A { + 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/implement2.kt.messages b/idea/testData/safeDelete/deleteFunction/implement2.kt.messages new file mode 100644 index 00000000000..f1e89f82803 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/implement2.kt.messages @@ -0,0 +1,2 @@ +fun foo(): jet.Unit in final class B : A, Z implements fun foo(): jet.Unit in trait A. +fun foo(): jet.Unit in final class B : A, Z implements fun foo(): jet.Unit in trait Z. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/noUsages.kt b/idea/testData/safeDelete/deleteFunction/noUsages.kt new file mode 100644 index 00000000000..b05a392db1d --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/noUsages.kt @@ -0,0 +1,7 @@ +class C { + fun foo { + } +} + +class B { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/noUsages.kt.after b/idea/testData/safeDelete/deleteFunction/noUsages.kt.after new file mode 100644 index 00000000000..3f11a5b1fd3 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/noUsages.kt.after @@ -0,0 +1,5 @@ +class C { +} + +class B { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/override1.kt b/idea/testData/safeDelete/deleteFunction/override1.kt new file mode 100644 index 00000000000..73f238168cb --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/override1.kt @@ -0,0 +1,11 @@ +open class A { + open fun foo() { + + } +} + +class B: A { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/override1.kt.after b/idea/testData/safeDelete/deleteFunction/override1.kt.after new file mode 100644 index 00000000000..15c2912677e --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/override1.kt.after @@ -0,0 +1,8 @@ +open class A { + open fun foo() { + + } +} + +class B: A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/override2.kt b/idea/testData/safeDelete/deleteFunction/override2.kt new file mode 100644 index 00000000000..afdf4b91e97 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/override2.kt @@ -0,0 +1,11 @@ +open class A { + open fun foo() { + + } +} + +class B: A { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/override2.kt.after b/idea/testData/safeDelete/deleteFunction/override2.kt.after new file mode 100644 index 00000000000..4d87308c243 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/override2.kt.after @@ -0,0 +1,5 @@ +open class A { +} + +class B: A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/overrideAndImplement1.kt b/idea/testData/safeDelete/deleteFunction/overrideAndImplement1.kt new file mode 100644 index 00000000000..b11689d9a37 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/overrideAndImplement1.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/overrideAndImplement1.kt.messages b/idea/testData/safeDelete/deleteFunction/overrideAndImplement1.kt.messages new file mode 100644 index 00000000000..b1f9c85864b --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/overrideAndImplement1.kt.messages @@ -0,0 +1 @@ +fun foo(): jet.Unit in final class B : A, Z implements fun foo(): jet.Unit in trait Z. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/overrideAndImplement2.kt b/idea/testData/safeDelete/deleteFunction/overrideAndImplement2.kt new file mode 100644 index 00000000000..053782794d8 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/overrideAndImplement2.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/overrideAndImplement2.kt.after b/idea/testData/safeDelete/deleteFunction/overrideAndImplement2.kt.after new file mode 100644 index 00000000000..92575432fe6 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/overrideAndImplement2.kt.after @@ -0,0 +1,12 @@ +open class A { +} + +trait Z { + fun foo() +} + +class B: A, Z { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt b/idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt new file mode 100644 index 00000000000..50de3d0bfdb --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt @@ -0,0 +1,15 @@ +open class A { + open fun foo() { + + } +} + +class B: A { + fun bar() { + foo() + } + + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt.after b/idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt.after new file mode 100644 index 00000000000..7d6de4fbd2f --- /dev/null +++ b/idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt.after @@ -0,0 +1,12 @@ +open class A { +} + +class B: A { + fun bar() { + foo() + } + + fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.java new file mode 100644 index 00000000000..9d1504fe3b6 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.java @@ -0,0 +1,3 @@ +interface A { + void foo(); +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt new file mode 100644 index 00000000000..a76fc973489 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt @@ -0,0 +1,5 @@ +class B: A { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt.messages b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt.messages new file mode 100644 index 00000000000..370cf8c5f42 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt.messages @@ -0,0 +1 @@ +fun foo(): jet.Unit in final class B : A implements [Java] void foo() in interface A. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.java new file mode 100644 index 00000000000..922ff12cbb2 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.java @@ -0,0 +1,5 @@ +class B implements A { + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.java.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.java.after new file mode 100644 index 00000000000..96506701c7c --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.java.after @@ -0,0 +1,2 @@ +class B implements A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt new file mode 100644 index 00000000000..f3a5a12bc65 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt @@ -0,0 +1,3 @@ +trait A { + fun foo() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt.after new file mode 100644 index 00000000000..670cabdb241 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt.after @@ -0,0 +1,2 @@ +trait A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.java new file mode 100644 index 00000000000..f39830b8fc1 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.java @@ -0,0 +1,7 @@ +interface A { + void foo(); +} + +interface Z { + void foo(); +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt new file mode 100644 index 00000000000..c6b6e0d3ee9 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt @@ -0,0 +1,5 @@ +class B: A, Z { + public override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt.messages b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt.messages new file mode 100644 index 00000000000..f6a48a49969 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt.messages @@ -0,0 +1,2 @@ +fun foo(): jet.Unit in final class B : A, Z implements [Java] void foo() in interface A. +fun foo(): jet.Unit in final class B : A, Z implements [Java] void foo() in interface Z. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.java new file mode 100644 index 00000000000..f8cba162620 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.java @@ -0,0 +1,5 @@ +class B implements A, Z { + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.java.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.java.after new file mode 100644 index 00000000000..f8cba162620 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.java.after @@ -0,0 +1,5 @@ +class B implements A, Z { + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt new file mode 100644 index 00000000000..3470b144414 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt @@ -0,0 +1,7 @@ +trait A { + fun foo() +} + +trait Z { + fun foo() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt.after new file mode 100644 index 00000000000..4b0d260090e --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt.after @@ -0,0 +1,6 @@ +trait A { +} + +trait Z { + fun foo() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.java new file mode 100644 index 00000000000..59ea3d006c7 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.java @@ -0,0 +1,5 @@ +class A { + void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.java.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.java.after new file mode 100644 index 00000000000..59ea3d006c7 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.java.after @@ -0,0 +1,5 @@ +class A { + void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt new file mode 100644 index 00000000000..a76fc973489 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt @@ -0,0 +1,5 @@ +class B: A { + override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt.after new file mode 100644 index 00000000000..994dc58cf69 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt.after @@ -0,0 +1,2 @@ +class B: A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.java new file mode 100644 index 00000000000..315ae36bf5a --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.java @@ -0,0 +1,6 @@ +class B extends A { + @Override + void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.java.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.java.after new file mode 100644 index 00000000000..99b93165680 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.java.after @@ -0,0 +1,2 @@ +class B extends A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt new file mode 100644 index 00000000000..f3d6421d400 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt @@ -0,0 +1,5 @@ +open class A { + open fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt.after new file mode 100644 index 00000000000..d80ee90d357 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt.after @@ -0,0 +1,2 @@ +open class A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.java new file mode 100644 index 00000000000..6647e4afa78 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.java @@ -0,0 +1,10 @@ +class B extends A { + void bar() { + foo(); + } + + @Override + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.java.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.java.after new file mode 100644 index 00000000000..774a6b0c204 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.java.after @@ -0,0 +1,9 @@ +class B extends A { + void bar() { + foo(); + } + + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt new file mode 100644 index 00000000000..f3d6421d400 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt @@ -0,0 +1,5 @@ +open class A { + open fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt.after new file mode 100644 index 00000000000..d80ee90d357 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt.after @@ -0,0 +1,2 @@ +open class A { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.java new file mode 100644 index 00000000000..780d713081d --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.java @@ -0,0 +1,9 @@ +class A { + public void foo() { + + } +} + +interface Z { + void foo(); +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt new file mode 100644 index 00000000000..c6b6e0d3ee9 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt @@ -0,0 +1,5 @@ +class B: A, Z { + public override fun foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt.messages b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt.messages new file mode 100644 index 00000000000..1f17b7e2ff5 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt.messages @@ -0,0 +1 @@ +fun foo(): jet.Unit in final class B : A, Z implements [Java] void foo() in interface Z. \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.java b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.java new file mode 100644 index 00000000000..8e3a7341f25 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.java @@ -0,0 +1,5 @@ +class B extends A implements Z { + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.java.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.java.after new file mode 100644 index 00000000000..8e3a7341f25 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.java.after @@ -0,0 +1,5 @@ +class B extends A implements Z { + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt new file mode 100644 index 00000000000..46b50ab2ac9 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt @@ -0,0 +1,9 @@ +class A { + public fun foo() { + + } +} + +trait Z { + fun foo() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt.after b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt.after new file mode 100644 index 00000000000..ce7ab3cebd7 --- /dev/null +++ b/idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt.after @@ -0,0 +1,6 @@ +class A { +} + +trait Z { + fun foo() +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.java b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.java new file mode 100644 index 00000000000..7ee62ca2e46 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.java @@ -0,0 +1,10 @@ +interface A { + public void foo(); +} + +abstract class C implements B { + @Override + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.java.after b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.java.after new file mode 100644 index 00000000000..e91065bc7be --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.java.after @@ -0,0 +1,5 @@ +interface A { +} + +abstract class C implements B { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt new file mode 100644 index 00000000000..4bde1062335 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt @@ -0,0 +1,11 @@ +trait B: A { + public override fun foo() { + throw UnsupportedOperationException() + } +} + +class D: C() { + public override fun foo() { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt.after b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt.after new file mode 100644 index 00000000000..d1fffa7e4b8 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt.after @@ -0,0 +1,5 @@ +trait B: A { +} + +class D: C() { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.java b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.java new file mode 100644 index 00000000000..88d0495e439 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.java @@ -0,0 +1,10 @@ +interface A { + public void foo(); +} + +abstract class C implements B { + @Override + public void foo() { + + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.java.after b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.java.after new file mode 100644 index 00000000000..525267c9118 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.java.after @@ -0,0 +1,6 @@ +interface A { + public void foo(); +} + +abstract class C implements B { +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt new file mode 100644 index 00000000000..4bde1062335 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt @@ -0,0 +1,11 @@ +trait B: A { + public override fun foo() { + throw UnsupportedOperationException() + } +} + +class D: C() { + public override fun foo() { + throw UnsupportedOperationException() + } +} \ No newline at end of file diff --git a/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt.after b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt.after new file mode 100644 index 00000000000..d208f64b7a7 --- /dev/null +++ b/idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt.after @@ -0,0 +1,8 @@ +trait B: A { + public override fun foo() { + throw UnsupportedOperationException() + } +} + +class D: C() { +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/jet/safeDelete/AbstractJetSafeDeleteTest.java b/idea/tests/org/jetbrains/jet/safeDelete/AbstractJetSafeDeleteTest.java index 0473afb8389..0ef86248851 100644 --- a/idea/tests/org/jetbrains/jet/safeDelete/AbstractJetSafeDeleteTest.java +++ b/idea/tests/org/jetbrains/jet/safeDelete/AbstractJetSafeDeleteTest.java @@ -16,44 +16,99 @@ package org.jetbrains.jet.safeDelete; -import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.LangDataKeys; +import com.intellij.codeInsight.TargetElementUtilBase; +import com.intellij.openapi.editor.Editor; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.CharsetToolkit; import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiMethod; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.refactoring.BaseRefactoringProcessor; import com.intellij.refactoring.safeDelete.SafeDeleteHandler; -import com.intellij.testFramework.LightCodeInsightTestCase; +import com.intellij.testFramework.LightProjectDescriptor; +import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.psi.JetClass; -import org.jetbrains.jet.lang.psi.JetElement; +import org.jetbrains.jet.lang.psi.JetNamedFunction; import org.jetbrains.jet.lang.psi.JetObjectDeclarationName; +import org.jetbrains.jet.plugin.JetLightProjectDescriptor; +import org.jetbrains.jet.plugin.PluginTestCaseBase; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.List; -public abstract class AbstractJetSafeDeleteTest extends LightCodeInsightTestCase { +public abstract class AbstractJetSafeDeleteTest extends LightCodeInsightFixtureTestCase { + @NotNull + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return JetLightProjectDescriptor.INSTANCE; + } + + @Override + public void setUp() throws Exception { + super.setUp(); + String pathBase = PluginTestCaseBase.getTestDataPathBase(); + myFixture.setTestDataPath(pathBase.substring(0, pathBase.lastIndexOf("/idea/testData"))); + } + public void doClassTest(@NotNull String path) throws Exception { - doTest(path, JetClass.class); + doTest(path, JetClass.class, false); } public void doObjectTest(@NotNull String path) throws Exception { - doTest(path, JetObjectDeclarationName.class); + doTest(path, JetObjectDeclarationName.class, false); } - private void doTest(@NotNull String path, @NotNull Class elementClass) throws Exception { - configureByFile(path); + public void doFunctionTest(@NotNull String path) throws Exception { + doTest(path, JetNamedFunction.class, false); + } - DataContext dataContext = getCurrentEditorDataContext(); - PsiElement element = PsiTreeUtil.getParentOfType(LangDataKeys.PSI_ELEMENT.getData(dataContext), elementClass, false); + public void doFunctionTestWithJava(@NotNull String path) throws Exception { + doTest(path, JetNamedFunction.class, true); + } + + public void doJavaMethodTest(@NotNull String path) throws Exception { + doTest(path, PsiMethod.class, true); + } + + private void doTest( + @NotNull String path, @NotNull Class elementClass, boolean withJava) throws Exception { + String[] filePaths; + if (withJava) { + filePaths = new String[]{path, path.endsWith(".java") ? path.replace(".java", ".kt") : path.replace(".kt", ".java")}; + } + else { + filePaths = new String[]{path}; + } + + Editor[] editors = new Editor[filePaths.length]; + int i = 0; + for (String filePath : filePaths) { + myFixture.configureByFile(filePath); + editors[i++] = myFixture.getEditor(); + } + + PsiElement elementAtCaret = null; + for (Editor editor : editors) { + elementAtCaret = TargetElementUtilBase.findTargetElement( + editor, TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED | TargetElementUtilBase.ELEMENT_NAME_ACCEPTED + ); + if (elementAtCaret != null) break; + } + + assertNotNull("Couldn't find element at caret position", elementAtCaret); + + T element = PsiTreeUtil.getParentOfType(elementAtCaret, elementClass, false); try { - new SafeDeleteHandler().invoke(getProject(), new PsiElement[] {element}, dataContext); - checkResultByFile(path + ".after"); + SafeDeleteHandler.invoke(getProject(), new PsiElement[] {element}, null, true, null); + for (int j = 0; j < filePaths.length; j++) { + String expectedText = FileUtil.loadFile(new File(filePaths[j] + ".after")); + assertEquals(StringUtil.convertLineSeparators(expectedText), editors[j].getDocument().getText()); + } } catch (BaseRefactoringProcessor.ConflictsInTestsException e) { List messages = new ArrayList(e.getMessages()); @@ -64,10 +119,4 @@ public abstract class AbstractJetSafeDeleteTest extends LightCodeInsightTestCase assertEquals(expectedMessage, StringUtil.join(messages, "\n")); } } - - @NotNull - @Override - protected String getTestDataPath() { - return ""; - } } diff --git a/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java b/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java index 6440a519560..78d2ffdb3e1 100644 --- a/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java +++ b/idea/tests/org/jetbrains/jet/safeDelete/JetSafeDeleteTestGenerated.java @@ -30,7 +30,7 @@ import org.jetbrains.jet.safeDelete.AbstractJetSafeDeleteTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") -@InnerTestClasses({JetSafeDeleteTestGenerated.DeleteClass.class, JetSafeDeleteTestGenerated.DeleteObject.class}) +@InnerTestClasses({JetSafeDeleteTestGenerated.DeleteClass.class, JetSafeDeleteTestGenerated.DeleteObject.class, JetSafeDeleteTestGenerated.DeleteFunction.class, JetSafeDeleteTestGenerated.DeleteFunctionWithJavaUsages.class, JetSafeDeleteTestGenerated.DeleteJavaMethod.class}) public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest { @TestMetadata("idea/testData/safeDelete/deleteClass") public static class DeleteClass extends AbstractJetSafeDeleteTest { @@ -118,10 +118,142 @@ public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest { } + @TestMetadata("idea/testData/safeDelete/deleteFunction") + public static class DeleteFunction extends AbstractJetSafeDeleteTest { + public void testAllFilesPresentInDeleteFunction() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/safeDelete/deleteFunction"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("fun1.kt") + public void testFun1() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/fun1.kt"); + } + + @TestMetadata("fun2.kt") + public void testFun2() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/fun2.kt"); + } + + @TestMetadata("implement1.kt") + public void testImplement1() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/implement1.kt"); + } + + @TestMetadata("implement2.kt") + public void testImplement2() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/implement2.kt"); + } + + @TestMetadata("noUsages.kt") + public void testNoUsages() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/noUsages.kt"); + } + + @TestMetadata("override1.kt") + public void testOverride1() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/override1.kt"); + } + + @TestMetadata("override2.kt") + public void testOverride2() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/override2.kt"); + } + + @TestMetadata("overrideAndImplement1.kt") + public void testOverrideAndImplement1() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/overrideAndImplement1.kt"); + } + + @TestMetadata("overrideAndImplement2.kt") + public void testOverrideAndImplement2() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/overrideAndImplement2.kt"); + } + + @TestMetadata("overrideWithUsages.kt") + public void testOverrideWithUsages() throws Exception { + doFunctionTest("idea/testData/safeDelete/deleteFunction/overrideWithUsages.kt"); + } + + } + + @TestMetadata("idea/testData/safeDelete/deleteFunctionWithJavaUsages") + public static class DeleteFunctionWithJavaUsages extends AbstractJetSafeDeleteTest { + public void testAllFilesPresentInDeleteFunctionWithJavaUsages() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/safeDelete/deleteFunctionWithJavaUsages"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("implement1.kt") + public void testImplement1() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement1.kt"); + } + + @TestMetadata("implement2.kt") + public void testImplement2() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement2.kt"); + } + + @TestMetadata("implement3.kt") + public void testImplement3() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement3.kt"); + } + + @TestMetadata("implement4.kt") + public void testImplement4() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/implement4.kt"); + } + + @TestMetadata("override1.kt") + public void testOverride1() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/override1.kt"); + } + + @TestMetadata("override2.kt") + public void testOverride2() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/override2.kt"); + } + + @TestMetadata("override3.kt") + public void testOverride3() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/override3.kt"); + } + + @TestMetadata("overrideAndImplement1.kt") + public void testOverrideAndImplement1() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement1.kt"); + } + + @TestMetadata("overrideAndImplement2.kt") + public void testOverrideAndImplement2() throws Exception { + doFunctionTestWithJava("idea/testData/safeDelete/deleteFunctionWithJavaUsages/overrideAndImplement2.kt"); + } + + } + + @TestMetadata("idea/testData/safeDelete/deleteJavaMethod") + public static class DeleteJavaMethod extends AbstractJetSafeDeleteTest { + public void testAllFilesPresentInDeleteJavaMethod() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("idea/testData/safeDelete/deleteJavaMethod"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("mixedHierarchy1.kt") + public void testMixedHierarchy1() throws Exception { + doJavaMethodTest("idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy1.kt"); + } + + @TestMetadata("mixedHierarchy2.kt") + public void testMixedHierarchy2() throws Exception { + doJavaMethodTest("idea/testData/safeDelete/deleteJavaMethod/mixedHierarchy2.kt"); + } + + } + public static Test suite() { TestSuite suite = new TestSuite("JetSafeDeleteTestGenerated"); suite.addTestSuite(DeleteClass.class); suite.addTestSuite(DeleteObject.class); + suite.addTestSuite(DeleteFunction.class); + suite.addTestSuite(DeleteFunctionWithJavaUsages.class); + suite.addTestSuite(DeleteJavaMethod.class); return suite; } }