StreamToLoop: reuse variable if possible when the stream is used in the declaration

This commit is contained in:
Tagir Valeev
2016-12-12 17:27:54 +07:00
parent 810445f21d
commit e87c551445
6 changed files with 85 additions and 61 deletions
@@ -326,7 +326,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
private final Set<String> myUsedNames;
private final Set<String> myUsedLabels;
private final List<String> myDeclarations = new ArrayList<>();
private PsiExpression myPlaceholder;
private PsiElement myPlaceholder;
private final PsiElementFactory myFactory;
private String myLabel;
private String myFinisher;
@@ -412,7 +412,22 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
myDeclarations.add(initStatement);
}
public String declareResult(String desiredName, String type, String initializer) {
public String declareResult(String desiredName, String type, String initializer, boolean finalResult) {
if(finalResult && myPlaceholder.getParent() instanceof PsiVariable) {
PsiVariable var = (PsiVariable)myPlaceholder.getParent();
if(var.getType().equalsToText(type) && var.getParent() instanceof PsiDeclarationStatement) {
PsiDeclarationStatement declaration = (PsiDeclarationStatement)var.getParent();
if(declaration.getDeclaredElements().length == 1) {
myPlaceholder = declaration;
PsiVariable copy = (PsiVariable)var.copy();
PsiExpression oldInitializer = copy.getInitializer();
LOG.assertTrue(oldInitializer != null);
oldInitializer.replace(createExpression(initializer));
myDeclarations.add(copy.getText());
return var.getName();
}
}
}
String name = registerVarName(Arrays.asList(desiredName, "result"));
myDeclarations.add(type + " " + name + " = " + initializer + ";");
if(myFinisher != null) {
@@ -424,7 +439,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
public PsiElement makeFinalReplacement() {
LOG.assertTrue(myPlaceholder != null);
if (myFinisher == null) {
if (myFinisher == null || myPlaceholder instanceof PsiStatement) {
myPlaceholder.delete();
return null;
}
@@ -450,7 +465,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
}
public String assignAndBreak(Condition condition) {
Predicate<PsiExpression> predicate = expr -> PsiUtil.skipParenthesizedExprUp(expr.getParent()) instanceof PsiReturnStatement;
Predicate<PsiElement> predicate = expr -> PsiUtil.skipParenthesizedExprUp(expr.getParent()) instanceof PsiReturnStatement;
if(condition instanceof Condition.Optional) {
condition = tryUnwrapOptional((Condition.Optional)condition, predicate);
}
@@ -461,26 +476,28 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
setFinisher(condition.getFalseBranch());
return "return "+condition.getTrueBranch()+";";
}
String found = declareResult(condition.getCondition(), condition.getType(), condition.getFalseBranch());
String found = declareResult(condition.getCondition(), condition.getType(), condition.getFalseBranch(), false);
return found + " = " +condition.getTrueBranch()+";\n" + getBreakStatement();
}
private Condition tryUnwrapBoolean(Condition.Boolean condition) {
PsiExpression negation = BoolUtils.findNegation(myPlaceholder);
if(negation != null) {
myPlaceholder = negation;
condition = condition.negate();
}
PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent());
if(parent instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)parent;
if(PsiTreeUtil.isAncestor(ternary.getCondition(), myPlaceholder, false)) {
myPlaceholder = ternary;
PsiType type = ternary.getType();
PsiExpression thenExpression = ternary.getThenExpression();
PsiExpression elseExpression = ternary.getElseExpression();
if (type != null && thenExpression != null && elseExpression != null) {
return condition.toPlain(type.getCanonicalText(), thenExpression.getText(), elseExpression.getText());
if (myPlaceholder instanceof PsiExpression) {
PsiExpression negation = BoolUtils.findNegation((PsiExpression)myPlaceholder);
if (negation != null) {
myPlaceholder = negation;
condition = condition.negate();
}
PsiElement parent = PsiUtil.skipParenthesizedExprUp(myPlaceholder.getParent());
if (parent instanceof PsiConditionalExpression) {
PsiConditionalExpression ternary = (PsiConditionalExpression)parent;
if (PsiTreeUtil.isAncestor(ternary.getCondition(), myPlaceholder, false)) {
myPlaceholder = ternary;
PsiType type = ternary.getType();
PsiExpression thenExpression = ternary.getThenExpression();
PsiExpression elseExpression = ternary.getElseExpression();
if (type != null && thenExpression != null && elseExpression != null) {
return condition.toPlain(type.getCanonicalText(), thenExpression.getText(), elseExpression.getText());
}
}
}
}
@@ -488,29 +505,32 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
}
@NotNull
private Condition tryUnwrapOptional(Condition.Optional condition, Predicate<PsiExpression> predicate) {
PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier(myPlaceholder);
if(call != null && !(call.getParent() instanceof PsiExpressionStatement)) {
String name = call.getMethodExpression().getReferenceName();
PsiExpression[] args = call.getArgumentList().getExpressions();
if(args.length == 0 && "isPresent".equals(name)) {
myPlaceholder = call;
return new Condition.Boolean(condition.getCondition(), false);
}
if(args.length == 1) {
String absentExpression = null;
if("orElse".equals(name)) {
absentExpression = args[0].getText();
} else if("orElseGet".equals(name) && predicate.test(call)) {
FunctionHelper helper = FunctionHelper.create(args[0], 0);
if(helper != null) {
helper.transform(this);
absentExpression = helper.getText();
}
}
if(absentExpression != null) {
private Condition tryUnwrapOptional(Condition.Optional condition, Predicate<PsiElement> predicate) {
if (myPlaceholder instanceof PsiExpression) {
PsiMethodCallExpression call = ExpressionUtils.getCallForQualifier((PsiExpression)myPlaceholder);
if (call != null && !(call.getParent() instanceof PsiExpressionStatement)) {
String name = call.getMethodExpression().getReferenceName();
PsiExpression[] args = call.getArgumentList().getExpressions();
if (args.length == 0 && "isPresent".equals(name)) {
myPlaceholder = call;
return condition.unwrap(absentExpression);
return new Condition.Boolean(condition.getCondition(), false);
}
if (args.length == 1) {
String absentExpression = null;
if ("orElse".equals(name)) {
absentExpression = args[0].getText();
}
else if ("orElseGet".equals(name) && predicate.test(call)) {
FunctionHelper helper = FunctionHelper.create(args[0], 0);
if (helper != null) {
helper.transform(this);
absentExpression = helper.getText();
}
}
if (absentExpression != null) {
myPlaceholder = call;
return condition.unwrap(absentExpression);
}
}
}
}
@@ -308,7 +308,7 @@ abstract class TerminalOperation extends Operation {
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
String accumulator = context.declareResult("acc", myType, myIdentity.getText());
String accumulator = context.declareResult("acc", myType, myIdentity.getText(), false);
myUpdater.transform(context, accumulator, inVar.getName());
return accumulator + "=" + myUpdater.getText() + ";";
}
@@ -331,7 +331,7 @@ abstract class TerminalOperation extends Operation {
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
String seen = context.declare("seen", "boolean", "false");
String accumulator = context.declareResult("acc", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null");
String accumulator = context.declareResult("acc", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null", false);
myUpdater.transform(context, accumulator, inVar.getName());
context.setFinisher(new Condition.Optional(myType, seen, accumulator));
String ifClause = "if(!" + seen + ") {\n" +
@@ -379,7 +379,7 @@ abstract class TerminalOperation extends Operation {
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
mySupplier.transform(context);
String candidate = mySupplier.suggestFinalOutputNames(context, myAccumulator.getParameterName(0), "acc").get(0);
String acc = context.declareResult(candidate, mySupplier.getResultType(), mySupplier.getText());
String acc = context.declareResult(candidate, mySupplier.getResultType(), mySupplier.getText(), true);
myAccumulator.transform(context, acc, inVar.getName());
return myAccumulator.getText()+";\n";
}
@@ -396,7 +396,7 @@ abstract class TerminalOperation extends Operation {
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
String sum = context.declareResult("sum", myDoubleAccumulator ? "double" : "long", "0");
String sum = context.declareResult("sum", myDoubleAccumulator ? "double" : "long", "0", false);
String count = context.declare("count", "long", "0");
String seenCheck = count + ">0";
String result = (myDoubleAccumulator ? "" : "(double)") + sum + "/" + count;
@@ -417,7 +417,7 @@ abstract class TerminalOperation extends Operation {
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
String arr = context.declareResult("arr", myType + "[]", "new " + myType + "[10]");
String arr = context.declareResult("arr", myType + "[]", "new " + myType + "[10]", false);
String count = context.declare("count", "int", "0");
context.setFinisher("java.util.Arrays.copyOfRange("+arr+",0,"+count+")");
return "if(" + arr + ".length==" + count + ") " + arr + "=java.util.Arrays.copyOf(" + arr + "," + count + "*2);\n" +
@@ -517,7 +517,7 @@ abstract class TerminalOperation extends Operation {
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
transform(context, inVar.getName());
String acc = context.declareResult(myAccNameSupplier.apply(context), myType, getSupplier());
String acc = context.declareResult(myAccNameSupplier.apply(context), myType, getSupplier(), true);
return getAccumulator(acc, inVar.getName());
}
@@ -572,7 +572,7 @@ abstract class TerminalOperation extends Operation {
@Override
public String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
String varName = context.declareResult(myAccName, myAccType, myAccInitializer);
String varName = context.declareResult(myAccName, myAccType, myAccInitializer, asCollector() != null);
context.setFinisher(myFinisherTemplate.replace("{acc}", varName));
return myUpdateTemplate.replace("{item}", inVar.getName()).replace("{acc}", varName);
}
@@ -664,7 +664,7 @@ abstract class TerminalOperation extends Operation {
}
}
String seen = context.declare("seen", "boolean", "false");
String best = context.declareResult("best", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null");
String best = context.declareResult("best", myType, TypeConversionUtil.isPrimitive(myType) ? "0" : "null", false);
String type = myType;
context.setFinisher(new Condition.Optional(type, seen, best));
return "if(!"+seen+" || "+myTemplate.replace("{best}", best).replace("{item}", inVar.getName()).replace("{comparator}", comparator)+") {\n" +
@@ -820,7 +820,7 @@ abstract class TerminalOperation extends Operation {
@Override
String generate(StreamVariable inVar, StreamToLoopReplacementContext context) {
String map = context.declareResult("map", myResultType, "new java.util.HashMap<>()");
String map = context.declareResult("map", myResultType, "new java.util.HashMap<>()", true);
myPredicate.transform(context, inVar.getName());
myCollector.transform(context, inVar.getName());
context.addInitStep(map+".put(false, "+myCollector.getSupplier()+");");
@@ -6,13 +6,14 @@ import java.util.stream.Collectors;
public class Main {
public static void test(List<String> strings) {
Map<Boolean, Map<Character, Set<String>>> map = new HashMap<>();
map.put(false, new HashMap<>());
map.put(true, new HashMap<>());
final Map<Boolean, Map<Character, Set<String>>> nestedMap =
new HashMap<>();
nestedMap.put(false, new HashMap<>());
nestedMap.put(true, new HashMap<>());
for (String s : strings) {
map.get(s.length() > 2).computeIfAbsent(s.charAt(0), k -> new HashSet<>()).add(s);
nestedMap.get(s.length() > 2).computeIfAbsent(s.charAt(0), k -> new HashSet<>()).add(s);
}
System.out.println(map);
System.out.println(nestedMap);
}
public static void main(String[] args) {
@@ -5,13 +5,13 @@ import java.util.stream.Collectors;
public class Main {
public static Map<Integer, String> test(List<String> strings) {
Map<Integer, String> map = new HashMap<>();
Map<Integer, String> mapping = new HashMap<>();
for (String str : strings) {
if (map.put(str.length(), str) != null) {
if (mapping.put(str.length(), str) != null) {
throw new IllegalStateException("Duplicate key");
}
}
return map;
return mapping;
}
public static void main(String[] args) {
@@ -6,7 +6,9 @@ import java.util.stream.Collectors;
public class Main {
public static void test(List<String> strings) {
System.out.println(strings.stream().c<caret>ollect(Collectors.partitioningBy((String s) -> s.length() > 2, Collectors.groupingBy(s -> s.charAt(0), Collectors.toSet()))));
final Map<Boolean, Map<Character, Set<String>>> nestedMap =
strings.stream().c<caret>ollect(Collectors.partitioningBy((String s) -> s.length() > 2, Collectors.groupingBy(s -> s.charAt(0), Collectors.toSet())));
System.out.println(nestedMap);
}
public static void main(String[] args) {
@@ -5,8 +5,9 @@ import java.util.stream.Collectors;
public class Main {
public static Map<Integer, String> test(List<String> strings) {
return strings.stream()
Map<Integer, String> mapping = strings.stream()
.co<caret>llect(Collectors.toMap(String::length, str -> str));
return mapping;
}
public static void main(String[] args) {