diff --git a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java index 8a3a1ced7dc8..b1b7765b4eaa 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyReferenceExpressionImpl.java @@ -306,14 +306,18 @@ public class PyReferenceExpressionImpl extends PyElementImpl implements PyRefere PsiFile file = ((PsiDirectory)target).findFile(PyNames.INIT_DOT_PY); if (file != null) return getTypeFromTarget(file, context, anchor); } + if (target instanceof PyFunction) { + final PyDecoratorList decoratorList = ((PyFunction)target).getDecoratorList(); + if (decoratorList != null) { + final PyDecorator decorator = decoratorList.findDecorator(PyNames.PROPERTY); + if (decorator != null) { + return PyBuiltinCache.getInstance(target).getObjectType(PyNames.PROPERTY); + } + } + } return null; } - @Nullable - private static PyType getTypeIfExpr(PyElement def, TypeEvalContext context) { - return def instanceof PyExpression ? context.getType((PyExpression)def) : null; - } - @Nullable public static PyType getReferenceTypeFromProviders(@NotNull final PsiElement target, TypeEvalContext context, diff --git a/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java b/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java index e479d8c9de4e..40736efe1b09 100644 --- a/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java +++ b/python/src/com/jetbrains/python/psi/resolve/CompletionVariantsProcessor.java @@ -8,9 +8,11 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.Function; import com.intellij.util.PlatformIcons; +import com.jetbrains.python.PyNames; import com.jetbrains.python.codeInsight.completion.PyClassInsertHandler; import com.jetbrains.python.codeInsight.completion.PyFunctionInsertHandler; import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.impl.PyBuiltinCache; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.Nullable; @@ -65,6 +67,13 @@ public class CompletionVariantsProcessor extends VariantsProcessor { } private static boolean isSingleArgDecoratorCall(PsiElement elementInCall, PyFunction callee) { + // special case hack to avoid the need of patching generator3.py + PyClass containingClass = callee.getContainingClass(); + if (containingClass != null && PyNames.PROPERTY.equals(containingClass.getName()) && + PyBuiltinCache.getInstance(elementInCall).hasInBuiltins(containingClass)) { + return true; + } + if (callee.getParameterList().getParameters().length > 1) { return false; } diff --git a/python/testData/completion/propertyDecorator.after.py b/python/testData/completion/propertyDecorator.after.py new file mode 100644 index 000000000000..63664aaa058a --- /dev/null +++ b/python/testData/completion/propertyDecorator.after.py @@ -0,0 +1,9 @@ +class C(object): + def __init__(self): + self._x = None + + @property + def x(self): + return self._x + + @x.setter \ No newline at end of file diff --git a/python/testData/completion/propertyDecorator.py b/python/testData/completion/propertyDecorator.py new file mode 100644 index 000000000000..967829f9f6ea --- /dev/null +++ b/python/testData/completion/propertyDecorator.py @@ -0,0 +1,9 @@ +class C(object): + def __init__(self): + self._x = None + + @property + def x(self): + return self._x + + @x.set \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/Py3CompletionTest.java b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java new file mode 100644 index 000000000000..d4b88bc6dbab --- /dev/null +++ b/python/testSrc/com/jetbrains/python/Py3CompletionTest.java @@ -0,0 +1,25 @@ +package com.jetbrains.python; + +import com.intellij.testFramework.LightProjectDescriptor; +import com.jetbrains.python.fixtures.PyTestCase; + +/** + * @author yole + */ +public class Py3CompletionTest extends PyTestCase { + @Override + protected LightProjectDescriptor getProjectDescriptor() { + return ourPy3Descriptor; + } + + public void testPropertyDecorator() { + doTest(); + } + + private void doTest() { + final String testName = "completion/" + getTestName(true); + myFixture.configureByFile(testName + ".py"); + myFixture.completeBasic(); + myFixture.checkResultByFile(testName + ".after.py"); + } +} diff --git a/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java b/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java index d65d40a40266..669ea76b5b90 100644 --- a/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java +++ b/python/testSrc/com/jetbrains/python/PythonAllTestsSuite.java @@ -39,6 +39,7 @@ public class PythonAllTestsSuite { CythonResolveTest.class, PyAssignmentMappingTest.class, PythonCompletionTest.class, + Py3CompletionTest.class, PyInheritorsSearchTest.class, PyParameterInfoTest.class, PyDecoratorTest.class,