mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
StreamToLoopInspection: reuse variable of inexact type (IDEA-167414)
This commit is contained in:
+17
-1
@@ -475,9 +475,17 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
}
|
||||
|
||||
public String declareResult(String desiredName, PsiType type, String initializer, @NotNull ResultKind kind) {
|
||||
return declareResult(desiredName, type, null, initializer, kind);
|
||||
}
|
||||
|
||||
public String declareResult(String desiredName,
|
||||
PsiType type,
|
||||
String mostAbstractAllowedType,
|
||||
String initializer,
|
||||
@NotNull ResultKind kind) {
|
||||
if (kind != ResultKind.UNKNOWN && myStreamExpression.getParent() instanceof PsiVariable) {
|
||||
PsiVariable var = (PsiVariable)myStreamExpression.getParent();
|
||||
if (EquivalenceChecker.getCanonicalPsiEquivalence().typesAreEquivalent(var.getType(), type) &&
|
||||
if (isCompatibleType(var, type, mostAbstractAllowedType) &&
|
||||
var.getParent() instanceof PsiDeclarationStatement && (kind == ResultKind.FINAL || canUseAsNonFinal(var))) {
|
||||
PsiDeclarationStatement declaration = (PsiDeclarationStatement)var.getParent();
|
||||
if(declaration.getDeclaredElements().length == 1) {
|
||||
@@ -506,6 +514,14 @@ public class StreamToLoopInspection extends BaseJavaBatchLocalInspectionTool {
|
||||
return name;
|
||||
}
|
||||
|
||||
private static boolean isCompatibleType(@NotNull PsiVariable var, @NotNull PsiType type, @Nullable String mostAbstractAllowedType) {
|
||||
if (EquivalenceChecker.getCanonicalPsiEquivalence().typesAreEquivalent(var.getType(), type)) return true;
|
||||
if (mostAbstractAllowedType == null) return false;
|
||||
PsiType[] superTypes = type.getSuperTypes();
|
||||
return Arrays.stream(superTypes).anyMatch(superType -> InheritanceUtil.isInheritor(superType, mostAbstractAllowedType) &&
|
||||
isCompatibleType(var, superType, mostAbstractAllowedType));
|
||||
}
|
||||
|
||||
@Contract("null -> false")
|
||||
private static boolean canUseAsNonFinal(PsiVariable var) {
|
||||
if (!(var instanceof PsiLocalVariable)) return false;
|
||||
|
||||
@@ -591,10 +591,14 @@ abstract class TerminalOperation extends Operation {
|
||||
final PsiType myType;
|
||||
final Function<StreamToLoopReplacementContext, String> myAccNameSupplier;
|
||||
final FunctionHelper mySupplier;
|
||||
final String myMostAbstractAllowedType;
|
||||
|
||||
CollectorBasedTerminalOperation(PsiType type, Function<StreamToLoopReplacementContext, String> accNameSupplier,
|
||||
CollectorBasedTerminalOperation(PsiType type,
|
||||
String mostAbstractAllowedType,
|
||||
Function<StreamToLoopReplacementContext, String> accNameSupplier,
|
||||
FunctionHelper accSupplier) {
|
||||
myType = type;
|
||||
myMostAbstractAllowedType = mostAbstractAllowedType;
|
||||
myAccNameSupplier = accNameSupplier;
|
||||
mySupplier = accSupplier;
|
||||
}
|
||||
@@ -603,7 +607,8 @@ abstract class TerminalOperation extends Operation {
|
||||
String initAccumulator(StreamVariable inVar, StreamToLoopReplacementContext context) {
|
||||
transform(context, inVar.getName());
|
||||
PsiType resultType = correctReturnType(myType);
|
||||
return context.declareResult(myAccNameSupplier.apply(context), resultType, getSupplier(), ResultKind.FINAL);
|
||||
return context
|
||||
.declareResult(myAccNameSupplier.apply(context), resultType, myMostAbstractAllowedType, getSupplier(), ResultKind.FINAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -710,7 +715,8 @@ abstract class TerminalOperation extends Operation {
|
||||
private final boolean myList;
|
||||
|
||||
public ToCollectionTerminalOperation(PsiType resultType, FunctionHelper fn, String desiredName) {
|
||||
super(resultType, context -> fn.suggestFinalOutputNames(context, desiredName, "collection").get(0), fn);
|
||||
super(resultType, CommonClassNames.JAVA_UTIL_COLLECTION,
|
||||
context -> fn.suggestFinalOutputNames(context, desiredName, "collection").get(0), fn);
|
||||
myList = InheritanceUtil.isInheritor(resultType, CommonClassNames.JAVA_UTIL_LIST);
|
||||
}
|
||||
|
||||
@@ -809,7 +815,7 @@ abstract class TerminalOperation extends Operation {
|
||||
PsiExpression merger,
|
||||
FunctionHelper supplier,
|
||||
PsiType resultType) {
|
||||
super(resultType, context -> "map", supplier);
|
||||
super(resultType, CommonClassNames.JAVA_UTIL_MAP, context -> "map", supplier);
|
||||
myKeyExtractor = keyExtractor;
|
||||
myValueExtractor = valueExtractor;
|
||||
myMerger = merger;
|
||||
@@ -878,7 +884,7 @@ abstract class TerminalOperation extends Operation {
|
||||
private String myKeyVar;
|
||||
|
||||
public GroupByTerminalOperation(FunctionHelper keyExtractor, FunctionHelper supplier, PsiType resultType, CollectorOperation collector) {
|
||||
super(resultType, context -> "map", supplier);
|
||||
super(resultType, CommonClassNames.JAVA_UTIL_MAP, context -> "map", supplier);
|
||||
myKeyExtractor = keyExtractor;
|
||||
myCollector = collector;
|
||||
}
|
||||
@@ -947,7 +953,7 @@ abstract class TerminalOperation extends Operation {
|
||||
PsiType resultType = context.createType(myResultType);
|
||||
resultType = correctTypeParameters(resultType, CommonClassNames.JAVA_UTIL_MAP,
|
||||
Collections.singletonMap("V", myCollector::correctReturnType));
|
||||
String map = context.declareResult("map", resultType, "new java.util.HashMap<>()", ResultKind.FINAL);
|
||||
String map = context.declareResult("map", resultType, CommonClassNames.JAVA_UTIL_MAP, "new java.util.HashMap<>()", ResultKind.FINAL);
|
||||
myPredicate.transform(context, inVar.getName());
|
||||
myCollector.transform(context, inVar.getName());
|
||||
context.addBeforeStep(map + ".put(false, " + myCollector.getSupplier() + ");");
|
||||
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
// "Fix all 'Stream API call chain can be replaced with loop' problems in file" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class InExactVariable {
|
||||
public void testMap() {
|
||||
HashMap<String, String> map = new HashMap<>();
|
||||
for (Integer integer2 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String of = String.valueOf(integer2);
|
||||
map.putIfAbsent(of.trim(), of);
|
||||
}
|
||||
Object map1 = map;
|
||||
HashMap<String, String> map2 = new HashMap<>();
|
||||
for (Integer integer1 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String valueOf = String.valueOf(integer1);
|
||||
map2.putIfAbsent(valueOf.trim(), valueOf);
|
||||
}
|
||||
Map<String, String> map3 = new HashMap<>();
|
||||
for (Integer integer : Arrays.asList(1, 2, 3, 4)) {
|
||||
String s = String.valueOf(integer);
|
||||
map3.putIfAbsent(s.trim(), s);
|
||||
}
|
||||
}
|
||||
|
||||
public void testList() {
|
||||
List<String> result1 = new ArrayList<>();
|
||||
for (Integer integer5 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String valueOf1 = String.valueOf(integer5);
|
||||
result1.add(valueOf1);
|
||||
}
|
||||
Object list1 = result1;
|
||||
List<String> result = new ArrayList<>();
|
||||
for (Integer integer4 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String s1 = String.valueOf(integer4);
|
||||
result.add(s1);
|
||||
}
|
||||
Iterable<String> list2 = result;
|
||||
Collection<String> list3 = new ArrayList<>();
|
||||
for (Integer integer3 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String value = String.valueOf(integer3);
|
||||
list3.add(value);
|
||||
}
|
||||
List<String> list4 = new ArrayList<>();
|
||||
for (Integer integer2 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String of = String.valueOf(integer2);
|
||||
list4.add(of);
|
||||
}
|
||||
Collection<Object> list5 = new ArrayList<>();
|
||||
for (Integer integer1 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String valueOf = String.valueOf(integer1);
|
||||
list5.add(valueOf);
|
||||
}
|
||||
List<String> list = new ArrayList<>();
|
||||
for (Integer integer : Arrays.asList(1, 2, 3, 4)) {
|
||||
String s = String.valueOf(integer);
|
||||
list.add(s);
|
||||
}
|
||||
Collection<?> list6 = list;
|
||||
}
|
||||
|
||||
public void testPartition() {
|
||||
Map<Boolean, List<String>> map = new HashMap<>();
|
||||
map.put(false, new ArrayList<>());
|
||||
map.put(true, new ArrayList<>());
|
||||
for (Integer integer1 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String s = String.valueOf(integer1);
|
||||
map.get(s.length() > 1).add(s);
|
||||
}
|
||||
Object map1 = map;
|
||||
Map<Boolean, List<String>> map2 = new HashMap<>();
|
||||
map2.put(false, new ArrayList<>());
|
||||
map2.put(true, new ArrayList<>());
|
||||
for (Integer integer : Arrays.asList(1, 2, 3, 4)) {
|
||||
String x = String.valueOf(integer);
|
||||
map2.get(x.length() > 1).add(x);
|
||||
}
|
||||
}
|
||||
|
||||
public void testGroupingBy() {
|
||||
TreeMap<Integer, Set<String>> result = new TreeMap<>();
|
||||
for (Integer integer4 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String s1 = String.valueOf(integer4);
|
||||
result.computeIfAbsent(s1.length(), k2 -> new HashSet<>()).add(s1);
|
||||
}
|
||||
Object map1 = result;
|
||||
TreeMap<Integer, Set<String>> map2 = new TreeMap<>();
|
||||
for (Integer integer3 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String value = String.valueOf(integer3);
|
||||
map2.computeIfAbsent(value.length(), key1 -> new HashSet<>()).add(value);
|
||||
}
|
||||
NavigableMap<Integer, Set<String>> map3 = new TreeMap<>();
|
||||
for (Integer integer2 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String of = String.valueOf(integer2);
|
||||
map3.computeIfAbsent(of.length(), k1 -> new HashSet<>()).add(of);
|
||||
}
|
||||
SortedMap<Integer, Set<String>> map4 = new TreeMap<>();
|
||||
for (Integer integer1 : Arrays.asList(1, 2, 3, 4)) {
|
||||
String valueOf = String.valueOf(integer1);
|
||||
map4.computeIfAbsent(valueOf.length(), key -> new HashSet<>()).add(valueOf);
|
||||
}
|
||||
TreeMap<Integer, Set<String>> map = new TreeMap<>();
|
||||
for (Integer integer : Arrays.asList(1, 2, 3, 4)) {
|
||||
String s = String.valueOf(integer);
|
||||
map.computeIfAbsent(s.length(), k -> new HashSet<>()).add(s);
|
||||
}
|
||||
Cloneable map5 = map;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
// "Fix all 'Stream API call chain can be replaced with loop' problems in file" "true"
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class InExactVariable {
|
||||
public void testMap() {
|
||||
Object map1 = Stream.of(1, 2, 3, 4).map(String::valueOf)
|
||||
.co<caret>llect(Collectors.toMap(String::trim, Function.identity(), (a, b) -> a, HashMap::new));
|
||||
HashMap<String, String> map2 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors
|
||||
.toMap(String::trim, Function.identity(), (a, b) -> a, HashMap::new));
|
||||
Map<String, String> map3 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors
|
||||
.toMap(String::trim, Function.identity(), (a, b) -> a, HashMap::new));
|
||||
}
|
||||
|
||||
public void testList() {
|
||||
Object list1 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors.toList());
|
||||
Iterable<String> list2 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors.toList());
|
||||
Collection<String> list3 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors.toList());
|
||||
List<String> list4 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors.toList());
|
||||
Collection<Object> list5 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors.toList());
|
||||
Collection<?> list6 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public void testPartition() {
|
||||
Object map1 = Stream.of(1, 2, 3, 4).map(String::valueOf)
|
||||
.collect(Collectors.partitioningBy(x -> x.length() > 1));
|
||||
Map<Boolean, List<String>> map2 = Stream.of(1, 2, 3, 4).map(String::valueOf)
|
||||
.collect(Collectors.partitioningBy((String x) -> x.length() > 1));
|
||||
}
|
||||
|
||||
public void testGroupingBy() {
|
||||
Object map1 = Stream.of(1, 2, 3, 4).map(String::valueOf)
|
||||
.collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toSet()));
|
||||
TreeMap<Integer, Set<String>> map2 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors
|
||||
.groupingBy(String::length, TreeMap::new, Collectors.toSet()));
|
||||
NavigableMap<Integer, Set<String>> map3 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors
|
||||
.groupingBy(String::length, TreeMap::new, Collectors.toSet()));
|
||||
SortedMap<Integer, Set<String>> map4 = Stream.of(1, 2, 3, 4).map(String::valueOf).collect(Collectors
|
||||
.groupingBy(String::length, TreeMap::new, Collectors.toSet()));
|
||||
Cloneable map5 = Stream.of(1, 2, 3, 4).map(String::valueOf)
|
||||
.collect(Collectors.groupingBy(String::length, TreeMap::new, Collectors.toSet()));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user