PY-50788: Correct resolve for inherited docstring attribute names
authorIrina.Fediaeva <irina.fediaeva@jetbrains.com>
Sat, 24 Sep 2022 14:58:29 +0000 (17:58 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Mon, 3 Oct 2022 13:21:34 +0000 (13:21 +0000)
Now during resolve if there is no class/instance attribute with appropriate name explicitly in the class, we will try to find it in the parent classes and resolve there.

GitOrigin-RevId: 52ab5f0ad63cba187457ba3db6107997ede33dee

python/python-common-tests/com/jetbrains/python/PyCommonResolveTest.java
python/python-psi-impl/src/com/jetbrains/python/documentation/docstrings/DocStringParameterReference.java
python/testData/resolve/NumpyDocstringAttributeNameResolvesToInheritedClassAttribute.py [new file with mode: 0644]
python/testData/resolve/NumpyDocstringAttributeNameResolvesToInheritedInstanceAttribute.py [new file with mode: 0644]
python/testData/resolve/RestDocstringCvarNameResolvesToInheritedClassAttribute.py [new file with mode: 0644]
python/testData/resolve/RestDocstringIvarNameResolvesToInheritedInstanceAttribute.py [new file with mode: 0644]
python/testData/resolve/RestDocstringVarNameResolvesToInheritedClassAttribute.py [new file with mode: 0644]
python/testData/resolve/RestDocstringVarNameResolvesToInheritedInstanceAttribute.py [new file with mode: 0644]

index 11798a0d39f6d97154260da97386936634d1b3b1..d779cfcedd41720e0dbffaddb9eab606cf5de869 100644 (file)
@@ -1667,4 +1667,34 @@ public abstract class PyCommonResolveTest extends PyCommonResolveTestCase {
   public void testRestDocstringIvarNameResolvesToDataClassAttribute() {
     runWithDocStringFormat(DocStringFormat.REST, () -> assertResolvesTo(PyTargetExpression.class, "var1"));
   }
+
+  // PY-50788
+  public void testRestDocstringIvarNameResolvesToInheritedInstanceAttribute() {
+    runWithDocStringFormat(DocStringFormat.REST, () -> assertResolvesTo(PyTargetExpression.class, "attr"));
+  }
+
+  // PY-50788
+  public void testRestDocstringVarNameResolvesToInheritedInstanceAttribute() {
+    runWithDocStringFormat(DocStringFormat.REST, () -> assertResolvesTo(PyTargetExpression.class, "attr"));
+  }
+
+  // PY-50788
+  public void testRestDocstringVarNameResolvesToInheritedClassAttribute() {
+    runWithDocStringFormat(DocStringFormat.REST, () -> assertResolvesTo(PyTargetExpression.class, "attr"));
+  }
+
+  // PY-50788
+  public void testRestDocstringCvarNameResolvesToInheritedClassAttribute() {
+    runWithDocStringFormat(DocStringFormat.REST, () -> assertResolvesTo(PyTargetExpression.class, "attr"));
+  }
+
+  // PY-50788
+  public void testNumpyDocstringAttributeNameResolvesToInheritedInstanceAttribute() {
+    runWithDocStringFormat(DocStringFormat.NUMPY, () -> assertResolvesTo(PyTargetExpression.class, "bar"));
+  }
+
+  // PY-50788
+  public void testNumpyDocstringAttributeNameResolvesToInheritedClassAttribute() {
+    runWithDocStringFormat(DocStringFormat.NUMPY, () -> assertResolvesTo(PyTargetExpression.class, "bar"));
+  }
 }
index 4891dd9b931c14f676c6e46dd58776ae8197e5d8..a8dbbea81fe95f3b93de940b5b90a3a22fc81411 100644 (file)
@@ -37,8 +37,7 @@ public class DocStringParameterReference extends PsiReferenceBase<PyStringLitera
     if (owner instanceof PyFunction) {
       return resolveParameter((PyFunction)owner);
     }
-    if (owner instanceof PyClass) {
-      PyClass pyClass = (PyClass)owner;
+    if (owner instanceof PyClass pyClass) {
       final PyFunction init = pyClass.findMethodByName(PyNames.INIT, false, null);
       if (myType == ReferenceType.PARAMETER) {
         return init != null ? resolveParameter(init) : resolveClassVariable(pyClass);
@@ -50,7 +49,7 @@ public class DocStringParameterReference extends PsiReferenceBase<PyStringLitera
             return parameter;
           }
         }
-        PyElement instanceAttr = resolveInstanceVariable(pyClass);
+        final PyElement instanceAttr = resolveInstanceVariable(pyClass);
         return instanceAttr != null ? instanceAttr : resolveClassVariable(pyClass);
       }
       if (myType == ReferenceType.CLASS_VARIABLE) {
@@ -74,25 +73,13 @@ public class DocStringParameterReference extends PsiReferenceBase<PyStringLitera
   }
 
   @Nullable
-  private PyTargetExpression resolveInstanceVariable(final PyClass owner) {
-    final List<PyTargetExpression> attributes = owner.getInstanceAttributes();
-    for (PyTargetExpression element : attributes) {
-      if (getCanonicalText().equals(element.getName())) {
-        return element;
-      }
-    }
-    return null;
+  private PyTargetExpression resolveInstanceVariable(@NotNull PyClass owner) {
+    return owner.findInstanceAttribute(getCanonicalText(), true);
   }
 
   @Nullable
-  private PyTargetExpression resolveClassVariable(@NotNull final PyClass owner) {
-    final List<PyTargetExpression> attributes = owner.getClassAttributes();
-    for (PyTargetExpression element : attributes) {
-      if (getCanonicalText().equals(element.getName())) {
-        return element;
-      }
-    }
-    return null;
+  private PyTargetExpression resolveClassVariable(@NotNull PyClass owner) {
+    return owner.findClassAttribute(getCanonicalText(), true, null);
   }
 
   @Nullable
diff --git a/python/testData/resolve/NumpyDocstringAttributeNameResolvesToInheritedClassAttribute.py b/python/testData/resolve/NumpyDocstringAttributeNameResolvesToInheritedClassAttribute.py
new file mode 100644 (file)
index 0000000..63f5ca2
--- /dev/null
@@ -0,0 +1,19 @@
+class Foo:
+    """
+    Attributes
+    ----------
+    bar
+        Something cool
+    """
+
+    bar = 1
+
+
+class Baz(Foo):
+    """
+    Attributes
+    ----------
+    bar
+    <ref>
+        Re-documented but does exist still.
+    """
\ No newline at end of file
diff --git a/python/testData/resolve/NumpyDocstringAttributeNameResolvesToInheritedInstanceAttribute.py b/python/testData/resolve/NumpyDocstringAttributeNameResolvesToInheritedInstanceAttribute.py
new file mode 100644 (file)
index 0000000..2576cc9
--- /dev/null
@@ -0,0 +1,20 @@
+class Foo:
+    """
+    Attributes
+    ----------
+    bar
+        Something cool
+    """
+
+    def __init__(self):
+        self.bar = 1
+
+
+class Baz(Foo):
+    """
+    Attributes
+    ----------
+    bar
+    <ref>
+        Re-documented but does exist still.
+    """
\ No newline at end of file
diff --git a/python/testData/resolve/RestDocstringCvarNameResolvesToInheritedClassAttribute.py b/python/testData/resolve/RestDocstringCvarNameResolvesToInheritedClassAttribute.py
new file mode 100644 (file)
index 0000000..188853e
--- /dev/null
@@ -0,0 +1,12 @@
+class Parent:
+    """
+    :cvar attr: parent attr doc
+    """
+    attr = 0
+
+
+class Child(Parent):
+    """
+    :cvar attr: child attr doc
+          <ref>
+    """
diff --git a/python/testData/resolve/RestDocstringIvarNameResolvesToInheritedInstanceAttribute.py b/python/testData/resolve/RestDocstringIvarNameResolvesToInheritedInstanceAttribute.py
new file mode 100644 (file)
index 0000000..766651f
--- /dev/null
@@ -0,0 +1,13 @@
+class Parent:
+    """
+    :ivar attr: parent attr doc
+    """
+    def __init__(self):
+        self.attr = 0
+
+
+class Child(Parent):
+    """
+    :ivar attr: child attr doc
+          <ref>
+    """
\ No newline at end of file
diff --git a/python/testData/resolve/RestDocstringVarNameResolvesToInheritedClassAttribute.py b/python/testData/resolve/RestDocstringVarNameResolvesToInheritedClassAttribute.py
new file mode 100644 (file)
index 0000000..65ce2b4
--- /dev/null
@@ -0,0 +1,12 @@
+class Parent:
+    """
+    :var attr: parent attr doc
+    """
+    attr = 0
+
+
+class Child(Parent):
+    """
+    :var attr: child attr doc
+         <ref>
+    """
diff --git a/python/testData/resolve/RestDocstringVarNameResolvesToInheritedInstanceAttribute.py b/python/testData/resolve/RestDocstringVarNameResolvesToInheritedInstanceAttribute.py
new file mode 100644 (file)
index 0000000..29bff46
--- /dev/null
@@ -0,0 +1,13 @@
+class Parent:
+    """
+    :var attr: parent attr doc
+    """
+    def __init__(self):
+        self.attr = 0
+
+
+class Child(Parent):
+    """
+    :var attr: child attr doc
+         <ref>
+    """
\ No newline at end of file