From f73ae3f9bf784d6470249adaf57b04cf624438df Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Fri, 22 May 2015 13:07:48 +0200 Subject: [PATCH] Fixed unresolved reference for parameters which methods are invoked inside the function body (PY-11541) We may get stuck in a recursive resolve loop (that results in unresolved references) if we match arguments to parameters for a call where the callee is a reference to the named parameter itself. The loop used to go like this: 1. Get the type of 'foo.bar' in 'foo.bar(foo)' 2. Get the type of 'foo' in 'def f(foo)' 3. Find the structural type for 'foo' 4. Ask nested calls where 'foo' is a parameter 5. Try to match args to params in 'foo.bar(foo)' 6. Resolve 'foo.bar' 7. Get the type of 'foo.bar' in 'foo.bar(foo') 8. Since the 'foo.bar' is evaluating, it's 'null' for preventing recursion 9. So 'foo.bar' resolves to 'null' which is false --- .../python/psi/impl/PyNamedParameterImpl.java | 28 +++++++++++++++---- .../baseStringCheck.py | 4 +++ .../PyUnresolvedReferencesInspectionTest.java | 5 ++++ 3 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 python/testData/inspections/PyUnresolvedReferencesInspection/baseStringCheck.py diff --git a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java index 7c89a1c4770c..76e96692194c 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyNamedParameterImpl.java @@ -349,11 +349,29 @@ public class PyNamedParameterImpl extends PyBaseElementImpl entry : mapping.getPlainMappedParams().entrySet()) { diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/baseStringCheck.py b/python/testData/inspections/PyUnresolvedReferencesInspection/baseStringCheck.py new file mode 100644 index 000000000000..a91281d759d6 --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/baseStringCheck.py @@ -0,0 +1,4 @@ +def repl(s): + if not isinstance(s, basestring): + return s + return s.replace(s.replace('a', 'b'), s) diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java index 5981c6b74767..1499084c4def 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnresolvedReferencesInspectionTest.java @@ -505,6 +505,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyInspectionTestCase { doTest(); } + // PY-11541 + public void testBaseStringCheck() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() {