PY-50788: Correct resolve for inherited docstring attribute names

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
This commit is contained in:
Irina.Fediaeva
2022-09-24 17:58:29 +03:00
committed by intellij-monorepo-bot
parent 50a0dbc592
commit 181edc5caa
8 changed files with 125 additions and 19 deletions

View 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"));
}
}

View 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

View File

@@ -0,0 +1,19 @@
class Foo:
"""
Attributes
----------
bar
Something cool
"""
bar = 1
class Baz(Foo):
"""
Attributes
----------
bar
<ref>
Re-documented but does exist still.
"""

View File

@@ -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.
"""

View File

@@ -0,0 +1,12 @@
class Parent:
"""
:cvar attr: parent attr doc
"""
attr = 0
class Child(Parent):
"""
:cvar attr: child attr doc
<ref>
"""

View File

@@ -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>
"""

View File

@@ -0,0 +1,12 @@
class Parent:
"""
:var attr: parent attr doc
"""
attr = 0
class Child(Parent):
"""
:var attr: child attr doc
<ref>
"""

View File

@@ -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>
"""