From edc1b4a591353d6413165965eecba2fdab1bf86d Mon Sep 17 00:00:00 2001 From: Ekaterina Tuzova Date: Fri, 2 Nov 2012 12:23:48 +0400 Subject: [PATCH] fixed PY-7933 Specify type in docstring intention not available --- .../SpecifyTypeInDocstringIntention.java | 108 +++++++++--------- .../intentions/afterTypeInDocstring3.py | 6 + .../intentions/beforeTypeInDocstring3.py | 3 + .../com/jetbrains/python/PyIntentionTest.java | 4 + 4 files changed, 69 insertions(+), 52 deletions(-) create mode 100644 python/testData/intentions/afterTypeInDocstring3.py create mode 100644 python/testData/intentions/beforeTypeInDocstring3.py diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java index 1f1f3e94d5b8..900400e300a6 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/SpecifyTypeInDocstringIntention.java @@ -1,16 +1,9 @@ package com.jetbrains.python.codeInsight.intentions; -import com.intellij.codeInsight.CodeInsightUtilBase; import com.intellij.codeInsight.intention.IntentionAction; -import com.intellij.codeInsight.template.*; import com.intellij.lang.ASTNode; -import com.intellij.openapi.editor.Document; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.fileEditor.FileEditorManager; -import com.intellij.openapi.fileEditor.OpenFileDescriptor; import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Pair; -import com.intellij.openapi.util.TextRange; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiReference; @@ -18,10 +11,7 @@ import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.IncorrectOperationException; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyNames; -import com.jetbrains.python.PyTokenTypes; import com.jetbrains.python.documentation.PyDocstringGenerator; -import com.jetbrains.python.documentation.PyDocumentationSettings; -import com.jetbrains.python.documentation.PythonDocumentationProvider; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.resolve.PyResolveContext; import com.jetbrains.python.psi.types.PyDynamicallyEvaluatedType; @@ -29,6 +19,7 @@ import com.jetbrains.python.psi.types.PyReturnTypeReference; import com.jetbrains.python.psi.types.PyType; import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * User: ktisha @@ -55,32 +46,9 @@ public class SpecifyTypeInDocstringIntention implements IntentionAction { PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); if (elementAt == null) return false; PyCallExpression callExpression = PsiTreeUtil.getParentOfType(elementAt, PyCallExpression.class); - if (callExpression != null && callExpression.resolveCalleeFunction(PyResolveContext.defaultContext()) != null) { - PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(elementAt, PyAssignmentStatement.class); - if (assignmentStatement != null) { - final PyExpression assignedValue = assignmentStatement.getAssignedValue(); - if (assignedValue != null) { - PyType type = assignedValue.getType(TypeEvalContext.slow()); - if (type == null || type instanceof PyReturnTypeReference) { - myText = PyBundle.message("INTN.specify.return.type"); - return true; - } - } - } - } - else { - PyFunction parentFunction = PsiTreeUtil.getParentOfType(elementAt, PyFunction.class); - if (parentFunction != null) { - final ASTNode nameNode = parentFunction.getNameNode(); - if (nameNode != null && nameNode.getPsi() == elementAt) { - myText = PyBundle.message("INTN.specify.return.type"); - return true; - } - } - } - - PyExpression problemElement = PyUtil.findProblemElement(editor, file, PyNamedParameter.class, PyQualifiedExpression.class); + if (checkAvailableForReturn(elementAt, callExpression)) return true; + PyExpression problemElement = PsiTreeUtil.getParentOfType(elementAt, PyNamedParameter.class, PyQualifiedExpression.class); if (problemElement == null) return false; if (problemElement instanceof PyQualifiedExpression) { final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier(); @@ -93,6 +61,10 @@ public class SpecifyTypeInDocstringIntention implements IntentionAction { return false; } final PyType type = problemElement.getType(TypeEvalContext.slow()); + return checkType(problemElement, type); + } + + private boolean checkType(PyExpression problemElement, @Nullable PyType type) { if (type == null || type instanceof PyReturnTypeReference || type instanceof PyDynamicallyEvaluatedType) { PyFunction pyFunction = PsiTreeUtil.getParentOfType(problemElement, PyFunction.class); PsiReference reference = problemElement.getReference(); @@ -117,24 +89,52 @@ public class SpecifyTypeInDocstringIntention implements IntentionAction { return false; } - public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - PsiElement elementAt = file.findElementAt(editor.getCaretModel().getOffset() - 1); - if (elementAt != null && !(elementAt.getNode().getElementType() == PyTokenTypes.IDENTIFIER)) { - elementAt = file.findElementAt(editor.getCaretModel().getOffset()); + private boolean checkAvailableForReturn(PsiElement elementAt, @Nullable PyCallExpression callExpression) { + if (callExpression != null && callExpression.resolveCalleeFunction(PyResolveContext.defaultContext()) != null) { + PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(elementAt, PyAssignmentStatement.class); + if (assignmentStatement != null) { + final PyExpression assignedValue = assignmentStatement.getAssignedValue(); + if (assignedValue != null) { + PyType type = assignedValue.getType(TypeEvalContext.slow()); + if (type == null || type instanceof PyReturnTypeReference) { + myText = PyBundle.message("INTN.specify.return.type"); + return true; + } + } + } } + else { + PyFunction parentFunction = PsiTreeUtil.getParentOfType(elementAt, PyFunction.class); + if (parentFunction != null) { + final ASTNode nameNode = parentFunction.getNameNode(); + if (nameNode != null && nameNode.getPsi() == elementAt) { + myText = PyBundle.message("INTN.specify.return.type"); + return true; + } + } + } + return false; + } + + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset()); String kind = "type"; - PyCallExpression callExpression = PyUtil.findProblemElement(editor, file, PyCallExpression.class); + PyCallExpression callExpression = PsiTreeUtil.getParentOfType(elementAt, PyCallExpression.class); PyFunction pyFunction = PsiTreeUtil.getParentOfType(elementAt, PyFunction.class); - PyExpression problemElement = PyUtil.findProblemElement(editor, file, PyNamedParameter.class, PyQualifiedExpression.class); + + PyExpression problemElement = PsiTreeUtil.getParentOfType(elementAt, PyNamedParameter.class, PyQualifiedExpression.class); if (callExpression != null) { PyAssignmentStatement assignmentStatement = PsiTreeUtil.getParentOfType(elementAt, PyAssignmentStatement.class); if (assignmentStatement != null) { - PyType pyType = assignmentStatement.getAssignedValue().getType(TypeEvalContext.slow()); - if (pyType == null || pyType instanceof PyReturnTypeReference) { - pyFunction = (PyFunction)callExpression.resolveCalleeFunction(PyResolveContext.defaultContext()); - problemElement = null; - kind = "rtype"; + final PyExpression assignedValue = assignmentStatement.getAssignedValue(); + if (assignedValue != null) { + PyType pyType = assignedValue.getType(TypeEvalContext.slow()); + if (pyType == null || pyType instanceof PyReturnTypeReference) { + pyFunction = (PyFunction)callExpression.resolveCalleeFunction(PyResolveContext.defaultContext()); + problemElement = null; + kind = "rtype"; + } } } } @@ -145,11 +145,17 @@ public class SpecifyTypeInDocstringIntention implements IntentionAction { } } + generateDocstring(elementAt, kind, callExpression, pyFunction, problemElement); + } + + private void generateDocstring(PsiElement elementAt, String kind, + @Nullable PyCallExpression callExpression, + PyFunction pyFunction, + PyExpression problemElement) { PsiReference reference = null; PyDocstringGenerator docstringGenerator = new PyDocstringGenerator(pyFunction); - String name = ""; if (problemElement != null) { name = problemElement.getName(); @@ -164,18 +170,16 @@ public class SpecifyTypeInDocstringIntention implements IntentionAction { } pyFunction = PsiTreeUtil.getParentOfType(problemElement, PyFunction.class); } + if (pyFunction == null || name == null) return; docstringGenerator.withParam(kind, name); final ASTNode nameNode = pyFunction.getNameNode(); - if ((pyFunction != null && - (problemElement instanceof PyParameter || reference != null && reference.resolve() instanceof PyParameter)) || - elementAt == nameNode.getPsi() || callExpression != null) { - + if ((problemElement instanceof PyParameter || reference != null && reference.resolve() instanceof PyParameter) || + (nameNode != null && elementAt == nameNode.getPsi()) || callExpression != null) { docstringGenerator.build(); } - docstringGenerator.startTemplate(); } diff --git a/python/testData/intentions/afterTypeInDocstring3.py b/python/testData/intentions/afterTypeInDocstring3.py new file mode 100644 index 000000000000..009561da2dca --- /dev/null +++ b/python/testData/intentions/afterTypeInDocstring3.py @@ -0,0 +1,6 @@ +def foo3(x, y, z, aa): #comment + """ + :type y: object + """ + i = xx + y + z + return i \ No newline at end of file diff --git a/python/testData/intentions/beforeTypeInDocstring3.py b/python/testData/intentions/beforeTypeInDocstring3.py new file mode 100644 index 000000000000..e4970e10d4aa --- /dev/null +++ b/python/testData/intentions/beforeTypeInDocstring3.py @@ -0,0 +1,3 @@ +def foo3(x, y, z, aa): #comment + i = xx + y + z + return i \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/PyIntentionTest.java index ebe37d566b82..b73b99898ff8 100644 --- a/python/testSrc/com/jetbrains/python/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/PyIntentionTest.java @@ -237,6 +237,10 @@ public class PyIntentionTest extends PyTestCase { doTest(PyBundle.message("INTN.specify.type")); } + public void testTypeInDocstring3() { + doTest(PyBundle.message("INTN.specify.type")); + } + private void doDocReturnTypeTest() { doTest(PyBundle.message("INTN.specify.return.type")); }