mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Inline inner: check when possible to inline this ref only (IDEA-39274)
This commit is contained in:
+5
-9
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package com.intellij.refactoring.inline;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.help.HelpManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiCall;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.util.PsiFormatUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.JavaRefactoringSettings;
|
||||
import com.intellij.refactoring.HelpID;
|
||||
import com.intellij.refactoring.JavaRefactoringSettings;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
@@ -36,11 +36,11 @@ public class InlineToAnonymousClassDialog extends InlineOptionsDialog {
|
||||
private JCheckBox myCbSearchInComments;
|
||||
private JCheckBox myCbSearchTextOccurences;
|
||||
|
||||
protected InlineToAnonymousClassDialog(Project project, PsiClass psiClass, final PsiCall callToInline) {
|
||||
protected InlineToAnonymousClassDialog(Project project, PsiClass psiClass, final PsiCall callToInline, boolean isInvokeOnReference) {
|
||||
super(project, true, psiClass);
|
||||
myClass = psiClass;
|
||||
myCallToInline = callToInline;
|
||||
myInvokedOnReference = (myCallToInline != null);
|
||||
myInvokedOnReference = isInvokeOnReference;
|
||||
setTitle(RefactoringBundle.message("inline.to.anonymous.refactoring"));
|
||||
init();
|
||||
}
|
||||
@@ -69,10 +69,6 @@ public class InlineToAnonymousClassDialog extends InlineOptionsDialog {
|
||||
protected JComponent createCenterPanel() {
|
||||
JComponent optionsPanel = super.createCenterPanel();
|
||||
|
||||
// TODO[yole]: make visible again when "inline this" option is fixed (IDEADEV-17928)
|
||||
myOptionsPanel.setVisible(false);
|
||||
myRbInlineAll.setSelected(true);
|
||||
|
||||
JPanel panel = new JPanel();
|
||||
panel.setLayout(new GridBagLayout());
|
||||
GridBagConstraints gbc = new GridBagConstraints();
|
||||
|
||||
+56
-2
@@ -24,9 +24,11 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.search.searches.ClassInheritorsSearch;
|
||||
import com.intellij.psi.search.searches.ReferencesSearch;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.refactoring.util.CommonRefactoringUtil;
|
||||
import com.intellij.refactoring.util.RefactoringUtil;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Processor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -62,16 +64,68 @@ public class InlineToAnonymousClassHandler extends JavaInlineActionHandler {
|
||||
final PsiClass psiClass = psiElement instanceof PsiMethod ? ((PsiMethod) psiElement).getContainingClass() : (PsiClass) psiElement;
|
||||
PsiCall callToInline = findCallToInline(editor);
|
||||
|
||||
final PsiClassType superType = InlineToAnonymousClassProcessor.getSuperType(psiClass);
|
||||
if (superType == null) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, "java.lang.Object is not found", RefactoringBundle.message("inline.to.anonymous.refactoring"), null);
|
||||
return;
|
||||
}
|
||||
|
||||
String errorMessage = getCannotInlineMessage(psiClass);
|
||||
if (errorMessage != null) {
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, errorMessage, RefactoringBundle.message("inline.to.anonymous.refactoring"), null);
|
||||
return;
|
||||
}
|
||||
|
||||
InlineToAnonymousClassDialog dlg = new InlineToAnonymousClassDialog(project, psiClass, callToInline);
|
||||
dlg.show();
|
||||
new InlineToAnonymousClassDialog(project, psiClass, callToInline, canBeInvokedOnReference(callToInline, superType)).show();
|
||||
}
|
||||
|
||||
public static boolean canBeInvokedOnReference(PsiCall callToInline, PsiType superType) {
|
||||
if (callToInline != null) {
|
||||
final PsiElement parent = callToInline.getParent();
|
||||
if (parent instanceof PsiExpressionStatement || parent instanceof PsiSynchronizedStatement) {
|
||||
return true;
|
||||
}
|
||||
else if (parent instanceof PsiReferenceExpression) {
|
||||
return true;
|
||||
}
|
||||
else if (parent instanceof PsiExpressionList) {
|
||||
final PsiMethodCallExpression methodCallExpression = PsiTreeUtil.getParentOfType(parent, PsiMethodCallExpression.class);
|
||||
if (methodCallExpression != null) {
|
||||
int paramIdx = ArrayUtil.find(methodCallExpression.getArgumentList().getExpressions(), callToInline);
|
||||
if (paramIdx != -1) {
|
||||
final JavaResolveResult resolveResult = methodCallExpression.resolveMethodGenerics();
|
||||
final PsiElement resolvedMethod = resolveResult.getElement();
|
||||
if (resolvedMethod instanceof PsiMethod) {
|
||||
PsiType paramType;
|
||||
final PsiParameter[] parameters = ((PsiMethod)resolvedMethod).getParameterList().getParameters();
|
||||
if (paramIdx >= parameters.length) {
|
||||
final PsiParameter varargParameter = parameters[parameters.length - 1];
|
||||
paramType = varargParameter.getType();
|
||||
}
|
||||
else {
|
||||
paramType = parameters[paramIdx].getType();
|
||||
}
|
||||
if (paramType instanceof PsiEllipsisType) {
|
||||
paramType = ((PsiEllipsisType)paramType).getComponentType();
|
||||
}
|
||||
paramType = resolveResult.getSubstitutor().substitute(paramType);
|
||||
|
||||
final PsiJavaCodeReferenceElement classReference = ((PsiNewExpression)callToInline).getClassOrAnonymousClassReference();
|
||||
if (classReference != null) {
|
||||
superType = classReference.advancedResolve(false).getSubstitutor().substitute(superType);
|
||||
if (TypeConversionUtil.isAssignable(paramType, superType)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public static PsiCall findCallToInline(final Editor editor) {
|
||||
PsiCall callToInline = null;
|
||||
|
||||
+12
-7
@@ -168,8 +168,8 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
|
||||
}
|
||||
|
||||
protected void performRefactoring(UsageInfo[] usages) {
|
||||
PsiClassType superType = getSuperType();
|
||||
|
||||
final PsiClassType superType = getSuperType(myClass);
|
||||
LOG.assertTrue(superType != null);
|
||||
List<PsiElement> elementsToDelete = new ArrayList<PsiElement>();
|
||||
List<PsiNewExpression> newExpressions = new ArrayList<PsiNewExpression>();
|
||||
for(UsageInfo info: usages) {
|
||||
@@ -249,22 +249,27 @@ public class InlineToAnonymousClassProcessor extends BaseRefactoringProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
private PsiClassType getSuperType() {
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(myClass.getProject()).getElementFactory();
|
||||
@Nullable
|
||||
public static PsiClassType getSuperType(final PsiClass aClass) {
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(aClass.getProject()).getElementFactory();
|
||||
|
||||
PsiClassType superType;
|
||||
PsiClass superClass = myClass.getSuperClass();
|
||||
PsiClassType[] interfaceTypes = myClass.getImplementsListTypes();
|
||||
PsiClass superClass = aClass.getSuperClass();
|
||||
PsiClassType[] interfaceTypes = aClass.getImplementsListTypes();
|
||||
if (interfaceTypes.length > 0 && !InlineToAnonymousClassHandler.isRedundantImplements(superClass, interfaceTypes [0])) {
|
||||
assert interfaceTypes.length == 1;
|
||||
superType = interfaceTypes [0];
|
||||
}
|
||||
else {
|
||||
PsiClassType[] classTypes = myClass.getExtendsListTypes();
|
||||
PsiClassType[] classTypes = aClass.getExtendsListTypes();
|
||||
if (classTypes.length > 0) {
|
||||
superType = classTypes [0];
|
||||
}
|
||||
else {
|
||||
if (superClass == null) {
|
||||
//java.lang.Object was not found
|
||||
return null;
|
||||
}
|
||||
superType = factory.createType(superClass);
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public class Simple {}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
String s = new Si<caret>mple().toString();
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
public class Simple implements Runnable {
|
||||
public void run(){}
|
||||
}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
bar(new Si<caret>mple());
|
||||
}
|
||||
|
||||
void bar(Runnable r){}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
public class Simple<T> implements Comparable<T> {
|
||||
public int compareTo(T o){}
|
||||
}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
bar(new Si<caret>mple<String>());
|
||||
}
|
||||
|
||||
void bar(Comparable<String>... r){}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
public class Simple<T> implements Comparable<T> {
|
||||
public int compareTo(T o){}
|
||||
}
|
||||
|
||||
class Usage<S> {
|
||||
void foo() {
|
||||
bar(new Si<caret>mple<S>());
|
||||
}
|
||||
|
||||
void bar(Comparable<S>... r){}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
public class Simple {}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
synchronized (new Si<caret>mple()) {
|
||||
//dosmth
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
public class Simple implements Runnable {
|
||||
public void run(){}
|
||||
}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
bar(new Si<caret>mple());
|
||||
}
|
||||
|
||||
void bar(Runnable... r){}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public class Simple {}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
Simple s = new Si<caret>mple();
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
public class Simple implements Runnable {
|
||||
public void run(){}
|
||||
}
|
||||
|
||||
class Usage {
|
||||
void foo() {
|
||||
bar(new Si<caret>mple());
|
||||
}
|
||||
|
||||
void bar(Simple s){}
|
||||
}
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
public class Simple {}
|
||||
|
||||
class Usage {
|
||||
Simple foo() {
|
||||
return new Si<caret>mple();
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import java.lang.Exception;
|
||||
|
||||
public class Simple extends Exception{}
|
||||
|
||||
class Usage {
|
||||
void foo() throws Simple {
|
||||
throw new Si<caret>mple();
|
||||
}
|
||||
}
|
||||
+53
@@ -6,6 +6,7 @@ import com.intellij.openapi.projectRoots.Sdk;
|
||||
import com.intellij.openapi.projectRoots.impl.JavaSdkImpl;
|
||||
import com.intellij.psi.PsiCall;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.PsiClassType;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.testFramework.LightCodeInsightTestCase;
|
||||
import com.intellij.usageView.UsageInfo;
|
||||
@@ -377,4 +378,56 @@ public class InlineToAnonymousClassTest extends LightCodeInsightTestCase {
|
||||
assertEquals(0, conflicts.size());
|
||||
processor.run();
|
||||
}
|
||||
|
||||
public void testCanBeInvokedOnReference() throws Exception {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCanBeInvokedOnReference1() throws Exception {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCanBeInvokedOnReferenceSubstitution() throws Exception {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCanBeInvokedOnReferenceSubstitution1() throws Exception {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCanBeInvokedOnReferenceVarargs() throws Exception {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCantBeInvokedOnReference() throws Exception {
|
||||
doTestCanBeInvokedOnReference(false);
|
||||
}
|
||||
|
||||
public void testCantBeInvokedOnReference1() throws Exception {
|
||||
doTestCanBeInvokedOnReference(false);
|
||||
}
|
||||
|
||||
public void testCantBeInvokedOnReferenceReturnStatement() throws Exception {
|
||||
doTestCanBeInvokedOnReference(false);
|
||||
}
|
||||
|
||||
public void testCanBeInvokedOnReferenceSyncStatement() throws Exception {
|
||||
doTestCanBeInvokedOnReference(true);
|
||||
}
|
||||
|
||||
public void testCantBeInvokedOnReferenceThrowStatement() throws Exception {
|
||||
doTestCanBeInvokedOnReference(false);
|
||||
}
|
||||
|
||||
private void doTestCanBeInvokedOnReference(boolean canBeInvokedOnReference) throws Exception {
|
||||
configureByFile("/refactoring/inlineToAnonymousClass/" + getTestName(false) + ".java");
|
||||
PsiElement element = TargetElementUtilBase
|
||||
.findTargetElement(myEditor, TargetElementUtilBase.ELEMENT_NAME_ACCEPTED | TargetElementUtilBase.REFERENCED_ELEMENT_ACCEPTED);
|
||||
PsiCall callToInline = InlineToAnonymousClassHandler.findCallToInline(myEditor);
|
||||
PsiClass classToInline = (PsiClass) element;
|
||||
assertEquals(null, InlineToAnonymousClassHandler.getCannotInlineMessage(classToInline));
|
||||
final PsiClassType superType = InlineToAnonymousClassProcessor.getSuperType(classToInline);
|
||||
assertTrue(superType != null);
|
||||
assertEquals(canBeInvokedOnReference, InlineToAnonymousClassHandler.canBeInvokedOnReference(callToInline, superType));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user