From 7d99b930a375c7b6fd80e592698b0cd4c0775a62 Mon Sep 17 00:00:00 2001 From: Semyon Proshev Date: Tue, 30 May 2017 16:52:45 +0300 Subject: [PATCH] PY-23623 Fixed: False positive: __getitem__ not being defined for list after isinstance check While calculating severity, we infer type for qualifier in `v[0]` subscription expression. While inferring type for qualifier, we infer type for `test_if_list` function. While inferring type for `test_if_list` function, we infer `Any` type for `v` in `v[0]` to prevent recursion and resolve `[]` to nothing. Unresolved `[]` is cached so when we ask for `[]` on `v[0]`, we receive nothing but at this moment we know type of `v` (`List[Any]`). --- .../PyUnresolvedReferencesInspection.java | 13 ++++++------- .../cachedOperatorInRecursivelyTypeInference.py | 9 +++++++++ .../PyUnresolvedReferencesInspectionTest.java | 5 +++++ 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/cachedOperatorInRecursivelyTypeInference.py diff --git a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java index bed07197dc2a..87c8e92a91eb 100644 --- a/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/unresolvedReference/PyUnresolvedReferencesInspection.java @@ -356,12 +356,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (!isEnabled(node) || reference == null || reference.isSoft()) { return; } - HighlightSeverity severity = HighlightSeverity.ERROR; - if (reference instanceof PsiReferenceEx) { - severity = ((PsiReferenceEx)reference).getUnresolvedHighlightSeverity(myTypeEvalContext); - if (severity == null) return; - } - PyExceptPart guard = getImportErrorGuard(node); + final PyExceptPart guard = getImportErrorGuard(node); if (guard != null) { processReferenceInImportGuard(node, guard); return; @@ -375,7 +370,7 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } } PsiElement target = null; - boolean unresolved; + final boolean unresolved; if (reference instanceof PsiPolyVariantReference) { final PsiPolyVariantReference poly = (PsiPolyVariantReference)reference; final ResolveResult[] resolveResults = poly.multiResolve(false); @@ -405,6 +400,10 @@ public class PyUnresolvedReferencesInspection extends PyInspection { } } if (!ignoreUnresolved) { + final HighlightSeverity severity = reference instanceof PsiReferenceEx + ? ((PsiReferenceEx)reference).getUnresolvedHighlightSeverity(myTypeEvalContext) + : HighlightSeverity.ERROR; + if (severity == null) return; registerUnresolvedReferenceProblem(node, reference, severity); } // don't highlight unresolved imports as unused diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/cachedOperatorInRecursivelyTypeInference.py b/python/testData/inspections/PyUnresolvedReferencesInspection/cachedOperatorInRecursivelyTypeInference.py new file mode 100644 index 000000000000..8658b4bb88eb --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/cachedOperatorInRecursivelyTypeInference.py @@ -0,0 +1,9 @@ +def test_if_list(value): + if isinstance(value, list): + v = [test_if_list(x) for x in value] + if len(v) > 1: + return v + else: + return v[0] + + return value \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 69f109d56ca9..0777b4ea01db 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -603,6 +603,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-23623 + public void testCachedOperatorInRecursivelyTypeInference() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() {