From 0c54074d30e73f040f4592dad072d8b545ec24e0 Mon Sep 17 00:00:00 2001 From: "Aleksandr.Govenko" Date: Thu, 20 Feb 2025 19:19:41 +0000 Subject: [PATCH] PY-26947 Class variable mistaken as module global variable Prevent resolving class-level target expressions in global scope. Merge-request: IJ-MR-155098 Merged-by: Aleksandr Govenko GitOrigin-RevId: 2452801387ee2480e61b2f5119e7f3f2704cb4ef --- .../com/jetbrains/python/PyCommonResolveTest.java | 9 +++++++++ .../python/psi/impl/references/PyReferenceImpl.java | 2 +- .../VariableDeclaredOnClassLevelResolvesOnlyToItself.py | 5 +++++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 python/testData/resolve/VariableDeclaredOnClassLevelResolvesOnlyToItself.py diff --git a/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java b/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java index 2b9e7af91279..b64308914e18 100644 --- a/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java +++ b/python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java @@ -1419,6 +1419,15 @@ public abstract class PyCommonResolveTest extends PyCommonResolveTestCase { assertEquals("global", ((PyStringLiteralExpression)value).getStringValue()); } + // PY-26947 + public void testVariableDeclaredOnClassLevelResolvesOnlyToItself() { + final PyTargetExpression foo = assertResolvesTo(PyTargetExpression.class, "foo"); + + final PyExpression value = foo.findAssignedValue(); + assertInstanceOf(value, PyStringLiteralExpression.class); + assertEquals("correct", ((PyStringLiteralExpression)value).getStringValue()); + } + // PY-29975 public void testUnboundVariableOnClassLevelNotDeclaredBelow() { assertResolvesTo(PyNamedParameter.class, "foo"); diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java index 6224f2952453..f18f305b067b 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/references/PyReferenceImpl.java @@ -256,7 +256,7 @@ public class PyReferenceImpl implements PsiReferenceEx, PsiPolyVariantReference }) .toImmutableList(); } - else if (resolvedOwner instanceof PyClass) { + else if (resolvedOwner instanceof PyClass && !(referenceAnchor instanceof PyTargetExpression)) { resolveInParentScope = () -> PyResolveUtil.parentScopeForUnresolvedClassLevelName((PyClass)resolvedOwner, referencedName); } else if (instructions.isEmpty() && allInOwnScopeComprehensions(resolvedElements)) { diff --git a/python/testData/resolve/VariableDeclaredOnClassLevelResolvesOnlyToItself.py b/python/testData/resolve/VariableDeclaredOnClassLevelResolvesOnlyToItself.py new file mode 100644 index 000000000000..ece8e7ee3bb5 --- /dev/null +++ b/python/testData/resolve/VariableDeclaredOnClassLevelResolvesOnlyToItself.py @@ -0,0 +1,5 @@ +foo = 'incorrect' + +class A: + foo = 'correct' + # \ No newline at end of file