mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-06 03:21:12 +07:00
Fixed unresolved references inspection for fields defined in __new__ (PY-6805)
The inspection may show false negative warnings for assigned attributes of objects other than the return value of __new__.
This commit is contained in:
@@ -95,6 +95,10 @@ __builtin__.next = \
|
||||
:type iterator: collections.Iterator of T \n\
|
||||
:rtype: T \n\
|
||||
|
||||
__builtin__.object.__new__ = \n\
|
||||
:type cls: T \n\
|
||||
:rtype: T \n\
|
||||
|
||||
__builtin__.open = \
|
||||
:type name: string \n\
|
||||
:type mode: string \n\
|
||||
|
||||
@@ -47,7 +47,7 @@ public class PyFileElementType extends IStubFileElementType<PyFileStub> {
|
||||
|
||||
@Override
|
||||
public int getStubVersion() {
|
||||
return 46;
|
||||
return 47;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -913,7 +913,7 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
private List<PyTargetExpression> collectInstanceAttributes() {
|
||||
Map<String, PyTargetExpression> result = new HashMap<String, PyTargetExpression>();
|
||||
|
||||
// __init__ takes priority over all other methods
|
||||
collectAttributesInNew(result);
|
||||
PyFunctionImpl initMethod = (PyFunctionImpl)findMethodByName(PyNames.INIT, false);
|
||||
if (initMethod != null) {
|
||||
collectInstanceAttributes(initMethod, result);
|
||||
@@ -929,6 +929,15 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
|
||||
return new ArrayList<PyTargetExpression>(expressions);
|
||||
}
|
||||
|
||||
private void collectAttributesInNew(@NotNull final Map<String, PyTargetExpression> result) {
|
||||
final PyFunction newMethod = findMethodByName(PyNames.NEW, false);
|
||||
if (newMethod != null) {
|
||||
for (PyTargetExpression target : getTargetExpressions(newMethod)) {
|
||||
result.put(target.getName(), target);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void collectInstanceAttributes(@NotNull PyFunction method, @NotNull final Map<String, PyTargetExpression> result) {
|
||||
final PyParameter[] params = method.getParameterList().getParameters();
|
||||
if (params.length == 0) {
|
||||
|
||||
@@ -182,7 +182,7 @@ public class PyNamedParameterImpl extends PyPresentableElementImpl<PyNamedParame
|
||||
initType = stdlib.getConstructorType(containingClass);
|
||||
}
|
||||
}
|
||||
if (initType != null && !(initType instanceof PyNoneType)) {
|
||||
if (initType != null && !(initType instanceof PyNoneType || initType instanceof PyReturnTypeReference)) {
|
||||
return initType;
|
||||
}
|
||||
return new PyClassTypeImpl(containingClass, modifier == PyFunction.Modifier.CLASSMETHOD);
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.intellij.psi.stubs.StubOutputStream;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.io.StringRef;
|
||||
import com.jetbrains.python.PyElementTypes;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyQualifiedName;
|
||||
import com.jetbrains.python.psi.impl.PyTargetExpressionImpl;
|
||||
@@ -110,6 +111,10 @@ public class PyTargetExpressionElementType extends PyStubElementType<PyTargetExp
|
||||
final ASTNode functionNode = TreeUtil.findParent(node, PyElementTypes.FUNCTION_DECLARATION);
|
||||
final ASTNode qualifierNode = node.findChildByType(PyElementTypes.REFERENCE_EXPRESSION);
|
||||
if (functionNode != null && qualifierNode != null) {
|
||||
final PsiElement function = functionNode.getPsi();
|
||||
if (function instanceof PyFunction && PyNames.NEW.equals(((PyFunction)function).getName())) {
|
||||
return true;
|
||||
}
|
||||
final ASTNode parameterList = functionNode.findChildByType(PyElementTypes.PARAMETER_LIST);
|
||||
assert parameterList != null;
|
||||
final ASTNode[] children = parameterList.getChildren(PyElementTypes.FORMAL_PARAMETER_SET);
|
||||
|
||||
8
python/testData/resolve/AttributeDefinedInNew.py
Normal file
8
python/testData/resolve/AttributeDefinedInNew.py
Normal file
@@ -0,0 +1,8 @@
|
||||
class Test(object):
|
||||
def __new__(cls, foo):
|
||||
x = super(Test, cls).__new__(cls)
|
||||
x.foo = foo
|
||||
return x
|
||||
|
||||
def bar(self):
|
||||
return self.f<ref>oo
|
||||
@@ -0,0 +1,5 @@
|
||||
from a import Test
|
||||
|
||||
x = Test('foo')
|
||||
print(x.foo)
|
||||
# <ref>
|
||||
@@ -0,0 +1,5 @@
|
||||
class Test(object):
|
||||
def __new__(cls, foo):
|
||||
x = super(Test, cls).__new__(cls)
|
||||
x.foo = foo
|
||||
return x
|
||||
@@ -432,6 +432,11 @@ public class PyMultiFileResolveTest extends PyResolveTestCase {
|
||||
assertResolvesTo(PyFunction.class, "foobar");
|
||||
}
|
||||
|
||||
// PY-6805
|
||||
public void testAttributeDefinedInNew() {
|
||||
assertResolvesTo(PyTargetExpression.class, "foo");
|
||||
}
|
||||
|
||||
private void prepareTestDirectory() {
|
||||
final String testName = getTestName(true);
|
||||
myFixture.copyDirectoryToProject(testName, "");
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.intellij.psi.PsiPolyVariantReference;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.ResolveResult;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.fixtures.PyResolveTestCase;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils;
|
||||
@@ -525,4 +527,16 @@ public class PyResolveTest extends PyResolveTestCase {
|
||||
public void testGeneratorShadowing() { // PY-8725
|
||||
assertResolvesTo(PyFunction.class, "_");
|
||||
}
|
||||
|
||||
// PY-6805
|
||||
public void testAttributeDefinedInNew() {
|
||||
final PsiElement resolved = resolve();
|
||||
assertInstanceOf(resolved, PyTargetExpression.class);
|
||||
final PyTargetExpression target = (PyTargetExpression)resolved;
|
||||
assertEquals("foo", target.getName());
|
||||
final ScopeOwner owner = ScopeUtil.getScopeOwner(target);
|
||||
assertNotNull(owner);
|
||||
assertInstanceOf(owner, PyFunction.class);
|
||||
assertEquals("__new__", owner.getName());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user