PY-22037 Fixed: Code completion on property that returns self declared in base class only shows options for base class

Pass receiver to Property.getType
This commit is contained in:
Semyon Proshev
2017-01-27 12:52:06 +03:00
parent 332a0dccfd
commit 709ed7a354
5 changed files with 23 additions and 10 deletions
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -72,5 +72,5 @@ public interface Property {
* Get the return type of the property getter.
*/
@Nullable
PyType getType(@NotNull TypeEvalContext context);
PyType getType(@Nullable PyExpression receiver, @NotNull TypeEvalContext context);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -926,7 +926,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
@Nullable
@Override
public PyType getType(@NotNull TypeEvalContext context) {
public PyType getType(@Nullable PyExpression receiver, @NotNull TypeEvalContext context) {
if (mySite instanceof PyTargetExpressionImpl) {
final PyType targetDocStringType = ((PyTargetExpressionImpl)mySite).getTypeFromDocString();
if (targetDocStringType != null) {
@@ -939,7 +939,7 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) {
return null;
}
return context.getReturnType(callable);
return callable.getCallType(receiver, Collections.emptyMap(), context);
}
return null;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2014 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -289,10 +289,10 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere
Property property = pyClass.findProperty(name, true, context);
if (property != null) {
if (classType.isDefinition()) {
return Ref.<PyType>create(PyBuiltinCache.getInstance(pyClass).getObjectType(PyNames.PROPERTY));
return Ref.create(PyBuiltinCache.getInstance(pyClass).getObjectType(PyNames.PROPERTY));
}
if (AccessDirection.of(this) == AccessDirection.READ) {
final PyType type = property.getType(context);
final PyType type = property.getType(getQualifier(), context);
if (type != null) {
return Ref.create(type);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2000-2013 JetBrains s.r.o.
* Copyright 2000-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -95,7 +95,7 @@ public class PyClassicPropertyTest extends PyTestCase {
accessor = p.getGetter();
assertFalse(accessor.isDefined());
final PyType codeInsightType = p.getType(TypeEvalContext.codeInsightFallback(myClass.getProject()));
final PyType codeInsightType = p.getType(null, TypeEvalContext.codeInsightFallback(myClass.getProject()));
assertNull(codeInsightType);
accessor = p.getSetter();
@@ -1621,6 +1621,19 @@ public class PyTypeTest extends PyTestCase {
" expr = foo");
}
// PY-22037
public void testAncestorPropertyReturnsSelf() {
doTest("Child",
"class Master(object):\n" +
" @property\n" +
" def me(self):\n" +
" return self\n" +
"class Child(Master):\n" +
" pass\n" +
"child = Child()\n" +
"expr = child.me");
}
private static List<TypeEvalContext> getTypeEvalContexts(@NotNull PyExpression element) {
return ImmutableList.of(TypeEvalContext.codeAnalysis(element.getProject(), element.getContainingFile()).withTracing(),
TypeEvalContext.userInitiated(element.getProject(), element.getContainingFile()).withTracing());