[java-inspections] IDEA-346005 Add new inspection: Unnecessary keySet() call

GitOrigin-RevId: d1f1db0ae939017a8550b91cd8742dc222a8db99
This commit is contained in:
Tagir Valeev
2024-09-16 11:48:53 +02:00
committed by intellij-monorepo-bot
parent ecc3d78a3a
commit ac0c57748b
8 changed files with 78 additions and 8 deletions

View File

@@ -2182,7 +2182,7 @@ inspection.replace.on.literal.display.name=Replacement operation has no effect
inspection.redundant.string.operation.display.name=Redundant 'String' operation
inspection.redundant.embedded.expression.display.name=Redundant embedded expression in string template
inspection.redundant.string.fix.remove.str.processor.description=String template can be converted to a plain string literal
inspection.redundant.string.remove.fix.name=Remove redundant ''{0}()'' call
inspection.remove.redundant.call.fix.name=Remove redundant ''{0}()'' call
inspection.redundant.string.fix.family.name=Remove redundant call
inspection.redundant.string.call.message=Call to <code>#ref()</code> is redundant #loc
inspection.redundant.empty.string.argument.message=Unnecessary empty string argument

View File

@@ -5,11 +5,11 @@ import com.intellij.codeInsight.Nullability;
import com.intellij.codeInspection.CleanupLocalInspectionTool;
import com.intellij.codeInspection.CommonQuickFixBundle;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.codeInspection.dataFlow.NullabilityUtil;
import com.intellij.codeInspection.options.OptPane;
import com.intellij.java.analysis.JavaAnalysisBundle;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
@@ -61,7 +61,7 @@ public final class UnnecessaryToStringCallInspection extends BaseInspection impl
@NotNull
public String getName() {
if (replacementText == null) {
return InspectionGadgetsBundle.message("inspection.redundant.string.remove.fix.name", "toString");
return InspectionGadgetsBundle.message("inspection.remove.redundant.call.fix.name", "toString");
}
return CommonQuickFixBundle.message("fix.replace.with.x", replacementText);
}

View File

@@ -127,7 +127,7 @@ public final class RedundantStreamOptionalCallInspection extends AbstractBaseJav
PsiMethodCallExpression qualifierCall = MethodCallUtils.getQualifierMethodCall(call);
if (STREAM_MAP.test(qualifierCall) && qualifierCall.getMethodExpression().getTypeParameters().length == 0 &&
!isIdentityMapping(qualifierCall.getArgumentList().getExpressions()[0], false)) {
String message = JavaBundle.message("inspection.redundant.stream.optional.call.message", name) +
String message = JavaBundle.message("inspection.call.message", name) +
": " + JavaBundle.message("inspection.redundant.stream.optional.call.explanation.map.flatMap");
holder.registerProblem(call, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, getRange(call),
new RemoveCallFix(name, "map"));
@@ -284,7 +284,7 @@ public final class RedundantStreamOptionalCallInspection extends AbstractBaseJav
String methodName = Objects.requireNonNull(call.getMethodExpression().getReferenceName());
String message = explanation != null
? JavaBundle.message("inspection.redundant.stream.optional.call.message.with.explanation", methodName, explanation)
: JavaBundle.message("inspection.redundant.stream.optional.call.message", methodName);
: JavaBundle.message("inspection.call.message", methodName);
holder.registerProblem(call, message, ProblemHighlightType.GENERIC_ERROR_OR_WARNING, getRange(call),
ArrayUtil.prepend(new RemoveCallFix(methodName), additionalFixes));
}

View File

@@ -5,6 +5,7 @@ import com.intellij.codeInsight.PsiEquivalenceUtil;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.util.InspectionMessage;
import com.intellij.codeInspection.util.IntentionName;
import com.intellij.java.JavaBundle;
import com.intellij.modcommand.ModPsiUpdater;
import com.intellij.modcommand.PsiUpdateModCommandQuickFix;
import com.intellij.openapi.project.Project;
@@ -25,6 +26,7 @@ import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.Objects;
import static com.intellij.util.ObjectUtils.tryCast;
import static com.siyeh.ig.callMatcher.CallMatcher.*;
@@ -78,7 +80,9 @@ public final class RedundantCollectionOperationInspection extends AbstractBaseJa
staticCall(CommonClassNames.JAVA_UTIL_COLLECTIONS, "singletonMap").parameterCount(2));
private static final CallMatcher COLLECTION_ADD_ALL =
instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "addAll").parameterTypes(CommonClassNames.JAVA_UTIL_COLLECTION);
private static final CallMatcher MAP_METHODS_SAME_ON_VIEW =
instanceCall(CommonClassNames.JAVA_UTIL_COLLECTION, "size", "isEmpty", "clear").parameterCount(0);
private static final CallMapper<RedundantCollectionOperationHandler> HANDLERS =
new CallMapper<RedundantCollectionOperationHandler>()
.register(TO_ARRAY, AsListToArrayHandler::handler)
@@ -89,6 +93,7 @@ public final class RedundantCollectionOperationInspection extends AbstractBaseJa
.register(REMOVE_BY_INDEX, RedundantIndexOfHandler::handler)
.register(AS_LIST, RedundantAsListForIterationHandler::handler)
.register(AS_LIST, RedundantSortAsListHandler::handler)
.register(anyOf(MAP_KEY_SET, MAP_VALUES), RedundantMapViewHandler::handler)
.register(ITERABLE_ITERATOR, RedundantEmptyIteratorHandler::handler)
.register(MAP_PUT_ALL, call -> ReplaceNestedCallHandler.handler(call, MAP_OF, "put"))
.register(COLLECTION_ADD_ALL, call -> ReplaceNestedCallHandler.handler(call, SINGLETON, "add"));
@@ -423,6 +428,41 @@ public final class RedundantCollectionOperationInspection extends AbstractBaseJa
}
}
private static final class RedundantMapViewHandler implements RedundantCollectionOperationHandler {
private final @NotNull String myName;
private RedundantMapViewHandler(@NotNull String name) {
this.myName = name;
}
@Override
public void performFix(@NotNull Project project, @NotNull PsiMethodCallExpression call) {
PsiExpression qualifier = call.getMethodExpression().getQualifierExpression();
if (qualifier != null) {
new CommentTracker().replaceAndRestoreComments(call, qualifier);
}
}
@Override
public String getProblemName() {
return JavaBundle.message("inspection.call.message", myName);
}
@Override
public @NotNull String getFixName() {
return InspectionGadgetsBundle.message("inspection.remove.redundant.call.fix.name", myName);
}
static RedundantMapViewHandler handler(PsiMethodCallExpression call) {
PsiMethodCallExpression nextCall = ExpressionUtils.getCallForQualifier(call);
String callName = Objects.requireNonNull(call.getMethodExpression().getReferenceName());
if (MAP_METHODS_SAME_ON_VIEW.test(nextCall) || COLLECTION_REMOVE.test(nextCall) && callName.equals("keySet")) {
return new RedundantMapViewHandler(callName);
}
return null;
}
}
private static final class MapKeySetContainsHandler implements RedundantCollectionOperationHandler {
private final String myReplacementMethod;

View File

@@ -927,7 +927,7 @@ public final class RedundantStringOperationInspection extends AbstractBaseJavaLo
@Override
public @Nls @NotNull String getName() {
return InspectionGadgetsBundle.message("inspection.redundant.string.remove.fix.name", myToRemove);
return InspectionGadgetsBundle.message("inspection.remove.redundant.call.fix.name", myToRemove);
}
@Override

View File

@@ -0,0 +1,15 @@
// "Fix all 'Redundant 'Collection' operation' problems in file" "true"
import java.util.*;
class Test {
void test(Map<String, String> map) {
if (map.isEmpty()) return;
if (map.isEmpty()) return;
map.remove("oops");
map.values().remove("oops");
if (map.size() > 10) return;
if (map.size() > 10) return;
map.clear();
map.clear();
}
}

View File

@@ -0,0 +1,15 @@
// "Fix all 'Redundant 'Collection' operation' problems in file" "true"
import java.util.*;
class Test {
void test(Map<String, String> map) {
if (map.ke<caret>ySet().isEmpty()) return;
if (map.values().isEmpty()) return;
map.keySet().remove("oops");
map.values().remove("oops");
if (map.keySet().size() > 10) return;
if (map.values().size() > 10) return;
map.keySet().clear();
map.values().clear();
}
}

View File

@@ -645,7 +645,7 @@ inspection.redundant.stream.optional.call.fix.bind.name=Merge the ''{0}()'' step
inspection.redundant.stream.optional.call.fix.name=Remove ''{0}()'' call
inspection.redundant.stream.optional.call.fix.replace.terminal=Replace the terminal operation
inspection.redundant.stream.optional.call.fix.replace.terminal.text=Replace the terminal operation with ''{0}()''
inspection.redundant.stream.optional.call.message=Redundant ''{0}()'' call
inspection.call.message=Redundant ''{0}()'' call
inspection.redundant.stream.optional.call.message.with.explanation=Redundant ''{0}()'' call: {1}
inspection.redundant.stream.optional.call.option.streamboxing=Report redundant boxing in Stream.map()
inspection.reflect.handle.invocation.argument.not.array=Argument is not an array type