extract method: allow to extract from fragment with different exit points which all are @NotNull

This commit is contained in:
Anna Kozlova
2014-12-03 17:26:32 +01:00
parent 540d9744e5
commit c460d82d7c
5 changed files with 71 additions and 19 deletions
@@ -106,8 +106,8 @@ public class ControlFlowWrapper {
}
if (myExitPoints.size() != 1) {
areExitStatementsTheSame();
myGenerateConditionalExit = true;
areExitStatementsTheSame();
}
return myExitStatements;
}
@@ -241,8 +241,11 @@ public class ExtractMethodProcessor implements MatchProvider {
}
catch (ControlFlowWrapper.ExitStatementsNotSameException e) {
myExitStatements = myControlFlowWrapper.getExitStatements();
showMultipleExitPointsMessage();
return false;
myNotNullConditionalCheck = areAllExitPointsAreNotNull(getExpectedReturnType());
if (!myNotNullConditionalCheck) {
showMultipleExitPointsMessage();
return false;
}
}
myOutputVariables = myControlFlowWrapper.getOutputVariables();
@@ -265,11 +268,7 @@ public class ExtractMethodProcessor implements MatchProvider {
}
myHasExpressionOutput = expressionType != PsiType.VOID;
final PsiType returnStatementType = myCodeFragmentMember instanceof PsiMethod
? ((PsiMethod)myCodeFragmentMember).getReturnType()
: myCodeFragmentMember instanceof PsiLambdaExpression
? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
: null;
final PsiType returnStatementType = getExpectedReturnType();
myHasReturnStatementOutput = myHasReturnStatement && returnStatementType != null && returnStatementType != PsiType.VOID;
if (myGenerateConditionalExit && myOutputVariables.length == 1) {
@@ -284,15 +283,7 @@ public class ExtractMethodProcessor implements MatchProvider {
myNullConditionalCheck &= isNullInferred(myOutputVariables[0].getName(), false);
}
if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
myNotNullConditionalCheck = returnStatementType != null && returnStatementType != PsiType.VOID;
for (PsiStatement statement : myExitStatements) {
if (statement instanceof PsiReturnStatement) {
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
myNotNullConditionalCheck &= returnValue != null && !isNullInferred(returnValue.getText(), true);
}
}
}
myNotNullConditionalCheck = areAllExitPointsAreNotNull(returnStatementType);
}
if (!myHasReturnStatementOutput && checkOutputVariablesCount() && !myNullConditionalCheck && !myNotNullConditionalCheck) {
@@ -342,6 +333,28 @@ public class ExtractMethodProcessor implements MatchProvider {
return true;
}
private PsiType getExpectedReturnType() {
return myCodeFragmentMember instanceof PsiMethod
? ((PsiMethod)myCodeFragmentMember).getReturnType()
: myCodeFragmentMember instanceof PsiLambdaExpression
? LambdaUtil.getFunctionalInterfaceReturnType((PsiLambdaExpression)myCodeFragmentMember)
: null;
}
private boolean areAllExitPointsAreNotNull(PsiType returnStatementType) {
if (insertNotNullCheckIfPossible() && myControlFlowWrapper.getOutputVariables(false).length == 0) {
boolean isNotNull = returnStatementType != null && returnStatementType != PsiType.VOID;
for (PsiStatement statement : myExitStatements) {
if (statement instanceof PsiReturnStatement) {
final PsiExpression returnValue = ((PsiReturnStatement)statement).getReturnValue();
isNotNull &= returnValue != null && !isNullInferred(returnValue.getText(), true);
}
}
return isNotNull;
}
return false;
}
protected boolean insertNotNullCheckIfPossible() {
return true;
}
@@ -796,7 +809,7 @@ public class ExtractMethodProcessor implements MatchProvider {
CodeStyleManager.getInstance(myProject).reformat(ifStatement);
}
else if (myNotNullConditionalCheck) {
String varName = myOutputVariable.getName();
String varName = myOutputVariable != null ? myOutputVariable.getName() : "x";
varName = declareVariableAtMethodCallLocation(varName, myReturnType instanceof PsiPrimitiveType ? ((PsiPrimitiveType)myReturnType).getBoxedType(myCodeFragmentMember) : myReturnType);
addToMethodCallLocation(myElementFactory.createStatementFromText("if (" + varName + " != null) return " + varName + ";", null));
}
@@ -1021,7 +1034,9 @@ public class ExtractMethodProcessor implements MatchProvider {
statement = (PsiDeclarationStatement)addToMethodCallLocation(statement);
PsiVariable var = (PsiVariable)statement.getDeclaredElements()[0];
myMethodCall = (PsiMethodCallExpression)var.getInitializer();
var.getModifierList().replace(myOutputVariable.getModifierList());
if (myOutputVariable != null) {
var.getModifierList().replace(myOutputVariable.getModifierList());
}
return name;
}
@@ -0,0 +1,12 @@
class Test {
Integer method() {
<selection>try {
if(cond1) return 0;
else if(cond2) return null;
System.out.println("Text");
} finally {
doSomething();
}</selection>
return 12;
}
}
@@ -0,0 +1,21 @@
import org.jetbrains.annotations.Nullable;
class Test {
int method() {
Integer x = newMethod();
if (x != null) return x;
return 12;
}
@Nullable
private Integer newMethod() {
try {
if(cond1) return 0;
else if(cond2) return 1;
System.out.println("Text");
} finally {
doSomething();
}
return null;
}
}
@@ -58,6 +58,10 @@ public class ExtractMethodTest extends LightCodeInsightTestCase {
}
public void testExitPoints4() throws Exception {
doTest();
}
public void testExitPoints4Nullable() throws Exception {
doExitPointsTest(false);
}