StreamToLoopInspection: support groupingBy(..., counting()/summingInt()/summingLong()/summingDouble()/mapping(summing...))

This commit is contained in:
Tagir Valeev
2017-01-24 17:54:30 +07:00
parent 80e09a9e59
commit 2d57e55143
40 changed files with 210 additions and 34 deletions

View File

@@ -35,6 +35,7 @@ import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.RedundantCastUtil;
import com.intellij.refactoring.util.RefactoringUtil;
import com.siyeh.ig.psiutils.*;
import one.util.streamex.IntStreamEx;
@@ -297,6 +298,7 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
private static void normalize(@NotNull Project project, PsiElement element) {
element = JavaCodeStyleManager.getInstance(project).shortenClassReferences(element);
PsiDiamondTypeUtil.removeRedundantTypeArguments(element);
RedundantCastUtil.getRedundantCastsInside(element).forEach(RedundantCastUtil::removeCast);
CodeStyleManager.getInstance(project).reformat(element);
}

View File

@@ -21,6 +21,7 @@ import com.intellij.codeInspection.util.OptionalUtil;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTypesUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.siyeh.ig.psiutils.BoolUtils;
@@ -73,7 +74,7 @@ abstract class TerminalOperation extends Operation {
return null;
}
if(name.equals("count") && args.length == 0) {
return new TemplateBasedOperation("count", "long", "0", "{acc}++;");
return TemplateBasedOperation.counting();
}
if(name.equals("sum") && args.length == 0) {
return TemplateBasedOperation.summing(resultType);
@@ -204,7 +205,7 @@ abstract class TerminalOperation extends Operation {
return null;
case "counting":
if (collectorArgs.length != 0) return null;
return new TemplateBasedOperation("count", "long", "0", "{acc}++;");
return TemplateBasedOperation.counting();
case "summingInt":
case "summingLong":
case "summingDouble": {
@@ -568,6 +569,10 @@ abstract class TerminalOperation extends Operation {
String getSupplier();
String getAccumulatorUpdater(StreamVariable inVar, String acc);
default String getMerger(StreamVariable inVar, String map, String key) {
return null;
}
default PsiType correctReturnType(PsiType type) {return type;}
}
@@ -650,7 +655,7 @@ abstract class TerminalOperation extends Operation {
@Override
CollectorOperation asCollector() {
return myFinisherTemplate.equals("{acc}") && !TypeConversionUtil.isPrimitive(myAccType) ? this : null;
return myFinisherTemplate.equals("{acc}") ? this : null;
}
@Override
@@ -663,9 +668,19 @@ abstract class TerminalOperation extends Operation {
return myUpdateTemplate.replace("{acc}", acc).replace("{item}", inVar.getName());
}
@Override
public String getMerger(StreamVariable inVar, String map, String key) {
String boxedType = PsiTypesUtil.boxIfPossible(myAccType);
if (boxedType.equals(myAccType)) return null;
String val = myUpdateTemplate.equals("{acc}++;") ? "1L" : "(" + myAccType + ")" + inVar;
String merger = boxedType + "::sum";
return map + ".merge(" + key + "," + val + "," + merger + ");\n";
}
@NotNull
static TemplateBasedOperation summing(PsiType type) {
return new TemplateBasedOperation("sum", type.getCanonicalText(), "0", "{acc}+={item};");
String defValue = type.equals(PsiType.DOUBLE) ? "0.0" : type.equals(PsiType.LONG) ? "0L" : "0";
return new TemplateBasedOperation("sum", type.getCanonicalText(), defValue, "{acc}+={item};");
}
@NotNull
@@ -673,6 +688,11 @@ abstract class TerminalOperation extends Operation {
return new TemplateBasedOperation("stat", resultType.getCanonicalText(), "new " + resultType.getCanonicalText() + "()",
"{acc}.accept({item});");
}
@NotNull
static TemplateBasedOperation counting() {
return new TemplateBasedOperation("count", "long", "0L", "{acc}++;");
}
}
static class ToCollectionTerminalOperation extends CollectorBasedTerminalOperation {
@@ -873,7 +893,10 @@ abstract class TerminalOperation extends Operation {
@Override
public String getAccumulatorUpdater(StreamVariable inVar, String map) {
String acc = map+".computeIfAbsent("+myKeyExtractor.getText()+","+myKeyVar+"->"+myCollector.getSupplier()+")";
String key = myKeyExtractor.getText();
String merger = myCollector.getMerger(inVar, map, key);
if (merger != null) return merger;
String acc = map + ".computeIfAbsent(" + key + "," + myKeyVar + "->" + myCollector.getSupplier() + ")";
return myCollector.getAccumulatorUpdater(inVar, acc);
}
}
@@ -911,7 +934,10 @@ abstract class TerminalOperation extends Operation {
myCollector.transform(context, inVar.getName());
context.addBeforeStep(map + ".put(false, " + myCollector.getSupplier() + ");");
context.addBeforeStep(map + ".put(true, " + myCollector.getSupplier() + ");");
return myCollector.getAccumulatorUpdater(inVar, map + ".get(" + myPredicate.getText() + ")");
String key = myPredicate.getText();
String merger = myCollector.getMerger(inVar, map, key);
if (merger != null) return merger;
return myCollector.getAccumulatorUpdater(inVar, map + ".get(" + key + ")");
}
}
@@ -984,6 +1010,12 @@ abstract class TerminalOperation extends Operation {
public String getAccumulatorUpdater(StreamVariable inVar, String acc) {
return myVariable.getDeclaration(myMapper.getText()) + myDownstreamCollector.getAccumulatorUpdater(myVariable, acc);
}
@Override
public String getMerger(StreamVariable inVar, String map, String key) {
String merger = myDownstreamCollector.getMerger(myVariable, map, key);
return merger == null ? null : myVariable.getDeclaration(myMapper.getText()) + merger;
}
}
static class InlineMappingTerminalOperation extends AbstractMappingTerminalOperation {
@@ -1008,6 +1040,11 @@ abstract class TerminalOperation extends Operation {
public String getAccumulatorUpdater(StreamVariable inVar, String acc) {
return myDownstreamCollector.getAccumulatorUpdater(new StreamVariable(myMapper.getResultType(), myMapper.getText()), acc);
}
@Override
public String getMerger(StreamVariable inVar, String map, String key) {
return myDownstreamCollector.getMerger(new StreamVariable(myMapper.getResultType(), myMapper.getText()), map, key);
}
}
static class ForEachTerminalOperation extends TerminalOperation {

View File

@@ -6,7 +6,7 @@ import java.util.Set;
public class Main {
private static long test() {
long count = 0;
long count = 0L;
Set<Integer> uniqueValues = new HashSet<>();
long toSkip = 1;
for (Integer integer : new Integer[]{1, 2, 3, 2, 3}) {

View File

@@ -5,7 +5,7 @@ import java.util.stream.Collectors;
public class Main {
public static long test(List<String> strings) {
long count = 0;
long count = 0L;
for (String s : strings) {
if (!s.isEmpty()) {
count++;

View File

@@ -7,7 +7,7 @@ import java.util.stream.Collectors;
public class Main {
public static Double test(List<String> strings) {
double sum = 0;
double sum = 0.0;
for (String string : strings) {
if (string != null) {
sum += string.length();

View File

@@ -4,7 +4,7 @@ import java.util.List;
public class Main {
public void test(List<String> list) {
long x = 0;
long x = 0L;
for (String s : list) {
x++;
}

View File

@@ -7,7 +7,7 @@ public class Main {
}
public long test(List<Count> count) {
long result = 0;
long result = 0L;
for (Count count1 : count) {
result++;
}

View File

@@ -5,7 +5,7 @@ import java.util.List;
public class Main {
public long test(List<String> list) {
if(!list.isEmpty()) {
long count = 0;
long count = 0L;
for (String s : list) {
count++;
}

View File

@@ -4,7 +4,7 @@ import java.util.List;
public class Main {
public long test(List<String> list) {
long count = 0;
long count = 0L;
for (String s : list) {
count++;
}

View File

@@ -6,7 +6,7 @@ import java.util.Set;
public class Main {
public long test(List<String> list) {
long count = 0;
long count = 0L;
Set<String> uniqueValues = new HashSet<>();
for (String s : list) {
if (uniqueValues.add(s)) {

View File

@@ -4,7 +4,7 @@ import java.util.Arrays;
public class Main {
private static long countInRange(int... input) {
long count = 0;
long count = 0L;
for (int x : input) {
if (x > 0) {
if (x < 10) {

View File

@@ -5,7 +5,7 @@ import java.util.Arrays;
public class Main {
private static long countInRange(int... input) {
int x = 1;
long count = 0;
long count = 0L;
for (int y : input) {
if (y > 0) {
if (y < 10) {

View File

@@ -6,7 +6,7 @@ public class Main {
private static long countInRange(int... input) {
int x = 1;
int y = 2;
long count = 0;
long count = 0L;
for (int i : input) {
if (i > 0) {
if (i < 10) {

View File

@@ -7,7 +7,7 @@ public class Main {
int x = 1;
int y = 2;
int i = 3;
long count = 0;
long count = 0L;
for (int x1 : input) {
if (x1 > 0) {
if (x1 < 10) {

View File

@@ -6,7 +6,7 @@ public class Main {
private static long countInRange(int... input) {
int x = 1;
int i = 3;
long result = 0;
long result = 0L;
for (int count : input) {
if (count > 0) {
if (count < 10) {

View File

@@ -6,7 +6,7 @@ import java.util.stream.Stream;
public class Main {
private static long test(List<? extends String> list) {
long count = 0;
long count = 0L;
for (Object o : Arrays.asList(0, null, "1", list)) {
for (Object o1 : Arrays.asList(o)) {
for (Object o2 : Arrays.asList(o1)) {

View File

@@ -8,7 +8,7 @@ import static java.util.Arrays.asList;
public class Main {
private static long test(List<List<String>> nested) {
long count = 0;
long count = 0L;
for (List<String> names : nested) {
Set<String> uniqueValues = new HashSet<>();
for (String name : names) {

View File

@@ -5,7 +5,7 @@ import java.util.*;
public class Main {
private static long test(Map<String, List<String>> strings) {
long count = 0;
long count = 0L;
for (Map.Entry<String, List<String>> e : strings.entrySet()) {
if (!e.getKey().isEmpty()) {
String sInner = e.getKey();

View File

@@ -7,7 +7,7 @@ public class Main {
static Predicate<String> nonEmpty = s -> s != null && !s.isEmpty();
private static long test(List<String> strings) {
long count = 0;
long count = 0L;
for (String string : strings) {
if (nonEmpty.test(string)) {
count++;

View File

@@ -6,7 +6,7 @@ import java.util.function.Predicate;
public class Main {
private static long test(List<Predicate<String>> predicates, List<String> strings) {
long count = 0;
long count = 0L;
for (Predicate<String> pred : predicates) {
if (pred != null) {
for (String string : strings) {

View File

@@ -0,0 +1,15 @@
// "Replace Stream API chain with loop" "true"
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Integer, Long> map = new HashMap<>();
for (String s : list) {
map.merge(s.length(), 1L, Long::sum);
}
}
}

View File

@@ -0,0 +1,16 @@
// "Replace Stream API chain with loop" "true"
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Integer, Integer> map3 = new HashMap<>();
for (String s : list) {
String trim = s.trim();
map3.merge(s.length(), trim.length(), Integer::sum);
}
}
}

View File

@@ -0,0 +1,15 @@
// "Replace Stream API chain with loop" "true"
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Integer, Double> map4 = new HashMap<>();
for (String s : list) {
map4.merge(s.length(), (double) s.length(), Double::sum);
}
}
}

View File

@@ -5,7 +5,7 @@ import java.util.List;
public class Main {
private static long countNonEmpty(List<String> input) {
long count = 0;
long count = 0L;
for (String str : input) {
String trim = str.trim();
if (!trim.isEmpty()) {

View File

@@ -7,7 +7,7 @@ import java.util.stream.Stream;
public class Main {
private static long test(Map<String, List<String>> strings) {
long sum = 0;
long sum = 0L;
for (Map.Entry<String, List<String>> e : strings.entrySet()) {
if (!e.getKey().isEmpty()) {
long count = e.getValue().stream().filter(new Predicate<String>() {

View File

@@ -6,7 +6,7 @@ import java.util.stream.Stream;
public class Main {
private static long test(Map<String, List<String>> strings) {
long sum = 0;
long sum = 0L;
for (Map.Entry<String, List<String>> e : strings.entrySet()) {
if (!e.getKey().isEmpty()) {
long count = e.getValue().stream().filter(s -> e.getKey().equals(s)).count();

View File

@@ -6,7 +6,7 @@ import java.util.stream.Stream;
public class Main {
private static long test(Map<String, List<String>> strings) {
long sum = 0;
long sum = 0L;
for (Map.Entry<String, List<String>> s : strings.entrySet()) {
if (!s.getKey().isEmpty()) {
long count = s.getValue().stream().filter(sx -> s.getKey().equals(sx)).count();

View File

@@ -7,7 +7,7 @@ import static java.util.Arrays.asList;
public class Main {
public static long test(List<String> list) {
long count = 0;
long count = 0L;
for (String l : list) {
if (l != null) {
(new Consumer<String>() {

View File

@@ -7,7 +7,7 @@ import static java.util.Arrays.asList;
public class Main {
public static long test(List<String> list) {
long count = 0;
long count = 0L;
for (String l : list) {
if (l != null) {
(new Consumer<String>() {

View File

@@ -0,0 +1,17 @@
// "Replace Stream API chain with loop" "true"
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Boolean, Long> map2 = new HashMap<>();
map2.put(false, 0L);
map2.put(true, 0L);
for (String s : list) {
map2.merge(s.isEmpty(), 1L, Long::sum);
}
}
}

View File

@@ -0,0 +1,17 @@
// "Replace Stream API chain with loop" "true"
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Boolean, Double> map1 = new HashMap<>();
map1.put(false, 0.0);
map1.put(true, 0.0);
for (String s : list) {
map1.merge(s.isEmpty(), (double) s.length(), Double::sum);
}
}
}

View File

@@ -4,7 +4,7 @@ import java.util.stream.IntStream;
public class Main {
private static long check(int start, int stop, double v) {
long count = 0;
long count = 0L;
for (int x = start; x < stop; x++) {
double x1 = 1.0 / x;
if (x1 < v) {

View File

@@ -4,7 +4,7 @@ import java.util.stream.IntStream;
public class Main {
private static long check(int start, double val) {
long count = 0;
long count = 0L;
int bound = start * 200;
for (int x = start; x <= bound; x++) {
double v = 1.0 / x;

View File

@@ -6,7 +6,7 @@ import java.util.function.LongSupplier;
public class Main {
private static void test(List<String> list) {
// and filter!
long count1 = 0;
long count1 = 0L;
for (String s : list) {
if (!s/* comment */.isEmpty()) {
count1++;

View File

@@ -4,7 +4,7 @@ import java.util.*;
public class Main {
private static long test(List<?> list) {
long count = 0;
long count = 0L;
Set<Object> uniqueValues = new HashSet<>();
long toSkip = list.size() / 2;
for (Object o : list) {

View File

@@ -0,0 +1,11 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Integer, Long> map = list.stream().coll<caret>ect(Collectors.groupingBy(String::length, Collectors.counting()));
}
}

View File

@@ -0,0 +1,11 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Integer, Integer> map3 = list.stream().coll<caret>ect(Collectors.groupingBy(String::length, Collectors.mapping(String::trim, Collectors.summingInt(String::length))));
}
}

View File

@@ -0,0 +1,11 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Integer, Double> map4 = list.stream().co<caret>llect(Collectors.groupingBy(String::length, Collectors.summingDouble(String::length)));
}
}

View File

@@ -0,0 +1,12 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Boolean, Long> map2 = list.stream()
.co<caret>llect(Collectors.partitioningBy(String::isEmpty, Collectors.counting()));
}
}

View File

@@ -0,0 +1,12 @@
// "Replace Stream API chain with loop" "true"
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
public class Test {
static void test(List<String> list) {
Map<Boolean, Double> map1 = list.stream()
.col<caret>lect(Collectors.partitioningBy(String::isEmpty, Collectors.summingDouble(String::length)));
}
}