diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
index 87a35404871d..a1e3adeff626 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/InspectionGadgetsBundle.properties
@@ -1036,6 +1036,7 @@ field.may.be.static.problem.descriptor=Field #ref may be 'static' #
method.may.be.static.problem.descriptor=Method #ref() may be 'static' #loc
class.initializer.may.be.static.problem.descriptor=Class initializer may be 'static' #loc
map.replaceable.by.enum.map.problem.descriptor=#ref replaceable with 'EnumMap' #loc
+map.replaceable.by.enum.map.fix.name=Replace with EnumMap
set.replaceable.by.enum.set.problem.descriptor=#ref replaceable with 'EnumSet' #loc
inner.class.may.be.static.problem.descriptor=Inner class #ref may be 'static' #loc
string.buffer.must.have.initial.capacity.problem.descriptor=new #ref() without initial capacity #loc
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CollectionReplaceableByEnumCollectionVisitor.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CollectionReplaceableByEnumCollectionVisitor.java
index 7b292a8559bf..0bccfe4705b9 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CollectionReplaceableByEnumCollectionVisitor.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/CollectionReplaceableByEnumCollectionVisitor.java
@@ -17,6 +17,7 @@ package com.siyeh.ig.performance;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
import com.siyeh.ig.BaseInspectionVisitor;
import com.siyeh.ig.psiutils.ExpectedTypeUtils;
import com.siyeh.ig.psiutils.TypeUtils;
@@ -24,6 +25,8 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
+import static com.intellij.util.ObjectUtils.tryCast;
+
/**
* @author Bas Leijdekkers
*/
@@ -78,11 +81,24 @@ abstract class CollectionReplaceableByEnumCollectionVisitor extends BaseInspecti
return;
}
}
- if (!expectedType.isAssignableFrom(TypeUtils.getType(getReplacementCollectionName(), expression)) &&
- !isReplaceableType((PsiClassType)expectedType)) {
+ PsiClassType replacementCollectionType = TypeUtils.getType(getReplacementCollectionName(), expression);
+ if (!expectedType.isAssignableFrom(replacementCollectionType) && !isReplaceableType((PsiClassType)expectedType)) {
return;
}
- registerNewExpressionError(expression);
+ PsiElement parent = PsiUtil.skipParenthesizedExprUp(expression).getParent();
+ PsiLocalVariable localVariable = tryCast(parent, PsiLocalVariable.class);
+ if (localVariable != null) {
+ PsiClass localVariableClass = PsiUtil.resolveClassInClassTypeOnly(localVariable.getType());
+ if (localVariableClass != null && getBaseCollectionName().equals(localVariableClass.getQualifiedName())) {
+ registerNewExpressionError(expression, localVariable);
+ }
+ else {
+ registerNewExpressionError(expression);
+ }
+ }
+ else {
+ registerNewExpressionError(expression);
+ }
}
private boolean isReplaceableType(PsiClassType classType) {
diff --git a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java
index 275b359e5212..388dea9f698f 100644
--- a/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java
+++ b/plugins/InspectionGadgets/InspectionGadgetsAnalysis/src/com/siyeh/ig/performance/MapReplaceableByEnumMapInspection.java
@@ -15,15 +15,28 @@
*/
package com.siyeh.ig.performance;
-import com.intellij.psi.CommonClassNames;
+import com.intellij.codeInspection.ProblemDescriptor;
+import com.intellij.openapi.project.Project;
+import com.intellij.psi.*;
+import com.intellij.psi.codeStyle.JavaCodeStyleManager;
+import com.intellij.psi.impl.PsiDiamondTypeUtil;
+import com.intellij.psi.util.PsiTreeUtil;
+import com.intellij.psi.util.PsiUtil;
import com.siyeh.InspectionGadgetsBundle;
import com.siyeh.ig.BaseInspection;
import com.siyeh.ig.BaseInspectionVisitor;
+import com.siyeh.ig.InspectionGadgetsFix;
+import com.siyeh.ig.psiutils.CommentTracker;
+import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.stream.Collectors;
+
+import static com.intellij.util.ObjectUtils.tryCast;
public class MapReplaceableByEnumMapInspection extends BaseInspection {
@@ -44,6 +57,61 @@ public class MapReplaceableByEnumMapInspection extends BaseInspection {
return new MapReplaceableByEnumMapVisitor();
}
+ @Nullable
+ @Override
+ protected InspectionGadgetsFix buildFix(Object... infos) {
+ if (infos.length != 1) return null;
+ PsiLocalVariable localVariable = (PsiLocalVariable)infos[0];
+ PsiExpression initializer = PsiUtil.skipParenthesizedExprDown(localVariable.getInitializer());
+ PsiNewExpression newExpression = tryCast(initializer, PsiNewExpression.class);
+ if (newExpression == null) return null;
+ PsiExpressionList argumentList = newExpression.getArgumentList();
+ if (argumentList == null || !argumentList.isEmpty()) return null;
+ PsiJavaCodeReferenceElement classReference = newExpression.getClassReference();
+ if (classReference == null) return null;
+ PsiReferenceParameterList parameterList = classReference.getParameterList();
+ if (parameterList == null) return null;
+ PsiClassType classType = tryCast(newExpression.getType(), PsiClassType.class);
+ if (classType == null) return null;
+ if (classType.getParameterCount() != 2) return null;
+ PsiType[] parameters = classType.getParameters();
+ PsiType enumParameter = parameters[0];
+ String parameterListText = Arrays.stream(parameters).map(p -> p.getCanonicalText()).collect(Collectors.joining(",", "<", ">"));
+ PsiClass probablyEnum = PsiUtil.resolveClassInClassTypeOnly(enumParameter);
+ if (probablyEnum == null || !probablyEnum.isEnum()) return null;
+ String text = "new java.util.EnumMap" + parameterListText + "(" + enumParameter.getCanonicalText() + ".class)";
+ return new EnumMapReplacingFix(text);
+ }
+
+ private static class EnumMapReplacingFix extends InspectionGadgetsFix {
+ private final String newEnumMapText;
+
+ private EnumMapReplacingFix(String text) {newEnumMapText = text;}
+
+ @Override
+ protected void doFix(Project project, ProblemDescriptor descriptor) {
+ PsiNewExpression newExpression = PsiTreeUtil.getParentOfType(descriptor.getStartElement(), PsiNewExpression.class);
+ if (newExpression == null) return;
+ PsiElement result = new CommentTracker().replaceAndRestoreComments(newExpression, newEnumMapText);
+ PsiDiamondTypeUtil.removeRedundantTypeArguments(result);
+ JavaCodeStyleManager.getInstance(project).shortenClassReferences(result);
+ }
+
+ @Nls(capitalization = Nls.Capitalization.Sentence)
+ @NotNull
+ @Override
+ public String getName() {
+ return getFamilyName();
+ }
+
+ @Nls(capitalization = Nls.Capitalization.Sentence)
+ @NotNull
+ @Override
+ public String getFamilyName() {
+ return InspectionGadgetsBundle.message("map.replaceable.by.enum.map.fix.name");
+ }
+ }
+
private static class MapReplaceableByEnumMapVisitor extends CollectionReplaceableByEnumCollectionVisitor {
@Override
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/map_replaceable_with_enum_map/Simple.after.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/map_replaceable_with_enum_map/Simple.after.java
new file mode 100644
index 000000000000..3f64f127c920
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/map_replaceable_with_enum_map/Simple.after.java
@@ -0,0 +1,11 @@
+import java.util.EnumMap;
+import java.util.HashMap;
+import java.util.Map;
+
+class EnumTest {
+ enum A {foo, bar;}
+
+ void foo() {
+ Map m = new EnumMap<>(A.class);
+ }
+}
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/map_replaceable_with_enum_map/Simple.java b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/map_replaceable_with_enum_map/Simple.java
new file mode 100644
index 000000000000..f68ecdca3421
--- /dev/null
+++ b/plugins/InspectionGadgets/test/com/siyeh/igfixes/performance/map_replaceable_with_enum_map/Simple.java
@@ -0,0 +1,10 @@
+import java.util.HashMap;
+import java.util.Map;
+
+class EnumTest {
+ enum A {foo, bar;}
+
+ void foo() {
+ Map m = new HashMap<>();
+ }
+}
\ No newline at end of file
diff --git a/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/MapReplaceableByEnumMapFixTest.java b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/MapReplaceableByEnumMapFixTest.java
new file mode 100644
index 000000000000..38a6f30990c5
--- /dev/null
+++ b/plugins/InspectionGadgets/testsrc/com/siyeh/ig/fixes/performance/MapReplaceableByEnumMapFixTest.java
@@ -0,0 +1,34 @@
+// Copyright 2000-2018 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.
+package com.siyeh.ig.fixes.performance;
+
+import com.siyeh.InspectionGadgetsBundle;
+import com.siyeh.ig.IGQuickFixesTestCase;
+import com.siyeh.ig.performance.MapReplaceableByEnumMapInspection;
+
+public class MapReplaceableByEnumMapFixTest extends IGQuickFixesTestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ myFixture.enableInspections(new MapReplaceableByEnumMapInspection());
+ myRelativePath = "performance/map_replaceable_with_enum_map";
+ myDefaultHint = InspectionGadgetsBundle.message("map.replaceable.by.enum.map.fix.name");
+ myFixture.addClass("package java.util;\n" +
+ "\n" +
+ "public class EnumMap, V> extends AbstractMap\n" +
+ " implements java.io.Serializable, Cloneable\n" +
+ "{\n" +
+ " public EnumMap(Class keyType) {\n" +
+ " \n" +
+ " }\n" +
+ "}");
+
+ }
+
+
+ public void testSimple() {
+ doTest();
+ }
+
+
+}
\ No newline at end of file