FinishMarker: use the first movable value when mayNeedMarker is true (may generate shorter code)

This commit is contained in:
Tagir Valeev
2019-04-19 15:02:32 +07:00
parent 6a6fbb0232
commit 723c055455
5 changed files with 43 additions and 11 deletions
@@ -27,8 +27,8 @@ class ExitContext {
private final @NotNull PsiCodeBlock myBlock;
private final @NotNull String myReturnVariable;
private final @NotNull PsiElementFactory myFactory;
boolean myReturnVariableUsed = false;
final PsiExpression myReturnVariableDefaultValue;
private boolean myReturnVariableUsed = false;
private final PsiExpression myReturnVariableDefaultValue;
ExitContext(@NotNull PsiCodeBlock block, @NotNull PsiType returnType, @NotNull FinishMarker marker) {
myBlock = block;
@@ -147,7 +147,7 @@ public class FinishMarker {
if (nonTerminalReturnValues.size() == 1 && nonTerminalReturnValues.iterator().next() != NULL) {
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, nonTerminalReturns.iterator().next());
}
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, findBestExpression(terminalReturn, nonTerminalReturns));
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, findBestExpression(terminalReturn, nonTerminalReturns, mayNeedMarker));
}
if (PsiType.BOOLEAN.equals(returnType)) {
if (nonTerminalReturnValues.size() == 1) {
@@ -160,7 +160,7 @@ public class FinishMarker {
}
}
if (PsiType.INT.equals(returnType) || PsiType.LONG.equals(returnType)) {
return getMarkerForIntegral(nonTerminalReturns, terminalReturn, returnType, factory);
return getMarkerForIntegral(nonTerminalReturns, terminalReturn, mayNeedMarker, returnType, factory);
}
if (!(returnType instanceof PsiPrimitiveType)) {
if (StreamEx.of(nonTerminalReturns).map(ret -> NullabilityUtil.getExpressionNullability(ret, true))
@@ -174,11 +174,13 @@ public class FinishMarker {
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, value);
}
}
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, findBestExpression(terminalReturn, nonTerminalReturns));
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, findBestExpression(terminalReturn, nonTerminalReturns, mayNeedMarker));
}
@Nullable
private static PsiExpression findBestExpression(PsiReturnStatement terminalReturn, List<PsiExpression> nonTerminalReturns) {
private static PsiExpression findBestExpression(PsiReturnStatement terminalReturn,
List<PsiExpression> nonTerminalReturns,
boolean mayNeedMarker) {
List<PsiExpression> bestGroup = StreamEx.of(nonTerminalReturns)
.filter(FinishMarker::canMoveToStart)
.groupingBy(PsiExpression::getText, LinkedHashMap::new, Collectors.toList())
@@ -192,13 +194,16 @@ public class FinishMarker {
if (terminalReturn != null && canMoveToStart(terminalReturn.getReturnValue())) {
return terminalReturn.getReturnValue();
}
if (mayNeedMarker && !bestGroup.isEmpty()) {
return bestGroup.get(0);
}
return null;
}
@NotNull
private static FinishMarker getMarkerForIntegral(List<PsiExpression> nonTerminalReturns,
PsiReturnStatement terminalReturn,
PsiType returnType, PsiElementFactory factory) {
boolean mayNeedMarker, PsiType returnType, PsiElementFactory factory) {
boolean isLong = PsiType.LONG.equals(returnType);
LongRangeSet fullSet = requireNonNull(LongRangeSet.fromType(returnType));
LongRangeSet set = nonTerminalReturns.stream()
@@ -236,11 +241,11 @@ public class FinishMarker {
return new FinishMarker(FinishMarkerType.VALUE_NON_EQUAL, factory.createExpressionFromText(text, null));
}
}
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, findBestExpression(terminalReturn, nonTerminalReturns));
return new FinishMarker(FinishMarkerType.SEPARATE_VAR, findBestExpression(terminalReturn, nonTerminalReturns, mayNeedMarker));
}
@Contract("null -> false")
static boolean canMoveToStart(PsiExpression value) {
private static boolean canMoveToStart(PsiExpression value) {
if (!ExpressionUtils.isSafelyRecomputableExpression(value)) return false;
PsiReferenceExpression ref = tryCast(PsiUtil.skipParenthesizedExprDown(value), PsiReferenceExpression.class);
if (ref != null && !ref.isQualified()) {
@@ -1,13 +1,12 @@
// "Transform body to single exit-point form" "true"
class Test {
String test2(List<String> list, String foo, String bar) {
String result = null;
String result = foo;
boolean finished = false;
for (String s : list) {
for (int i = 0; i < 10; i++) {
bar = s;
if (s.length() == i) {
result = foo;
finished = true;
break;
}
@@ -0,0 +1,18 @@
// "Transform body to single exit-point form" "true"
class Test {
String test(int i) {
String result = null;
boolean finished = false;
if (i > 0) {
if (i == 10) {
finished = true;
} else {
System.out.println(i);
}
}
if (!finished) {
result = String.valueOf(i);
}
return result;
}
}
@@ -0,0 +1,10 @@
// "Transform body to single exit-point form" "true"
class Test {
String <caret>test(int i) {
if (i > 0) {
if (i == 10) return null;
System.out.println(i);
}
return String.valueOf(i);
}
}