diff --git a/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties b/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties index 6c8ec16f6663..613869c74c63 100644 --- a/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties +++ b/java/java-analysis-impl/resources/messages/InspectionGadgetsBundle.properties @@ -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 #ref() is redundant #loc inspection.redundant.empty.string.argument.message=Unnecessary empty string argument diff --git a/java/java-analysis-impl/src/com/siyeh/ig/style/UnnecessaryToStringCallInspection.java b/java/java-analysis-impl/src/com/siyeh/ig/style/UnnecessaryToStringCallInspection.java index b330134b2099..af3e44e9f325 100644 --- a/java/java-analysis-impl/src/com/siyeh/ig/style/UnnecessaryToStringCallInspection.java +++ b/java/java-analysis-impl/src/com/siyeh/ig/style/UnnecessaryToStringCallInspection.java @@ -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); } diff --git a/java/java-impl-inspections/src/com/intellij/codeInspection/RedundantStreamOptionalCallInspection.java b/java/java-impl-inspections/src/com/intellij/codeInspection/RedundantStreamOptionalCallInspection.java index 3573702ed38b..aa9f334b84b5 100644 --- a/java/java-impl-inspections/src/com/intellij/codeInspection/RedundantStreamOptionalCallInspection.java +++ b/java/java-impl-inspections/src/com/intellij/codeInspection/RedundantStreamOptionalCallInspection.java @@ -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)); } diff --git a/java/java-impl/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java b/java/java-impl/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java index 184092923929..a22be2b04f0a 100644 --- a/java/java-impl/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java +++ b/java/java-impl/src/com/siyeh/ig/redundancy/RedundantCollectionOperationInspection.java @@ -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 HANDLERS = new CallMapper() .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; diff --git a/java/java-impl/src/com/siyeh/ig/redundancy/RedundantStringOperationInspection.java b/java/java-impl/src/com/siyeh/ig/redundancy/RedundantStringOperationInspection.java index 4c26eb5f1cb8..3941ff9f2655 100644 --- a/java/java-impl/src/com/siyeh/ig/redundancy/RedundantStringOperationInspection.java +++ b/java/java-impl/src/com/siyeh/ig/redundancy/RedundantStringOperationInspection.java @@ -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 diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterMapKeySetValues.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterMapKeySetValues.java new file mode 100644 index 000000000000..504fcfdda281 --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/afterMapKeySetValues.java @@ -0,0 +1,15 @@ +// "Fix all 'Redundant 'Collection' operation' problems in file" "true" +import java.util.*; + +class Test { + void test(Map 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(); + } +} \ No newline at end of file diff --git a/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeMapKeySetValues.java b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeMapKeySetValues.java new file mode 100644 index 000000000000..e99ec0722eec --- /dev/null +++ b/java/java-tests/testData/codeInsight/daemonCodeAnalyzer/quickFix/redundantCollectionOperation/beforeMapKeySetValues.java @@ -0,0 +1,15 @@ +// "Fix all 'Redundant 'Collection' operation' problems in file" "true" +import java.util.*; + +class Test { + void test(Map map) { + if (map.keySet().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(); + } +} \ No newline at end of file diff --git a/java/openapi/resources/messages/JavaBundle.properties b/java/openapi/resources/messages/JavaBundle.properties index 745953f29054..50ed2230b6ac 100644 --- a/java/openapi/resources/messages/JavaBundle.properties +++ b/java/openapi/resources/messages/JavaBundle.properties @@ -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