mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-191690 Inline method: less restrictions on tail call
This commit is contained in:
@@ -17,7 +17,7 @@
|
||||
package com.intellij.refactoring.inline;
|
||||
|
||||
import com.intellij.codeInsight.TargetElementUtil;
|
||||
import com.intellij.lang.StdLanguages;
|
||||
import com.intellij.lang.java.JavaLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.vfs.ReadonlyStatusHandler;
|
||||
@@ -37,7 +37,7 @@ class InlineMethodHandler extends JavaInlineActionHandler {
|
||||
}
|
||||
|
||||
public boolean canInlineElement(PsiElement element) {
|
||||
return element instanceof PsiMethod && element.getNavigationElement() instanceof PsiMethod && element.getLanguage() == StdLanguages.JAVA;
|
||||
return element instanceof PsiMethod && element.getNavigationElement() instanceof PsiMethod && element.getLanguage() == JavaLanguage.INSTANCE;
|
||||
}
|
||||
|
||||
public void inlineElement(final Project project, Editor editor, PsiElement element) {
|
||||
@@ -61,7 +61,7 @@ class InlineMethodHandler extends JavaInlineActionHandler {
|
||||
PsiReference reference = editor != null ? TargetElementUtil.findReference(editor, editor.getCaretModel().getOffset()) : null;
|
||||
if (reference != null) {
|
||||
final PsiElement refElement = reference.getElement();
|
||||
if (refElement != null && !isEnabledForLanguage(refElement.getLanguage())) {
|
||||
if (!isEnabledForLanguage(refElement.getLanguage())) {
|
||||
String message = RefactoringBundle
|
||||
.message("refactoring.is.not.supported.for.language", "Inline of Java method", refElement.getLanguage().getDisplayName());
|
||||
CommonRefactoringUtil.showErrorHint(project, editor, message, REFACTORING_NAME, HelpID.INLINE_METHOD);
|
||||
|
||||
@@ -323,11 +323,18 @@ public class InlineUtil {
|
||||
return TailCallType.Return;
|
||||
}
|
||||
if (callParent instanceof PsiExpressionStatement) {
|
||||
PsiStatement callStatement = (PsiStatement)callParent;
|
||||
PsiMethod callerMethod = PsiTreeUtil.getParentOfType(callStatement, PsiMethod.class);
|
||||
if (callerMethod != null) {
|
||||
final PsiStatement[] psiStatements = callerMethod.getBody().getStatements();
|
||||
return psiStatements.length > 0 && callStatement == psiStatements [psiStatements.length-1] ? TailCallType.Simple : TailCallType.None;
|
||||
PsiStatement curElement = (PsiStatement)callParent;
|
||||
while (true) {
|
||||
if (PsiTreeUtil.getNextSiblingOfType(curElement, PsiStatement.class) != null) return TailCallType.None;
|
||||
PsiElement parent = curElement.getParent();
|
||||
if (parent instanceof PsiCodeBlock) {
|
||||
PsiElement blockParent = parent.getParent();
|
||||
if (blockParent instanceof PsiMethod || blockParent instanceof PsiLambdaExpression) return TailCallType.Simple;
|
||||
if (!(blockParent instanceof PsiBlockStatement)) return TailCallType.None;
|
||||
parent = blockParent.getParent();
|
||||
}
|
||||
if (!(parent instanceof PsiLabeledStatement) && !(parent instanceof PsiIfStatement)) return TailCallType.None;
|
||||
curElement = (PsiStatement)parent;
|
||||
}
|
||||
}
|
||||
return TailCallType.None;
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
class A {
|
||||
void foo() {
|
||||
if(Math.random() > 2) {
|
||||
System.out.println("xyz");
|
||||
return;
|
||||
}
|
||||
System.out.println("oops");
|
||||
}
|
||||
|
||||
void bar(int x) {
|
||||
if (x > 0) {
|
||||
f<caret>oo();
|
||||
}
|
||||
System.out.println("x < 0");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
class A {
|
||||
void foo() {
|
||||
if(Math.random() > 2) {
|
||||
System.out.println("xyz");
|
||||
return;
|
||||
}
|
||||
System.out.println("oops");
|
||||
}
|
||||
|
||||
void bar(int x) {
|
||||
if (x > 0) {
|
||||
f<caret>oo();
|
||||
} else {
|
||||
System.out.println("x < 0");
|
||||
}
|
||||
}
|
||||
|
||||
void baz(int x) {
|
||||
if (x > 0)
|
||||
if (x < 10) {
|
||||
foo();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
class A {
|
||||
|
||||
void bar(int x) {
|
||||
if (x > 0) {
|
||||
if(Math.random() > 2) {
|
||||
System.out.println("xyz");
|
||||
return;
|
||||
}
|
||||
System.out.println("oops");
|
||||
} else {
|
||||
System.out.println("x < 0");
|
||||
}
|
||||
}
|
||||
|
||||
void baz(int x) {
|
||||
if (x > 0)
|
||||
if (x < 10) {
|
||||
if(Math.random() > 2) {
|
||||
System.out.println("xyz");
|
||||
return;
|
||||
}
|
||||
System.out.println("oops");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
class A {
|
||||
void foo() {
|
||||
if(Math.random() > 2) {
|
||||
System.out.println("xyz");
|
||||
return;
|
||||
}
|
||||
System.out.println("oops");
|
||||
}
|
||||
|
||||
void bar(int x) {
|
||||
Runnable r = () -> {
|
||||
System.out.println("hi");
|
||||
f<caret>oo();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
class A {
|
||||
|
||||
void bar(int x) {
|
||||
Runnable r = () -> {
|
||||
System.out.println("hi");
|
||||
if(Math.random() > 2) {
|
||||
System.out.println("xyz");
|
||||
return;
|
||||
}
|
||||
System.out.println("oops");
|
||||
};
|
||||
}
|
||||
}
|
||||
+39
-14
@@ -407,20 +407,31 @@ public class InlineMethodTest extends LightRefactoringTestCase {
|
||||
doTestInlineThisOnly();
|
||||
}
|
||||
|
||||
public void testTailCallInsideIf() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTailCallInsideLambda() {
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testNotTailCallInsideIf() {
|
||||
doTestAssertBadReturn();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sdk getProjectJDK() {
|
||||
return getTestName(false).contains("Src") ? IdeaTestUtil.getMockJdk17() : super.getProjectJDK();
|
||||
}
|
||||
|
||||
private void doTestInlineThisOnly() {
|
||||
@NonNls String fileName = "/refactoring/inlineMethod/" + getTestName(false) + ".java";
|
||||
configureByFile(fileName);
|
||||
@NonNls String fileName = configure();
|
||||
performAction(new MockInlineMethodOptions(){
|
||||
@Override
|
||||
public boolean isInlineThisOnly() {
|
||||
return true;
|
||||
}
|
||||
}, false);
|
||||
}, false, false);
|
||||
checkResultByFile(fileName + ".after");
|
||||
}
|
||||
|
||||
@@ -429,18 +440,28 @@ public class InlineMethodTest extends LightRefactoringTestCase {
|
||||
}
|
||||
|
||||
private void doTest(final boolean nonCode) {
|
||||
String name = getTestName(false);
|
||||
@NonNls String fileName = "/refactoring/inlineMethod/" + name + ".java";
|
||||
configureByFile(fileName);
|
||||
@NonNls String fileName = configure();
|
||||
performAction(nonCode);
|
||||
checkResultByFile(fileName + ".after");
|
||||
}
|
||||
|
||||
private void performAction(final boolean nonCode) {
|
||||
performAction(new MockInlineMethodOptions(), nonCode);
|
||||
private void doTestAssertBadReturn() {
|
||||
@NonNls String fileName = configure();
|
||||
performAction(new MockInlineMethodOptions(), false, true);
|
||||
}
|
||||
|
||||
private void performAction(final InlineOptions options, final boolean nonCode) {
|
||||
@NotNull
|
||||
private String configure() {
|
||||
@NonNls String fileName = "/refactoring/inlineMethod/" + getTestName(false) + ".java";
|
||||
configureByFile(fileName);
|
||||
return fileName;
|
||||
}
|
||||
|
||||
private static void performAction(final boolean nonCode) {
|
||||
performAction(new MockInlineMethodOptions(), nonCode, false);
|
||||
}
|
||||
|
||||
private static void performAction(final InlineOptions options, final boolean nonCode, final boolean assertBadReturn) {
|
||||
PsiElement element = TargetElementUtil
|
||||
.findTargetElement(myEditor, TargetElementUtil.ELEMENT_NAME_ACCEPTED | TargetElementUtil.REFERENCED_ELEMENT_ACCEPTED);
|
||||
final PsiReference ref = myFile.findReferenceAt(myEditor.getCaretModel().getOffset());
|
||||
@@ -454,10 +475,14 @@ public class InlineMethodTest extends LightRefactoringTestCase {
|
||||
assertTrue(element instanceof PsiMethod);
|
||||
PsiMethod method = (PsiMethod)element.getNavigationElement();
|
||||
final boolean condition = InlineMethodProcessor.checkBadReturns(method) && !InlineUtil.allUsagesAreTailCalls(method);
|
||||
assertFalse("Bad returns found", condition);
|
||||
final InlineMethodProcessor processor =
|
||||
new InlineMethodProcessor(getProject(), method, refExpr, myEditor, options.isInlineThisOnly(), nonCode, nonCode,
|
||||
!options.isKeepTheDeclaration());
|
||||
processor.run();
|
||||
if (assertBadReturn) {
|
||||
assertTrue("Bad returns not found", condition);
|
||||
} else {
|
||||
assertFalse("Bad returns found", condition);
|
||||
final InlineMethodProcessor processor =
|
||||
new InlineMethodProcessor(getProject(), method, refExpr, myEditor, options.isInlineThisOnly(), nonCode, nonCode,
|
||||
!options.isKeepTheDeclaration());
|
||||
processor.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user