mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Java8MapApiInspection: check if rhs has no map usages (except map.get(key)) for key set based loop (IDEA-CR-44452)
This commit is contained in:
+20
-14
@@ -115,10 +115,18 @@ public class Java8MapApiInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
if (!condition.isKeyAccess(key)) return;
|
||||
PsiExpression value = args[1];
|
||||
if (condition.isEntrySet() && isUsedAsReference(value, condition)) return;
|
||||
if (hasMapUsages(condition, value)) return;
|
||||
if (!LambdaGenerationUtil.canBeUncheckedLambda(value, variable -> condition.getMap().equals(variable))) return;
|
||||
|
||||
ReplaceWithSingleMapOperation fix = ReplaceWithSingleMapOperation.create("replaceAll", putCall, value);
|
||||
holder.registerProblem(statement.getFirstChild(), QuickFixBundle.message("java.8.map.api.inspection.description", fix.myMethodName),
|
||||
fix);
|
||||
holder.registerProblem(statement.getFirstChild(),
|
||||
QuickFixBundle.message("java.8.map.api.inspection.description", fix.myMethodName), fix);
|
||||
}
|
||||
|
||||
private boolean hasMapUsages(@NotNull MapLoopCondition condition, @Nullable PsiExpression value) {
|
||||
return !VariableAccessUtils.getVariableReferences(condition.getMap(), value).stream()
|
||||
.map(ExpressionUtils::getCallForQualifier)
|
||||
.allMatch(call -> condition.isValueAccess(call));
|
||||
}
|
||||
|
||||
private boolean isUsedAsReference(@NotNull PsiElement value, @NotNull MapLoopCondition condition) {
|
||||
@@ -389,23 +397,21 @@ public class Java8MapApiInspection extends AbstractBaseJavaLocalInspectionTool {
|
||||
@NotNull MapLoopCondition loopCondition,
|
||||
@NotNull PsiExpression value,
|
||||
@NotNull CommentTracker tracker) {
|
||||
if (value instanceof PsiMethodCallExpression) {
|
||||
if (loopCondition.isKeyAccess(value)) return factory.createExpressionFromText("(" + kVar + "," + vVar + ") ->" + kVar, value);
|
||||
if (loopCondition.isValueAccess(value)) return factory.createExpressionFromText("(" + kVar + "," + vVar + ") ->" + vVar, value);
|
||||
}
|
||||
if (!loopCondition.isEntrySet()) {
|
||||
PsiParameter param = loopCondition.getIterParam();
|
||||
VariableAccessUtils.getVariableReferences(param, value).forEach(ref -> ExpressionUtils.bindReferenceTo(ref, kVar));
|
||||
}
|
||||
else {
|
||||
if (value instanceof PsiMethodCallExpression) {
|
||||
if (loopCondition.isKeyAccess(value)) return factory.createExpressionFromText("(" + kVar + "," + vVar + ") ->" + kVar, value);
|
||||
if (loopCondition.isValueAccess(value)) return factory.createExpressionFromText("(" + kVar + "," + vVar + ") ->" + vVar, value);
|
||||
Collection<PsiMethodCallExpression> calls = PsiTreeUtil.collectElementsOfType(value, PsiMethodCallExpression.class);
|
||||
for (PsiMethodCallExpression call : calls) {
|
||||
if (loopCondition.isKeyAccess(call)) {
|
||||
tracker.replace(call, kVar);
|
||||
}
|
||||
Collection<PsiMethodCallExpression> calls = PsiTreeUtil.collectElementsOfType(value, PsiMethodCallExpression.class);
|
||||
for (PsiMethodCallExpression call : calls) {
|
||||
if (loopCondition.isKeyAccess(call)) {
|
||||
tracker.replace(call, kVar);
|
||||
}
|
||||
else if (loopCondition.isValueAccess(call)) {
|
||||
tracker.replace(call, vVar);
|
||||
}
|
||||
else if (loopCondition.isValueAccess(call)) {
|
||||
tracker.replace(call, vVar);
|
||||
}
|
||||
}
|
||||
return factory.createExpressionFromText("(" + kVar + "," + vVar + ") ->" + tracker.text(value), value);
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
// "Replace with 'replaceAll' method call" "true"
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Main {
|
||||
public void test() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("foo", "bar");
|
||||
map.replaceAll((k, v) -> v);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// "Replace with 'replaceAll' method call" "true"
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class Main {
|
||||
public void test() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("foo", "bar");
|
||||
for<caret> (String key : map.keySet()) {
|
||||
map.put(key, map.get(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// "Replace with 'replaceAll' method call" "false"
|
||||
|
||||
public class Main {
|
||||
public void test() {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
map.put("foo", "bar");
|
||||
String s = "foo";
|
||||
s += "bar";
|
||||
for<caret> (String k : map.keySet()) {
|
||||
map.put(k, s);
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
-6
@@ -298,11 +298,14 @@ public class Java8MigrationUtils {
|
||||
private final PsiParameter myIterParam;
|
||||
private final boolean myIsEntrySet;
|
||||
private final PsiReferenceExpression myMapExpression;
|
||||
private final PsiVariable myMap;
|
||||
|
||||
private MapLoopCondition(@NotNull PsiParameter iterParam, boolean isEntrySet, @NotNull PsiReferenceExpression mapExpression) {
|
||||
private MapLoopCondition(@NotNull PsiParameter iterParam, boolean isEntrySet,
|
||||
@NotNull PsiReferenceExpression mapExpression, @NotNull PsiVariable map) {
|
||||
myIterParam = iterParam;
|
||||
myIsEntrySet = isEntrySet;
|
||||
myMapExpression = mapExpression;
|
||||
myMap = map;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -317,7 +320,7 @@ public class Java8MigrationUtils {
|
||||
ObjectUtils.tryCast(ControlFlowUtils.stripBraces(statement.getBody()), PsiExpressionStatement.class);
|
||||
if (putStatement == null) return null;
|
||||
PsiMethodCallExpression putCall = extractMapMethodCall(putStatement.getExpression(), "put");
|
||||
if (putCall == null || !isMap(putCall.getMethodExpression().getQualifierExpression())) return null;
|
||||
if (putCall == null || !isMapRef(putCall.getMethodExpression().getQualifierExpression())) return null;
|
||||
return putCall;
|
||||
}
|
||||
|
||||
@@ -334,10 +337,20 @@ public class Java8MigrationUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given expression is entry.getValue() call (for entry set based loop).
|
||||
* Check if given expression is entry.getValue() call (for entry set based loop) or map.get(key) (for key based loop).
|
||||
*/
|
||||
public boolean isValueAccess(@NotNull PsiExpression expression) {
|
||||
return myIsEntrySet && isParamCall(expression, "getValue");
|
||||
if (myIsEntrySet) return isParamCall(expression, "getValue");
|
||||
return isGetCall(expression);
|
||||
}
|
||||
|
||||
private boolean isGetCall(@NotNull PsiExpression expression) {
|
||||
PsiMethodCallExpression call = ObjectUtils.tryCast(expression, PsiMethodCallExpression.class);
|
||||
if (call == null) return false;
|
||||
String name = call.getMethodExpression().getReferenceName();
|
||||
if (!"get".equals(name) || !isMapRef(call.getMethodExpression().getQualifierExpression())) return false;
|
||||
PsiExpression[] args = call.getArgumentList().getExpressions();
|
||||
return args.length == 1 && ExpressionUtils.isReferenceTo(args[0], myIterParam);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -353,6 +366,10 @@ public class Java8MigrationUtils {
|
||||
return myIterParam;
|
||||
}
|
||||
|
||||
public PsiVariable getMap() {
|
||||
return myMap;
|
||||
}
|
||||
|
||||
public boolean isEntrySet() {
|
||||
return myIsEntrySet;
|
||||
}
|
||||
@@ -364,7 +381,7 @@ public class Java8MigrationUtils {
|
||||
return expectedName.equals(name) && isParamCall(call);
|
||||
}
|
||||
|
||||
private boolean isMap(@Nullable PsiElement element) {
|
||||
private boolean isMapRef(@Nullable PsiElement element) {
|
||||
return element != null && PsiEquivalenceUtil.areElementsEquivalent(myMapExpression, element);
|
||||
}
|
||||
|
||||
@@ -388,7 +405,9 @@ public class Java8MigrationUtils {
|
||||
private static MapLoopCondition create(@NotNull PsiParameter iterParam, boolean isEntrySet, @Nullable PsiExpression qualifier) {
|
||||
PsiReferenceExpression ref = ObjectUtils.tryCast(qualifier, PsiReferenceExpression.class);
|
||||
if (ref == null) return null;
|
||||
return new MapLoopCondition(iterParam, isEntrySet, ref);
|
||||
PsiVariable map = ObjectUtils.tryCast(ref.resolve(), PsiVariable.class);
|
||||
if (map == null) return null;
|
||||
return new MapLoopCondition(iterParam, isEntrySet, ref, map);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user