diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java index 2d27e6787958..e7e3a3fb84ff 100644 --- a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java @@ -277,39 +277,49 @@ public class PyStringFormatInspection extends PyInspection { return 0; } } + int referenceKeyNumber = 0; for (PyKeyValueExpression expression : expressions) { final PyExpression key = expression.getKey(); + final PyExpression value = expression.getValue(); if (key instanceof PyStringLiteralExpression) { - final String name = ((PyStringLiteralExpression)key).getStringValue(); - if (myUsedMappingKeys.get(name) != null) { - myUsedMappingKeys.put(name, true); - final PyExpression value = expression.getValue(); - if (value != null) { - checkExpressionType(value, myFormatSpec.get(name), problemTarget); - } - } + resolveMappingKey(problemTarget, (PyStringLiteralExpression)key, value); + } + else if (key instanceof PyReferenceExpression) { + referenceKeyNumber ++; } } for (Map.Entry expression : additionalExpressions.entrySet()) { final PyExpression key = expression.getKey(); + final PyExpression value = expression.getValue(); if (key instanceof PyStringLiteralExpression) { - final String name = ((PyStringLiteralExpression)key).getStringValue(); - if (myUsedMappingKeys.get(name) != null) { - myUsedMappingKeys.put(name, true); - final PyExpression value = expression.getValue(); - if (value != null) { - checkExpressionType(value, myFormatSpec.get(name), problemTarget); - } + resolveMappingKey(problemTarget, (PyStringLiteralExpression)key, value); + } + else if (key instanceof PyReferenceExpression) { + referenceKeyNumber ++; + } + } + + int unresolved = 0; + for (String key : myUsedMappingKeys.keySet()) { + if (!myUsedMappingKeys.get(key).booleanValue()) { + unresolved++; + if (unresolved > referenceKeyNumber) { + registerProblem(problemTarget, PyBundle.message("INSP.key.$0.has.no.arg", key)); + break; } } } - for (String key : myUsedMappingKeys.keySet()) { - if (!myUsedMappingKeys.get(key).booleanValue()) { - registerProblem(problemTarget, PyBundle.message("INSP.key.$0.has.no.arg", key)); - break; + return (expressions.length + additionalExpressions.size()); + } + + private void resolveMappingKey(PsiElement problemTarget, PyStringLiteralExpression key, PyExpression value) { + final String name = key.getStringValue(); + if (myUsedMappingKeys.get(name) != null) { + myUsedMappingKeys.put(name, true); + if (value != null) { + checkExpressionType(value, myFormatSpec.get(name), problemTarget); } } - return (expressions.length + additionalExpressions.size()); } private void registerProblem(@NotNull PsiElement problemTarget, @NotNull final String message, @NotNull LocalQuickFix quickFix) { diff --git a/python/testData/inspections/PyStringFormatInspection/DictionaryArgument.py b/python/testData/inspections/PyStringFormatInspection/DictionaryArgument.py index 432540418308..b0caa8f13267 100644 --- a/python/testData/inspections/PyStringFormatInspection/DictionaryArgument.py +++ b/python/testData/inspections/PyStringFormatInspection/DictionaryArgument.py @@ -10,3 +10,10 @@ my_dict['tmp'] = 'classes %(claz)s' %