From f71913288de80301ae3a248cca413e5c905c96c9 Mon Sep 17 00:00:00 2001 From: Mikhail Golubev Date: Mon, 17 Dec 2018 22:09:19 +0700 Subject: [PATCH] PY-33218 Match entire tuple type of %-formatting argument to remove dup warnings --- .../inspections/PyStringFormatInspection.java | 27 ++++++++++++------- .../PyStringFormatInspection/Basic.py | 6 ++--- .../TupleMultiplication.py | 2 +- .../PyStringFormatInspectionTest.java | 3 +-- 4 files changed, 23 insertions(+), 15 deletions(-) diff --git a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java index e7d0d4ed01b7..1242ad237a76 100644 --- a/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyStringFormatInspection.java @@ -79,7 +79,7 @@ public class PyStringFormatInspection extends PyInspection { private final Visitor myVisitor; private final TypeEvalContext myTypeEvalContext; - private final Map myFormatSpec = new HashMap<>(); + private final Map 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 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 addSubscriptions(PsiFile file, String operand) { Map additionalExpressions = new HashMap<>(); Collection subscriptionExpressions = PsiTreeUtil.findChildrenOfType(file, PySubscriptionExpression.class); diff --git a/python/testData/inspections/PyStringFormatInspection/Basic.py b/python/testData/inspections/PyStringFormatInspection/Basic.py index ad6559fd78f5..364a32cc7150 100644 --- a/python/testData/inspections/PyStringFormatInspection/Basic.py +++ b/python/testData/inspections/PyStringFormatInspection/Basic.py @@ -100,9 +100,9 @@ print '%d, %d, %d, %d' % my # PY-12801 print '%d %s' % ((42,) + ('spam',)) -print '%d %s' % (('ham',) + ('spam',)) -print '%d %s' % ((42,) + ()) -print '%d' % ((42,) + ('spam',)) +print '%d %s' % (('ham',) + ('spam',)) +print '%d %s' % ((42,) + ()) +print '%d' % ((42,) + ('spam',)) # PY-11274 import collections diff --git a/python/testData/inspections/PyStringFormatInspection/TupleMultiplication.py b/python/testData/inspections/PyStringFormatInspection/TupleMultiplication.py index 616ea22ef9d5..c1926917f912 100644 --- a/python/testData/inspections/PyStringFormatInspection/TupleMultiplication.py +++ b/python/testData/inspections/PyStringFormatInspection/TupleMultiplication.py @@ -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' % (t * num) +res = '%d %d' % (t * num) diff --git a/python/testSrc/com/jetbrains/python/inspections/PyStringFormatInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyStringFormatInspectionTest.java index f9ebaf86dff4..7b49980e1c9c 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyStringFormatInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyStringFormatInspectionTest.java @@ -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