diff --git a/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java b/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java index 20232dcddc7b..f2dea24b49a5 100644 --- a/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyDictDuplicateKeysInspection.java @@ -22,6 +22,7 @@ import com.intellij.lang.ASTNode; import com.intellij.openapi.util.Pair; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; +import com.intellij.util.containers.MultiMap; import com.jetbrains.python.PyBundle; import com.jetbrains.python.inspections.quickfix.PyRemoveDictKeyQuickFix; import com.jetbrains.python.psi.*; @@ -32,7 +33,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.math.BigDecimal; -import java.util.HashMap; +import java.util.Collection; import java.util.Map; /** @@ -66,29 +67,42 @@ public class PyDictDuplicateKeysInspection extends PyInspection { public void visitPyDictLiteralExpression(@NotNull PyDictLiteralExpression node) { if (node.isEmpty()) return; - final Map map = new HashMap<>(); + final MultiMap keyValueAndKeys = new MultiMap<>(); for (PyKeyValueExpression element : node.getElements()) { - checkKey(map, getDictLiteralKey(element), new PyRemoveDictKeyQuickFix()); + final Pair keyAndValue = getDictLiteralKey(element); + if (keyAndValue != null) { + keyValueAndKeys.putValue(keyAndValue.second, keyAndValue.first); + } } + + registerProblems(keyValueAndKeys, new PyRemoveDictKeyQuickFix()); } @Override public void visitPyCallExpression(@NotNull PyCallExpression node) { if (!isDict(node)) return; - final Map map = new HashMap<>(); + final MultiMap keyValueAndKeys = new MultiMap<>(); for (PyExpression argument : node.getArguments()) { argument = PyPsiUtils.flattenParens(argument); if (argument instanceof PySequenceExpression) { for (PyExpression element : ((PySequenceExpression)argument).getElements()) { - checkKey(map, getDictCallKey(element)); + final Pair keyAndValue = getDictCallKey(element); + if (keyAndValue != null) { + keyValueAndKeys.putValue(keyAndValue.second, keyAndValue.first); + } } } else if (argument instanceof PyKeywordArgument) { - checkKey(map, getDictCallKey(argument)); + final Pair keyAndValue = getDictCallKey(argument); + if (keyAndValue != null) { + keyValueAndKeys.putValue(keyAndValue.second, keyAndValue.first); + } } } + + registerProblems(keyValueAndKeys); } @Nullable @@ -118,19 +132,17 @@ public class PyDictDuplicateKeysInspection extends PyInspection { return node instanceof PyLiteralExpression || node instanceof PyReferenceExpression ? node.getText() : null; } - private void checkKey(@NotNull Map map, - @Nullable Pair keyAndValue, - @NotNull LocalQuickFix... quickFixes) { - if (keyAndValue == null) return; + private void registerProblems(@NotNull MultiMap keyValueAndKeys, @NotNull LocalQuickFix... quickFixes) { + for (Map.Entry> entry : keyValueAndKeys.entrySet()) { + final String keyValue = entry.getKey(); + final Collection keys = entry.getValue(); - final PsiElement key = keyAndValue.first; - final String keyValue = keyAndValue.second; - - if (map.containsKey(keyValue)) { - registerProblem(key, "Dictionary contains duplicate keys '" + keyValue + "'", quickFixes); - registerProblem(map.get(keyValue), "Dictionary contains duplicate keys '" + keyValue + "'", quickFixes); + if (keys.size() > 1) { + for (PsiElement key : keys) { + registerProblem(key, "Dictionary contains duplicate keys '" + keyValue + "'", quickFixes); + } + } } - map.put(keyValue, key); } @Nullable diff --git a/python/testData/inspections/PyDictDuplicateKeysInspection/test.py b/python/testData/inspections/PyDictDuplicateKeysInspection/test.py index ac2066177e57..7b920828d6af 100644 --- a/python/testData/inspections/PyDictDuplicateKeysInspection/test.py +++ b/python/testData/inspections/PyDictDuplicateKeysInspection/test.py @@ -33,4 +33,10 @@ d = {11: 1, < d = {11.1: 1, 1_1.1: 1} d = {11j: 1, 1_1j: 1} d = {11j: 1, 11: 1} -d = {0j: 1, 0: 2} \ No newline at end of file +d = {0j: 1, 0: 2} + +{ + 'a': 1, + 'a': 2, + 'a': 3, +} \ No newline at end of file