mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Now docstring intention available if type is not specified in docstring
and annotation intention available if type is not specified in annotation fixed PY-8782 Specify return type in doctring: intention is not available on function call with collected types
This commit is contained in:
+28
@@ -6,11 +6,13 @@ import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.jetbrains.python.PyBundle;
|
||||
import com.jetbrains.python.debugger.PySignature;
|
||||
import com.jetbrains.python.debugger.PySignatureCacheManager;
|
||||
import com.jetbrains.python.documentation.PyDocstringGenerator;
|
||||
import com.jetbrains.python.documentation.StructuredDocString;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@@ -69,4 +71,30 @@ public class SpecifyTypeInDocstringIntention extends TypeIntention {
|
||||
protected void updateText(boolean isReturn) {
|
||||
myText = isReturn? PyBundle.message("INTN.specify.return.type") : PyBundle.message("INTN.specify.type");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTypeDefined(PyExpression problemElement) {
|
||||
return isDefinedInDocstring(problemElement);
|
||||
}
|
||||
|
||||
private boolean isDefinedInDocstring(PyExpression problemElement) {
|
||||
PsiReference reference = problemElement.getReference();
|
||||
PyFunction pyFunction = PsiTreeUtil.getParentOfType(problemElement, PyFunction.class);
|
||||
if (pyFunction != null && (problemElement instanceof PyParameter || reference != null && reference.resolve() instanceof PyParameter)) {
|
||||
final String docstring = pyFunction.getDocStringValue();
|
||||
if (docstring != null) {
|
||||
String name = problemElement.getName();
|
||||
if (problemElement instanceof PyQualifiedExpression) {
|
||||
final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
|
||||
if (qualifier != null) {
|
||||
name = qualifier.getText();
|
||||
}
|
||||
}
|
||||
StructuredDocString structuredDocString = StructuredDocString.parse(docstring);
|
||||
return structuredDocString != null && structuredDocString.getParamType(name) != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+34
-1
@@ -83,7 +83,7 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention {
|
||||
TemplateManager.getInstance(project).startTemplate(editor, template);
|
||||
}
|
||||
|
||||
private static void annotateReturnType(Project project, PsiElement resolved) {
|
||||
private void annotateReturnType(Project project, PsiElement resolved) {
|
||||
PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project);
|
||||
|
||||
Callable callable = getCallable(resolved);
|
||||
@@ -123,6 +123,39 @@ public class SpecifyTypeInPy3AnnotationsIntention extends TypeIntention {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTypeDefined(PyExpression problemElement) {
|
||||
|
||||
return isDefinedInAnnotation(problemElement);
|
||||
}
|
||||
|
||||
private boolean isDefinedInAnnotation(PyExpression problemElement) {
|
||||
if (LanguageLevel.forElement(problemElement).isOlderThan(LanguageLevel.PYTHON30)) {
|
||||
return false;
|
||||
}
|
||||
PsiReference reference = problemElement.getReference();
|
||||
final PsiElement resolved = reference != null? reference.resolve() : null;
|
||||
PyParameter parameter = getParameter(problemElement, resolved);
|
||||
|
||||
if (parameter instanceof PyNamedParameter && (((PyNamedParameter)parameter).getAnnotation() != null)) return true;
|
||||
|
||||
if (resolved instanceof PyTargetExpression) { // return type
|
||||
final PyExpression assignedValue = ((PyTargetExpression)resolved).findAssignedValue();
|
||||
if (assignedValue instanceof PyCallExpression) {
|
||||
final PyExpression callee = ((PyCallExpression)assignedValue).getCallee();
|
||||
if (callee != null) {
|
||||
final PsiReference psiReference = callee.getReference();
|
||||
if (psiReference != null && psiReference.resolve() == null) return false;
|
||||
}
|
||||
final Callable callable = ((PyCallExpression)assignedValue).resolveCalleeFunction(getResolveContext(problemElement));
|
||||
|
||||
if (callable instanceof PyFunction && ((PyFunction)callable).getAnnotation() != null) return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void updateText(boolean isReturn) {
|
||||
myText = isReturn? PyBundle.message("INTN.specify.return.type.in.annotation") : PyBundle.message("INTN.specify.type.in.annotation");
|
||||
|
||||
@@ -9,10 +9,8 @@ import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.documentation.StructuredDocString;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.types.PyDynamicallyEvaluatedType;
|
||||
import com.jetbrains.python.psi.types.PyReturnTypeReference;
|
||||
import com.jetbrains.python.psi.types.PyType;
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext;
|
||||
@@ -31,7 +29,10 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
|
||||
PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
|
||||
if (elementAt == null) return false;
|
||||
if (isAvailableForReturn(elementAt)) return true;
|
||||
if (isAvailableForReturn(elementAt)) {
|
||||
updateText(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
final PyExpression problemElement = getProblemElement(elementAt);
|
||||
if (problemElement == null) return false;
|
||||
@@ -49,7 +50,7 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return isTypeUndefined(problemElement);
|
||||
return !isTypeDefined(problemElement);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -67,43 +68,7 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
|
||||
protected abstract void updateText(boolean isReturn);
|
||||
|
||||
private static boolean isTypeUndefined(PyExpression problemElement) {
|
||||
final PyType type = problemElement.getType(TypeEvalContext.fastStubOnly(problemElement.getContainingFile()));
|
||||
if (type == null || type instanceof PyReturnTypeReference || type instanceof PyDynamicallyEvaluatedType) {
|
||||
PsiReference reference = problemElement.getReference();
|
||||
if (problemElement instanceof PyQualifiedExpression) {
|
||||
final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
|
||||
if (qualifier != null && !qualifier.getText().equals(PyNames.CANONICAL_SELF)) reference = qualifier.getReference();
|
||||
}
|
||||
|
||||
if (isDefinedInDocstring(problemElement, reference)) return false;
|
||||
return !isDefinedInAnnotation(problemElement, reference);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isDefinedInAnnotation(PyExpression problemElement, PsiReference reference) {
|
||||
if (LanguageLevel.forElement(problemElement).isOlderThan(LanguageLevel.PYTHON30)) {
|
||||
return false;
|
||||
}
|
||||
final PsiElement resolved = reference != null? reference.resolve() : null;
|
||||
PyParameter parameter = getParameter(problemElement, resolved);
|
||||
|
||||
if (parameter instanceof PyNamedParameter && (((PyNamedParameter)parameter).getAnnotation() != null)) return true;
|
||||
|
||||
if (resolved instanceof PyTargetExpression) { // return type
|
||||
final PyExpression assignedValue = ((PyTargetExpression)resolved).findAssignedValue();
|
||||
if (assignedValue instanceof PyCallExpression) {
|
||||
final PyExpression callee = ((PyCallExpression)assignedValue).getCallee();
|
||||
if (callee != null) {
|
||||
final PsiReference psiReference = callee.getReference();
|
||||
if (psiReference != null && psiReference.resolve() == null) return false;
|
||||
}
|
||||
final Callable callable = ((PyCallExpression)assignedValue).resolveCalleeFunction(getResolveContext(problemElement));
|
||||
|
||||
if (callable instanceof PyFunction && ((PyFunction)callable).getAnnotation() != null) return true;
|
||||
}
|
||||
}
|
||||
protected boolean isTypeDefined(PyExpression problemElement) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -115,26 +80,6 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
return parameter;
|
||||
}
|
||||
|
||||
private static boolean isDefinedInDocstring(PyExpression problemElement, PsiReference reference) {
|
||||
PyFunction pyFunction = PsiTreeUtil.getParentOfType(problemElement, PyFunction.class);
|
||||
if (pyFunction != null && (problemElement instanceof PyParameter || reference != null && reference.resolve() instanceof PyParameter)) {
|
||||
final String docstring = pyFunction.getDocStringValue();
|
||||
if (docstring != null) {
|
||||
String name = problemElement.getName();
|
||||
if (problemElement instanceof PyQualifiedExpression) {
|
||||
final PyExpression qualifier = ((PyQualifiedExpression)problemElement).getQualifier();
|
||||
if (qualifier != null) {
|
||||
name = qualifier.getText();
|
||||
}
|
||||
}
|
||||
StructuredDocString structuredDocString = StructuredDocString.parse(docstring);
|
||||
return structuredDocString != null && structuredDocString.getParamType(name) != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isAvailableForReturn(PsiElement elementAt) {
|
||||
PyCallExpression callExpression = getCallExpression(elementAt);
|
||||
|
||||
@@ -160,7 +105,6 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
updateText(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -172,7 +116,6 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
if (parentFunction != null) {
|
||||
final ASTNode nameNode = parentFunction.getNameNode();
|
||||
if (nameNode != null && nameNode.getPsi() == elementAt) {
|
||||
updateText(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -204,7 +147,7 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected static Callable getCallable(PsiElement elementAt) {
|
||||
protected Callable getCallable(PsiElement elementAt) {
|
||||
PyCallExpression callExpression = getCallExpression(elementAt);
|
||||
|
||||
if (callExpression != null && elementAt != null) {
|
||||
@@ -214,7 +157,7 @@ public abstract class TypeIntention implements IntentionAction {
|
||||
return PsiTreeUtil.getParentOfType(elementAt, PyFunction.class);
|
||||
}
|
||||
|
||||
private static PyResolveContext getResolveContext(@NotNull PsiElement origin) {
|
||||
protected PyResolveContext getResolveContext(@NotNull PsiElement origin) {
|
||||
return PyResolveContext.defaultContext().withTypeEvalContext(TypeEvalContext.fastStubOnly(origin.getContainingFile()));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user