From be280d0e044666d4fc679f66a7f444c9e42ea767 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 14 Aug 2013 17:41:21 +0400 Subject: [PATCH 1/3] Allow stub->AST in TypeEvalContext only if explicitly allowed or in the origin file --- .../src/com/jetbrains/python/psi/types/TypeEvalContext.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index 2a5c2b475f5d..03bb1ac60102 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -159,7 +159,7 @@ public class TypeEvalContext { } public boolean maySwitchToAST(@NotNull StubBasedPsiElement element) { - return myAllowStubToAST || (element.getStub() == null && (myOrigin == null || myOrigin == element.getContainingFile())); + return myAllowStubToAST || myOrigin == element.getContainingFile(); } @Nullable From 81458c1cc34203cf8a5a1d73397c6b3b35f43d9e Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 14 Aug 2013 21:33:42 +0400 Subject: [PATCH 2/3] Allow any PsiElement as an anchor in TypeEvalContext.maySwitchToAST() --- .../src/com/jetbrains/python/psi/types/TypeEvalContext.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java index 03bb1ac60102..ff0d48ad734e 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java +++ b/python/psi-api/src/com/jetbrains/python/psi/types/TypeEvalContext.java @@ -3,7 +3,6 @@ package com.jetbrains.python.psi.types; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; -import com.intellij.psi.StubBasedPsiElement; import com.jetbrains.python.psi.PyTypedElement; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -158,7 +157,7 @@ public class TypeEvalContext { } } - public boolean maySwitchToAST(@NotNull StubBasedPsiElement element) { + public boolean maySwitchToAST(@NotNull PsiElement element) { return myAllowStubToAST || myOrigin == element.getContainingFile(); } From 25e55b1c1b138d4f624970fa6bd9f08a45554211 Mon Sep 17 00:00:00 2001 From: Andrey Vlasovskikh Date: Wed, 14 Aug 2013 21:39:28 +0400 Subject: [PATCH 3/3] Property.getGetter() doesn't depend on stub/AST switch, explicit Property.getType() --- .../com/jetbrains/python/psi/Property.java | 7 +++ .../python/psi/impl/PyClassImpl.java | 49 +++++++++++++++++-- .../psi/impl/PyReferenceExpressionImpl.java | 12 +++-- python/testData/property/Classic.py | 2 +- .../python/PyClassicPropertyTest.java | 5 ++ 5 files changed, 66 insertions(+), 9 deletions(-) diff --git a/python/psi-api/src/com/jetbrains/python/psi/Property.java b/python/psi-api/src/com/jetbrains/python/psi/Property.java index aad101b0a575..60373dd0a0db 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/Property.java +++ b/python/psi-api/src/com/jetbrains/python/psi/Property.java @@ -1,5 +1,7 @@ package com.jetbrains.python.psi; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,4 +53,9 @@ public interface Property { @NotNull Maybe getByDirection(@NotNull AccessDirection direction); + /** + * Get the return type of the property getter. + */ + @Nullable + PyType getType(@NotNull TypeEvalContext context); } diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 1eb2a9b1fcb4..829cde42f98e 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -691,6 +691,24 @@ public class PyClassImpl extends PyPresentableElementImpl implement mySite = site; } + @NotNull + @Override + public Maybe getGetter() { + return filterNonStubExpression(myGetter); + } + + @NotNull + @Override + public Maybe getSetter() { + return filterNonStubExpression(mySetter); + } + + @NotNull + @Override + public Maybe getDeleter() { + return filterNonStubExpression(myDeleter); + } + public String getName() { return myName; } @@ -704,15 +722,29 @@ public class PyClassImpl extends PyPresentableElementImpl implement public Maybe getByDirection(@NotNull AccessDirection direction) { switch (direction) { case READ: - return myGetter; + return getGetter(); case WRITE: - return mySetter; + return getSetter(); case DELETE: - return myDeleter; + return getDeleter(); } throw new IllegalArgumentException("Unknown direction " + PyUtil.nvl(direction)); } + @Nullable + @Override + public PyType getType(@NotNull TypeEvalContext context) { + final Callable callable = myGetter.valueOrNull(); + if (callable != null) { + // Ignore return types of non stub-based elements if we are not allowed to use AST + if (!(callable instanceof StubBasedPsiElement) && !context.maySwitchToAST(callable)) { + return null; + } + return callable.getReturnType(context, null); + } + return null; + } + @NotNull @Override protected Maybe translate(@Nullable PyExpression expr) { @@ -733,6 +765,17 @@ public class PyClassImpl extends PyPresentableElementImpl implement return NONE; } + @NotNull + private static Maybe filterNonStubExpression(@NotNull Maybe maybeCallable) { + final Callable callable = maybeCallable.valueOrNull(); + if (callable != null) { + if (!(callable instanceof StubBasedPsiElement)) { + return UNKNOWN_CALL; + } + } + return maybeCallable; + } + public String toString() { return "property(" + myGetter + ", " + mySetter + ", " + myDeleter + ", " + myDoc + ")"; } diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index f77f6501f6f8..3e702bf69ef5 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -27,7 +27,6 @@ import com.jetbrains.python.psi.impl.references.PyReferenceImpl; import com.jetbrains.python.psi.resolve.*; import com.jetbrains.python.psi.types.*; import com.jetbrains.python.refactoring.PyDefUseUtil; -import com.jetbrains.python.toolbox.Maybe; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -269,10 +268,13 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere if (classType.isDefinition()) { return Ref.create(PyBuiltinCache.getInstance(pyClass).getObjectType(PyNames.PROPERTY)); } - final Maybe accessor = property.getByDirection(AccessDirection.of(this)); - final Callable callable = accessor.valueOrNull(); - final PyType type = (callable != null) ? callable.getReturnType(context, this) : null; - return Ref.create(type); + if (AccessDirection.of(this) == AccessDirection.READ) { + final PyType type = property.getType(context); + if (type != null) { + return Ref.create(type); + } + } + return Ref.create(); } } else if (qualifierType instanceof PyUnionType) { diff --git a/python/testData/property/Classic.py b/python/testData/property/Classic.py index c7293b63d2e4..c48b4503b513 100644 --- a/python/testData/property/Classic.py +++ b/python/testData/property/Classic.py @@ -19,6 +19,6 @@ class A(object): v1 = property(getter, setter) v2 = property(fset=setter, fdel=deleter, fget=getter, doc="doc of v2") - v3 = property(lambda self: self._v, None, (deleter)) + v3 = property(lambda self: 0, None, (deleter)) v4 = otherworldly # NOTE: not supported yet v5 = property(v5getter, v5setter) diff --git a/python/testSrc/com/jetbrains/python/PyClassicPropertyTest.java b/python/testSrc/com/jetbrains/python/PyClassicPropertyTest.java index 0ba9de3683eb..e72e10aaea5f 100644 --- a/python/testSrc/com/jetbrains/python/PyClassicPropertyTest.java +++ b/python/testSrc/com/jetbrains/python/PyClassicPropertyTest.java @@ -2,6 +2,8 @@ package com.jetbrains.python; import com.jetbrains.python.fixtures.PyTestCase; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.types.PyType; +import com.jetbrains.python.psi.types.TypeEvalContext; import com.jetbrains.python.toolbox.Maybe; public class PyClassicPropertyTest extends PyTestCase { @@ -78,6 +80,9 @@ public class PyClassicPropertyTest extends PyTestCase { accessor = p.getGetter(); assertFalse(accessor.isDefined()); + final PyType codeInsightType = p.getType(TypeEvalContext.codeInsightFallback()); + assertNull(codeInsightType); + accessor = p.getSetter(); assertTrue(accessor.isDefined()); assertNull(accessor.value());