Implement "Safe Delete" refactoring for named functions

Conflicts:
	idea/src/org/jetbrains/jet/plugin/refactoring/safeDelete/KotlinSafeDeleteProcessor.java
This commit is contained in:
Alexey Sedunov
2013-07-12 18:18:46 +04:00
parent 6658564bdd
commit cd6b6e4934
71 changed files with 1442 additions and 43 deletions
@@ -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;
}
}
@@ -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")
);
}
+4 -1
View File
@@ -227,7 +227,10 @@
<elementDescriptionProvider implementation="org.jetbrains.jet.plugin.findUsages.JetElementDescriptionProvider"/>
<findUsagesHandlerFactory implementation="org.jetbrains.jet.plugin.findUsages.KotlinFindUsagesHandlerFactory"/>
<usageTypeProvider implementation="org.jetbrains.jet.plugin.findUsages.JetUsageTypeProvider"/>
<refactoring.safeDeleteProcessor implementation="org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinSafeDeleteProcessor" id="kotlinProcessor"/>
<refactoring.safeDeleteProcessor
id="kotlinProcessor"
implementation="org.jetbrains.jet.plugin.refactoring.safeDelete.KotlinSafeDeleteProcessor"
order="before javaProcessor"/>
<debugger.positionManagerFactory implementation="org.jetbrains.jet.plugin.debugger.JetPositionManagerFactory"/>
<codeInsight.implementMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler"/>
<codeInsight.overrideMethod language="jet" implementationClass="org.jetbrains.jet.plugin.codeInsight.OverrideMethodsHandler"/>
@@ -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
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
@@ -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
@@ -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<UsageInfo> 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<UsageInfo> 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<UsageInfo> getSelected() {
ArrayList<UsageInfo> result = new ArrayList<UsageInfo>();
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();
}
}
}
@@ -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();
}
}
}
@@ -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<UsageInfo> result
) {
List<UsageInfo> javaUsages = new ArrayList<UsageInfo>();
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 <T, C extends T> List<C> difference(Collection<C> from, T[] a) {
List<C> list = new ArrayList<C>(from);
list.removeAll(Arrays.asList(a));
return list;
}
protected static NonCodeUsageSearchInfo findFunctionUsages(
JetNamedFunction function,
final PsiElement[] allElementsToDelete,
List<UsageInfo> result
) {
PsiMethod lightMethod = LightClassUtil.getLightClassMethod(function);
if (lightMethod == null) {
return getDefaultNonCodeUsageSearchInfo(function, allElementsToDelete);
}
Collection<PsiReference> references = ReferencesSearch.search(function).findAll();
List<PsiMethod> 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<PsiMethod, Collection<PsiReference>> methodToReferences = new HashMap<PsiMethod, Collection<PsiReference>>();
for (PsiMethod overridingMethod : overridingMethods) {
Collection<PsiReference> overridingReferences =
ReferencesSearch.search(
overridingMethod instanceof JetClsMethod ? ((JetClsMethod) overridingMethod).getOrigin() : overridingMethod
).findAll();
methodToReferences.put(overridingMethod, overridingReferences);
}
final Set<PsiMethod> safeOverriding =
filterSafeOverridingMethods(lightMethod, references, overridingMethods, methodToReferences, result, allElementsToDelete);
return new NonCodeUsageSearchInfo(
new Condition<PsiElement>() {
@Override
public boolean value(PsiElement usage) {
if (usage instanceof JetFile) return false;
return isInside(usage, allElementsToDelete) || isInside(usage, safeOverriding);
}
},
function
);
}
/*
* Mostly copied from JavaSafeDeleteProcessor.validateOverridingMethods
* Revision: d4fc033
* (simplified and implemented proper treatment of light methods)
*/
private static Set<PsiMethod> filterSafeOverridingMethods(
PsiMethod originalMethod, Collection<PsiReference> originalReferences,
Collection<PsiMethod> overridingMethods, HashMap<PsiMethod, Collection<PsiReference>> methodToReferences,
List<UsageInfo> usages,
PsiElement[] allElementsToDelete
) {
Set<PsiMethod> validOverriding = new LinkedHashSet<PsiMethod>(overridingMethods);
boolean anyNewBadRefs;
do {
anyNewBadRefs = false;
for (PsiMethod overridingMethod : overridingMethods) {
if (validOverriding.contains(overridingMethod)) {
Collection<PsiReference> 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 ? "<code>" + s + "</code>" : 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<String> 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<String> messages = new ArrayList<String>();
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<UsageInfo> result = new ArrayList<UsageInfo>();
ArrayList<UsageInfo> overridingMethodUsages = new ArrayList<UsageInfo>();
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<MethodSignatureBackedByPsiMethod> superMethods =
SuperMethodsSearch.search(method, null, true, false).findAll();
Collection<PsiMethod> overridingMethods = OverridingMethodsSearch.search(method, false).findAll();
overrideLoop: for (PsiMethod overridingMethod : overridingMethods) {
PsiElement overridingElement = overridingMethod instanceof JetClsMethod
? ((JetClsMethod) overridingMethod).getOrigin()
: overridingMethod;
Collection<MethodSignatureBackedByPsiMethod> currentSuperMethods =
SuperMethodsSearch.search(overridingMethod, null, true, false).findAll();
currentSuperMethods.addAll(superMethods);
for (MethodSignatureBackedByPsiMethod superMethod: currentSuperMethods) {
if (superMethod.getMethod() != method) continue overrideLoop;
}
removeOverrideModifier(overridingElement);
}
}
@Nullable
private static Collection<? extends PsiElement> checkSuperMethods(
@NotNull JetNamedFunction function, @Nullable Collection<PsiElement> 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<? extends FunctionDescriptor> overridenDescriptors = functionDescriptor.getOverriddenDescriptors();
Collection<? extends PsiElement> superMethods = ContainerUtil.map(
overridenDescriptors,
new Function<FunctionDescriptor, PsiElement>() {
@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<String> superClasses = ContainerUtil.map(
superMethods,
new Function<PsiElement, String>() {
@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<? extends PsiElement> getElementsToSearch(
PsiElement element, @Nullable Module module, Collection<PsiElement> 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<PsiElement> getAdditionalElementsToDelete(
PsiElement element, Collection<PsiElement> 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);
}
@@ -0,0 +1,11 @@
package test
import test.foo
fun <caret>foo() {
}
class B {
}
@@ -0,0 +1,5 @@
package test
class B {
}
@@ -0,0 +1,11 @@
package test
import test.foo
fun <caret>foo() {
}
class B {
val ref = ::foo
}
@@ -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.
@@ -0,0 +1,9 @@
trait A {
fun foo()
}
class B: A {
override fun <caret>foo() {
}
}
@@ -0,0 +1 @@
fun foo(): jet.Unit in final class B : A implements fun foo(): jet.Unit in trait A.
@@ -0,0 +1,13 @@
trait A {
fun foo()
}
trait Z {
fun foo()
}
class B: A, Z {
override fun <caret>foo() {
}
}
@@ -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.
@@ -0,0 +1,7 @@
class C {
fun <caret>foo {
}
}
class B {
}
@@ -0,0 +1,5 @@
class C {
}
class B {
}
@@ -0,0 +1,11 @@
open class A {
open fun foo() {
}
}
class B: A {
override fun <caret>foo() {
}
}
@@ -0,0 +1,8 @@
open class A {
open fun foo() {
}
}
class B: A {
}
@@ -0,0 +1,11 @@
open class A {
open fun <caret>foo() {
}
}
class B: A {
override fun foo() {
}
}
@@ -0,0 +1,5 @@
open class A {
}
class B: A {
}
@@ -0,0 +1,15 @@
open class A {
open fun foo() {
}
}
trait Z {
fun foo()
}
class B: A, Z {
override fun <caret>foo() {
}
}
@@ -0,0 +1 @@
fun foo(): jet.Unit in final class B : A, Z implements fun foo(): jet.Unit in trait Z.
@@ -0,0 +1,15 @@
open class A {
open fun <caret>foo() {
}
}
trait Z {
fun foo()
}
class B: A, Z {
override fun foo() {
}
}
@@ -0,0 +1,12 @@
open class A {
}
trait Z {
fun foo()
}
class B: A, Z {
override fun foo() {
}
}
@@ -0,0 +1,15 @@
open class A {
open fun <caret>foo() {
}
}
class B: A {
fun bar() {
foo()
}
override fun foo() {
}
}
@@ -0,0 +1,12 @@
open class A {
}
class B: A {
fun bar() {
foo()
}
fun foo() {
}
}
@@ -0,0 +1,3 @@
interface A {
void foo();
}
@@ -0,0 +1,5 @@
class B: A {
override fun <caret>foo() {
}
}
@@ -0,0 +1 @@
fun foo(): jet.Unit in final class B : A implements [Java] void foo() in interface A.
@@ -0,0 +1,5 @@
class B implements A {
public void foo() {
}
}
@@ -0,0 +1,2 @@
class B implements A {
}
@@ -0,0 +1,3 @@
trait A {
fun <caret>foo()
}
@@ -0,0 +1,2 @@
trait A {
}
@@ -0,0 +1,7 @@
interface A {
void foo();
}
interface Z {
void foo();
}
@@ -0,0 +1,5 @@
class B: A, Z {
public override fun <caret>foo() {
}
}
@@ -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.
@@ -0,0 +1,5 @@
class B implements A, Z {
public void foo() {
}
}
@@ -0,0 +1,5 @@
class B implements A, Z {
public void foo() {
}
}
@@ -0,0 +1,7 @@
trait A {
fun <caret>foo()
}
trait Z {
fun foo()
}
@@ -0,0 +1,6 @@
trait A {
}
trait Z {
fun foo()
}
@@ -0,0 +1,5 @@
class A {
void foo() {
}
}
@@ -0,0 +1,5 @@
class A {
void foo() {
}
}
@@ -0,0 +1,5 @@
class B: A {
override fun <caret>foo() {
}
}
@@ -0,0 +1,2 @@
class B: A {
}
@@ -0,0 +1,6 @@
class B extends A {
@Override
void foo() {
}
}
@@ -0,0 +1,2 @@
class B extends A {
}
@@ -0,0 +1,5 @@
open class A {
open fun <caret>foo() {
}
}
@@ -0,0 +1,2 @@
open class A {
}
@@ -0,0 +1,10 @@
class B extends A {
void bar() {
foo();
}
@Override
public void foo() {
}
}
@@ -0,0 +1,9 @@
class B extends A {
void bar() {
foo();
}
public void foo() {
}
}
@@ -0,0 +1,5 @@
open class A {
open fun <caret>foo() {
}
}
@@ -0,0 +1,2 @@
open class A {
}
@@ -0,0 +1,9 @@
class A {
public void foo() {
}
}
interface Z {
void foo();
}
@@ -0,0 +1,5 @@
class B: A, Z {
public override fun <caret>foo() {
}
}
@@ -0,0 +1 @@
fun foo(): jet.Unit in final class B : A, Z implements [Java] void foo() in interface Z.
@@ -0,0 +1,5 @@
class B extends A implements Z {
public void foo() {
}
}
@@ -0,0 +1,5 @@
class B extends A implements Z {
public void foo() {
}
}
@@ -0,0 +1,9 @@
class A {
public fun <caret>foo() {
}
}
trait Z {
fun foo()
}
@@ -0,0 +1,6 @@
class A {
}
trait Z {
fun foo()
}
@@ -0,0 +1,10 @@
interface A {
public void <caret>foo();
}
abstract class C implements B {
@Override
public void foo() {
}
}
@@ -0,0 +1,5 @@
interface A {
}
abstract class C implements B {
}
@@ -0,0 +1,11 @@
trait B: A {
public override fun foo() {
throw UnsupportedOperationException()
}
}
class D: C() {
public override fun foo() {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,5 @@
trait B: A {
}
class D: C() {
}
@@ -0,0 +1,10 @@
interface A {
public void foo();
}
abstract class C implements B {
@Override
public void <caret>foo() {
}
}
@@ -0,0 +1,6 @@
interface A {
public void foo();
}
abstract class C implements B {
}
@@ -0,0 +1,11 @@
trait B: A {
public override fun foo() {
throw UnsupportedOperationException()
}
}
class D: C() {
public override fun foo() {
throw UnsupportedOperationException()
}
}
@@ -0,0 +1,8 @@
trait B: A {
public override fun foo() {
throw UnsupportedOperationException()
}
}
class D: C() {
}
@@ -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 <T extends JetElement> void doTest(@NotNull String path, @NotNull Class<T> 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 <T extends PsiElement> void doTest(
@NotNull String path, @NotNull Class<T> 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<String> messages = new ArrayList<String>(e.getMessages());
@@ -64,10 +119,4 @@ public abstract class AbstractJetSafeDeleteTest extends LightCodeInsightTestCase
assertEquals(expectedMessage, StringUtil.join(messages, "\n"));
}
}
@NotNull
@Override
protected String getTestDataPath() {
return "";
}
}
@@ -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;
}
}