PY-33218 Match entire tuple type of %-formatting argument to remove dup warnings

This commit is contained in:
Mikhail Golubev
2019-01-09 19:48:39 +03:00
parent 7963a789b0
commit f71913288d
4 changed files with 23 additions and 15 deletions
@@ -79,7 +79,7 @@ public class PyStringFormatInspection extends PyInspection {
private final Visitor myVisitor;
private final TypeEvalContext myTypeEvalContext;
private final Map<String, String> myFormatSpec = new HashMap<>();
private final Map<String, String> myFormatSpec = new LinkedHashMap<>();
Inspection(Visitor visitor, TypeEvalContext typeEvalContext) {
myVisitor = visitor;
@@ -100,14 +100,7 @@ public class PyStringFormatInspection extends PyInspection {
final PyType rightType = myTypeEvalContext.getType(rightExpression);
if (rightType instanceof PyTupleType) {
final PyTupleType tupleType = (PyTupleType)rightType;
for (int i = 0; i < tupleType.getElementCount(); i++) {
final PyType elementType = tupleType.getElementType(i);
if (elementType != null) {
final String typeName = myFormatSpec.get(String.valueOf(i + 1));
final PyType type = typeName != null ? PyTypeParser.getTypeByName(problemTarget, typeName, myTypeEvalContext) : null;
checkTypeCompatible(problemTarget, elementType, type);
}
}
matchEntireTupleTypes(problemTarget, tupleType);
return tupleType.getElementCount();
}
else {
@@ -210,6 +203,22 @@ public class PyStringFormatInspection extends PyInspection {
return -1;
}
private void matchEntireTupleTypes(@NotNull PsiElement rightExpression, PyTupleType rightExpressionType) {
final List<PyType> expectedElementTypes = ContainerUtil.map(myFormatSpec.values(), name -> {
if (name == null) {
return null;
}
final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(rightExpression);
final PyType expected = PyTypeParser.getTypeByName(rightExpression, name, myTypeEvalContext);
if (expected == builtinCache.getStrType()) {
return null;
}
return expected;
});
final PyTupleType expectedTupleType = PyTupleType.create(rightExpression, expectedElementTypes);
checkTypeCompatible(rightExpression, rightExpressionType, expectedTupleType);
}
private static Map<PyExpression, PyExpression> addSubscriptions(PsiFile file, String operand) {
Map<PyExpression, PyExpression> additionalExpressions = new HashMap<>();
Collection<PySubscriptionExpression> subscriptionExpressions = PsiTreeUtil.findChildrenOfType(file, PySubscriptionExpression.class);
@@ -100,9 +100,9 @@ print '%d, %d, %d, %d' % <warning descr="Too few arguments for format string">my
# PY-12801
print '%d %s' % ((42,) + ('spam',))
print '%d %s' % (<warning descr="Unexpected type str">('ham',) + ('spam',)</warning>)
print '%d %s' % (<warning descr="Too few arguments for format string">(42,) + ()</warning>)
print '%d' % (<warning descr="Too many arguments for format string">(42,) + ('spam',)</warning>)
print '%d %s' % (<warning descr="Unexpected type (str, str)">('ham',) + ('spam',)</warning>)
print '%d %s' % (<warning descr="Too few arguments for format string"><warning descr="Unexpected type (int)">(42,) + ()</warning></warning>)
print '%d' % (<warning descr="Too many arguments for format string"><warning descr="Unexpected type (int, str)">(42,) + ('spam',)</warning></warning>)
# PY-11274
import collections
@@ -2,4 +2,4 @@ argument_pattern = re.compile(r'(%s)\s*(\(\s*(%s)\s*\)\s*)?$'
% ((states.Inliner.simplename,) * 2))
t, num = ('foo',), 2
res = '%d %d' % (<warning descr="Unexpected type str"><warning descr="Unexpected type str">t * num</warning></warning>)
res = '%d %d' % (<warning descr="Unexpected type (str, str)">t * num</warning>)
@@ -1,7 +1,6 @@
// Copyright 2000-2017 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.jetbrains.python.inspections;
import com.intellij.testFramework.ExpectedHighlightingData;
import com.jetbrains.python.fixtures.PyInspectionTestCase;
import org.jetbrains.annotations.NotNull;
@@ -20,7 +19,7 @@ public class PyStringFormatInspectionTest extends PyInspectionTestCase {
// PY-4647
public void testTupleMultiplication() {
ExpectedHighlightingData.expectedDuplicatedHighlighting(this::doTest);
doTest();
}
// PY-6756