diff --git a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java index 5e2a0b028512..7a81cffa6c10 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java +++ b/python/psi-api/src/com/jetbrains/python/psi/impl/PyPsiUtils.java @@ -373,6 +373,11 @@ public class PyPsiUtils { return expression instanceof PyStringLiteralExpression ? ((PyStringLiteralExpression)expression).getStringValue() : null; } + public static boolean isBefore(@NotNull final PsiElement element, @NotNull final PsiElement element2) { + // TODO: From RubyPsiUtil, should be moved to PsiTreeUtil + return element.getTextOffset() <= element2.getTextOffset(); + } + private static abstract class TopLevelVisitor extends PyRecursiveElementVisitor { public void visitPyElement(final PyElement node) { super.visitPyElement(node); diff --git a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index b532f27a348e..42cf1af99b7f 100644 --- a/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -227,6 +227,19 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference else if (owner == originalOwner && !scope.isGlobal(referencedName)) { final ResolveResultList latest = resolveToLatestDefs(owner, myElement, referencedName); if (!latest.isEmpty()) { + if (myElement instanceof PyTargetExpression) { + final RatedResolveResult result = latest.get(0); + final PsiElement element = result.getElement(); + if (element instanceof PyTargetExpression) { + if (PyPsiUtils.isBefore(element, myElement)) { + return latest; + } + else { + ret.poke(myElement, getRate(myElement)); + return ret; + } + } + } return latest; } if (owner instanceof PyClass) { diff --git a/python/testData/resolve/LoopToLowerReassignment.py b/python/testData/resolve/LoopToLowerReassignment.py new file mode 100644 index 000000000000..6f592d38c8be --- /dev/null +++ b/python/testData/resolve/LoopToLowerReassignment.py @@ -0,0 +1,5 @@ +def f(): + while True: + foo = 1 +# + foo = 2 diff --git a/python/testData/resolve/LoopToUpperReassignment.py b/python/testData/resolve/LoopToUpperReassignment.py new file mode 100644 index 000000000000..4fde5c18ffec --- /dev/null +++ b/python/testData/resolve/LoopToUpperReassignment.py @@ -0,0 +1,5 @@ +def f(): + while True: + foo = 1 + foo = 2 +# diff --git a/python/testSrc/com/jetbrains/python/PyResolveTest.java b/python/testSrc/com/jetbrains/python/PyResolveTest.java index 505fdc335b1f..c973512352c3 100644 --- a/python/testSrc/com/jetbrains/python/PyResolveTest.java +++ b/python/testSrc/com/jetbrains/python/PyResolveTest.java @@ -7,6 +7,7 @@ import com.intellij.psi.ResolveResult; import com.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.fixtures.PyResolveTestCase; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyPsiUtils; import com.jetbrains.python.psi.impl.PythonLanguageLevelPusher; import com.jetbrains.python.psi.resolve.ImportedResolveResult; @@ -483,4 +484,23 @@ public class PyResolveTest extends PyResolveTestCase { public void testReferenceInDocstring() { assertResolvesTo(PyClass.class, "datetime"); } + + // PY-7541 + public void testLoopToUpperReassignment() { + final PsiReference ref = findReferenceByMarker(); + final PsiElement source = ref.getElement(); + final PsiElement target = ref.resolve(); + assertNotNull(target); + assertTrue(source != target); + assertTrue(PyPsiUtils.isBefore(target, source)); + } + + // PY-7541 + public void testLoopToLowerReassignment() { + final PsiReference ref = findReferenceByMarker(); + final PsiElement source = ref.getElement(); + final PsiElement target = ref.resolve(); + assertNotNull(target); + assertTrue(source == target); + } }