diff --git a/java/java-impl/src/com/intellij/codeInspection/bulkOperation/BulkMethodInfo.java b/java/java-impl/src/com/intellij/codeInspection/bulkOperation/BulkMethodInfo.java index 7fc0ac534321..abc40ace30af 100644 --- a/java/java-impl/src/com/intellij/codeInspection/bulkOperation/BulkMethodInfo.java +++ b/java/java-impl/src/com/intellij/codeInspection/bulkOperation/BulkMethodInfo.java @@ -1,12 +1,15 @@ // Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.codeInspection.bulkOperation; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.pom.java.LanguageLevel; import com.intellij.psi.*; import com.intellij.psi.util.InheritanceUtil; import com.intellij.psi.util.PsiUtil; import com.intellij.util.containers.ContainerUtil; import com.siyeh.ig.psiutils.TypeUtils; +import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -16,11 +19,13 @@ public final class BulkMethodInfo { private final String myClassName; private final String mySimpleName; private final String myBulkName; + private final String myBulkParameterType; - public BulkMethodInfo(String className, String simpleName, String bulkName) { + public BulkMethodInfo(String className, String simpleName, String bulkName, String bulkParameterType) { myClassName = className; mySimpleName = simpleName; myBulkName = bulkName; + myBulkParameterType = bulkParameterType; } public boolean isMyMethod(PsiReferenceExpression ref) { @@ -29,13 +34,15 @@ public final class BulkMethodInfo { if (!(element instanceof PsiMethod)) return false; PsiMethod method = (PsiMethod)element; PsiParameterList parameters = method.getParameterList(); - if (parameters.getParametersCount() != (myClassName.equals(JAVA_UTIL_MAP) ? 2 : 1)) return false; - PsiParameter parameter = Objects.requireNonNull(parameters.getParameter(0)); - PsiClass parameterClass = PsiUtil.resolveClassInClassTypeOnly(parameter.getType()); - if (parameterClass == null || - JAVA_LANG_ITERABLE.equals(parameterClass.getQualifiedName()) || - JAVA_UTIL_COLLECTION.equals(parameterClass.getQualifiedName())) { - return false; + if (parameters.getParametersCount() != getSimpleParametersCount()) return false; + if (getSimpleParametersCount() == 1) { + PsiParameter parameter = Objects.requireNonNull(parameters.getParameter(0)); + PsiClass parameterClass = PsiUtil.resolveClassInClassTypeOnly(parameter.getType()); + if (parameterClass == null || + JAVA_LANG_ITERABLE.equals(parameterClass.getQualifiedName()) || + JAVA_UTIL_COLLECTION.equals(parameterClass.getQualifiedName())) { + return false; + } } PsiClass methodClass = method.getContainingClass(); if (methodClass == null || !InheritanceUtil.isInheritor(methodClass, myClassName)) return false; @@ -46,11 +53,7 @@ public final class BulkMethodInfo { return ContainerUtil.or(aClass.findMethodsByName(myBulkName, true), method -> { PsiParameter[] parameters = method.getParameterList().getParameters(); if (parameters.length != 1) return false; - PsiParameter parameter = parameters[0]; - if (myClassName.equals(JAVA_UTIL_MAP)) { - return TypeUtils.variableHasTypeOrSubtype(parameter, JAVA_UTIL_MAP); - } - return TypeUtils.variableHasTypeOrSubtype(parameter, JAVA_LANG_ITERABLE, JAVA_UTIL_COLLECTION); + return TypeUtils.variableHasTypeOrSubtype(parameters[0], getBulkParameterType(aClass.getProject())); }); } @@ -78,16 +81,8 @@ public final class BulkMethodInfo { } PsiClass aClass = PsiUtil.resolveClassInType(type); if (aClass == null) return false; - PsiClass commonParent; - if (myClassName.equals(JAVA_UTIL_MAP)) { - commonParent = psiFacade.findClass(JAVA_UTIL_MAP, aClass.getResolveScope()); - } else { - commonParent = psiFacade.findClass(JAVA_LANG_ITERABLE, aClass.getResolveScope()); - if (commonParent == null) { - // No Iterable class in Java 1.4 - commonParent = psiFacade.findClass(JAVA_UTIL_COLLECTION, aClass.getResolveScope()); - } - } + String bulkParameterType = getBulkParameterType(aClass.getProject()); + PsiClass commonParent = psiFacade.findClass(bulkParameterType, aClass.getResolveScope()); if (!InheritanceUtil.isInheritorOrSelf(aClass, commonParent, true)) return false; PsiExpression expression = factory.createExpressionFromText(qualifier.getText() + "." + myBulkName + "(" + text + ")", iterable); if (!(expression instanceof PsiMethodCallExpression)) return false; @@ -101,10 +96,7 @@ public final class BulkMethodInfo { PsiClass parameterClass = PsiUtil.resolveClassInClassTypeOnly(parameterType); if (parameterClass == null) return false; String qualifiedName = parameterClass.getQualifiedName(); - return (myClassName.equals(JAVA_UTIL_MAP) - ? JAVA_UTIL_MAP.equals(qualifiedName) - : (JAVA_LANG_ITERABLE.equals(qualifiedName) || JAVA_UTIL_COLLECTION.equals(qualifiedName))) && - parameterType.isAssignableFrom(type); + return bulkParameterType.equals(qualifiedName) && parameterType.isAssignableFrom(type); } public String getClassName() { @@ -115,10 +107,22 @@ public final class BulkMethodInfo { return mySimpleName; } + public int getSimpleParametersCount() { + return myBulkParameterType.equals(JAVA_UTIL_MAP) ? 2 : 1; + } + public String getBulkName() { return myBulkName; } + public String getBulkParameterType(@NotNull Project project) { + if (myBulkParameterType.equals(JAVA_LANG_ITERABLE) && + PsiUtil.getLanguageLevel(project).isLessThan(LanguageLevel.JDK_1_5)) { + return JAVA_UTIL_COLLECTION; + } + return myBulkParameterType; + } + public String getReplacementName() { return StringUtil.getShortName(myClassName) + "." + myBulkName; } diff --git a/java/java-impl/src/com/intellij/codeInspection/bulkOperation/JdkBulkMethodInfoProvider.java b/java/java-impl/src/com/intellij/codeInspection/bulkOperation/JdkBulkMethodInfoProvider.java index bf7ca7bc8863..6b9a65790a5d 100644 --- a/java/java-impl/src/com/intellij/codeInspection/bulkOperation/JdkBulkMethodInfoProvider.java +++ b/java/java-impl/src/com/intellij/codeInspection/bulkOperation/JdkBulkMethodInfoProvider.java @@ -9,8 +9,8 @@ import java.util.stream.Stream; public class JdkBulkMethodInfoProvider implements BulkMethodInfoProvider { private static final BulkMethodInfo[] INFOS = { - new BulkMethodInfo(CommonClassNames.JAVA_UTIL_COLLECTION, "add", "addAll"), - new BulkMethodInfo(CommonClassNames.JAVA_UTIL_MAP, "put", "putAll") + new BulkMethodInfo(CommonClassNames.JAVA_UTIL_COLLECTION, "add", "addAll", CommonClassNames.JAVA_UTIL_COLLECTION), + new BulkMethodInfo(CommonClassNames.JAVA_UTIL_MAP, "put", "putAll", CommonClassNames.JAVA_UTIL_MAP), }; @NotNull diff --git a/java/java-impl/src/com/intellij/codeInspection/bulkOperation/UseBulkOperationInspection.java b/java/java-impl/src/com/intellij/codeInspection/bulkOperation/UseBulkOperationInspection.java index cfc2fb22a2b7..8838f148f2d4 100644 --- a/java/java-impl/src/com/intellij/codeInspection/bulkOperation/UseBulkOperationInspection.java +++ b/java/java-impl/src/com/intellij/codeInspection/bulkOperation/UseBulkOperationInspection.java @@ -55,8 +55,7 @@ public class UseBulkOperationInspection extends AbstractBaseJavaLocalInspectionT @Nullable private static PsiExpression findIterable(PsiMethodCallExpression expression, BulkMethodInfo info) { PsiExpression[] args = expression.getArgumentList().getExpressions(); - int simpleMethodParametersCount = info.getClassName().equals(CommonClassNames.JAVA_UTIL_MAP) ? 2 : 1; - if (args.length != simpleMethodParametersCount) return null; + if (args.length != info.getSimpleParametersCount()) return null; PsiElement parent = expression.getParent(); if (parent instanceof PsiLambdaExpression) { return findIterableForLambda((PsiLambdaExpression)parent, args, info); @@ -78,7 +77,7 @@ public class UseBulkOperationInspection extends AbstractBaseJavaLocalInspectionT if (args.length == 1 && ExpressionUtils.isReferenceTo(args[0], declaration.getNextElementVariable(statements[0]))) { return declaration.getIterable(); } else if (args.length == 2) { - if (isGetValueAndGetKey(args, declaration.getNextElementVariable(statements[0]))) { + if (isGetKeyAndGetValue(args, declaration.getNextElementVariable(statements[0]))) { PsiMethodCallExpression entrySetCandidate = ObjectUtils.tryCast(declaration.getIterable(), PsiMethodCallExpression.class); if (MAP_ENTRY_SET.test(entrySetCandidate)) { return entrySetCandidate.getMethodExpression().getQualifierExpression(); @@ -115,7 +114,7 @@ public class UseBulkOperationInspection extends AbstractBaseJavaLocalInspectionT int lambdaParametersCount = parameterList.getParametersCount(); if (info.getClassName().equals(CommonClassNames.JAVA_UTIL_MAP)) { if (lambdaParametersCount == 1) { - if (!isGetValueAndGetKey(args, parameters[0])) return null; + if (!isGetKeyAndGetValue(args, parameters[0])) return null; } else if (lambdaParametersCount == 2) { if (!ExpressionUtils.isReferenceTo(args[0], parameters[0]) || !ExpressionUtils.isReferenceTo(args[1], parameters[1])) return null; @@ -124,7 +123,7 @@ public class UseBulkOperationInspection extends AbstractBaseJavaLocalInspectionT return findIterableForFunction(lambda); } - private static boolean isGetValueAndGetKey(PsiExpression[] args, PsiVariable variable) { + private static boolean isGetKeyAndGetValue(PsiExpression[] args, PsiVariable variable) { PsiMethodCallExpression getKeyCandidate = ObjectUtils.tryCast(args[0], PsiMethodCallExpression.class); PsiMethodCallExpression getValueCandidate = ObjectUtils.tryCast(args[1], PsiMethodCallExpression.class); if (!ENTRY_GET_KEY.test(getKeyCandidate) || !ENTRY_GET_VALUE.test(getValueCandidate)) return false; @@ -135,12 +134,13 @@ public class UseBulkOperationInspection extends AbstractBaseJavaLocalInspectionT @Nullable private static PsiExpression findIterableForSingleStatement(PsiStatement statement, PsiExpression[] args) { + assert args.length == 1 || args.length == 2 : "The number of arguments must be either 1 or 2"; PsiElement parent = statement.getParent(); if (parent instanceof PsiForeachStatement) { PsiForeachStatement foreachStatement = (PsiForeachStatement)parent; PsiExpression iteratedValue = foreachStatement.getIteratedValue(); if (args.length == 2) { - if (isGetValueAndGetKey(args, foreachStatement.getIterationParameter())) { + if (isGetKeyAndGetValue(args, foreachStatement.getIterationParameter())) { PsiMethodCallExpression entrySetCandidate = ObjectUtils.tryCast(iteratedValue, PsiMethodCallExpression.class); if (MAP_ENTRY_SET.test(entrySetCandidate)) { return entrySetCandidate.getMethodExpression().getQualifierExpression(); diff --git a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/UseBulkOperationInspectionTest.java b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/UseBulkOperationInspectionTest.java index 68e4849612c4..75dfe460750b 100644 --- a/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/UseBulkOperationInspectionTest.java +++ b/java/java-tests/testSrc/com/intellij/java/codeInsight/daemon/quickFix/UseBulkOperationInspectionTest.java @@ -1,4 +1,4 @@ -// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.java.codeInsight.daemon.quickFix; import com.intellij.codeInsight.daemon.quickFix.LightQuickFixParameterizedTestCase; @@ -7,6 +7,7 @@ import com.intellij.codeInspection.bulkOperation.BulkMethodInfo; import com.intellij.codeInspection.bulkOperation.BulkMethodInfoProvider; import com.intellij.codeInspection.bulkOperation.UseBulkOperationInspection; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.psi.CommonClassNames; import com.intellij.testFramework.ServiceContainerUtil; import org.jetbrains.annotations.NotNull; @@ -19,7 +20,7 @@ public class UseBulkOperationInspectionTest extends LightQuickFixParameterizedTe @NotNull @Override public Stream consumers() { - return Stream.of(new BulkMethodInfo("testpackage.TestClass", "test", "test")); + return Stream.of(new BulkMethodInfo("testpackage.TestClass", "test", "test", CommonClassNames.JAVA_LANG_ITERABLE)); } };