mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-27392 Better names of intentions for functions and variable type hints
Now it's possible to distinguish between them when both are offered on a target of a call expression result assignment (as it was noticed during the testing of PY-16412).
This commit is contained in:
committed by
Andrey Vlasovskikh
parent
149eefa75e
commit
b7ebc74682
@@ -280,8 +280,12 @@ INTN.add.parameters.to.docstring=Add parameters to docstring
|
||||
INTN.specify.type.in.annotation=Specify type for reference using annotation
|
||||
INTN.specify.return.type.in.annotation=Specify return type using annotation
|
||||
|
||||
#PyAnnotateTypesIntention
|
||||
INTN.annotate.types=Annotate types
|
||||
#PyAnnotateTypesIntention/PyAnnotateVariableTypeIntention
|
||||
INTN.add.type.hints.for.function.family=Add type hints for function
|
||||
INTN.add.type.hints.for.function=Add type hints for function ''{0}''
|
||||
INTN.add.type.hint.for.variable.family=Add type hint for variable
|
||||
INTN.add.type.hint.for.variable=Add type hint for variable ''{0}''
|
||||
INTN.add.type.hint.for.variable.PEP484.incompatible.type=Type ''{0}'' cannot be expressed inline in PEP 484 format
|
||||
|
||||
#TypeAssertionIntention
|
||||
INTN.insert.assertion=Insert type assertion
|
||||
@@ -295,8 +299,6 @@ INTN.convert.static.method.to.function=Convert static method to function
|
||||
#PyConvertMethodToPropertyIntention
|
||||
INTN.convert.method.to.property=Convert method to property
|
||||
|
||||
INTN.annotate.variable.type.PEP484.incompatible.type=The type ''{0}'' cannot be expressed in PEP 484 format
|
||||
|
||||
# Conflict checker
|
||||
CONFLICT.name.$0.obscured=Name ''{0}'' obscured by local definitions
|
||||
CONFLICT.name.$0.obscured.cannot.convert=Name ''{0}'' obscured. Cannot convert.
|
||||
|
||||
+4
-14
@@ -38,32 +38,26 @@ import java.util.List;
|
||||
|
||||
import static com.jetbrains.python.codeInsight.intentions.SpecifyTypeInPy3AnnotationsIntention.*;
|
||||
import static com.jetbrains.python.codeInsight.intentions.TypeIntention.getMultiCallable;
|
||||
import static com.jetbrains.python.codeInsight.intentions.TypeIntention.resolvesToFunction;
|
||||
|
||||
/**
|
||||
* @author traff
|
||||
*/
|
||||
public class PyAnnotateTypesIntention extends PyBaseIntentionAction {
|
||||
|
||||
public PyAnnotateTypesIntention() {
|
||||
setText(PyBundle.message("INTN.annotate.types"));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getFamilyName() {
|
||||
return PyBundle.message("INTN.annotate.types");
|
||||
return PyBundle.message("INTN.add.type.hints.for.function.family");
|
||||
}
|
||||
|
||||
public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) {
|
||||
if (!(file instanceof PyFile) || file instanceof PyDocstringFile) return false;
|
||||
|
||||
updateText();
|
||||
|
||||
final PsiElement elementAt = PyUtil.findNonWhitespaceAtOffset(file, editor.getCaretModel().getOffset());
|
||||
if (elementAt == null) return false;
|
||||
|
||||
if (resolvesToFunction(elementAt, input -> true)) {
|
||||
updateText();
|
||||
final PyFunction function = TypeIntention.findSuitableFunction(elementAt, input -> true);
|
||||
if (function != null) {
|
||||
setText(PyBundle.message("INTN.add.type.hints.for.function", function.getName()));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -221,8 +215,4 @@ public class PyAnnotateTypesIntention extends PyBaseIntentionAction {
|
||||
startTemplate(project, callable, builder);
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateText() {
|
||||
setText(PyBundle.message("INTN.annotate.types"));
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -44,7 +44,7 @@ public class PyAnnotateVariableTypeIntention extends PyBaseIntentionAction {
|
||||
@NotNull
|
||||
@Override
|
||||
public String getFamilyName() {
|
||||
return PyBundle.message("INTN.annotate.types");
|
||||
return PyBundle.message("INTN.add.type.hint.for.variable.family");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -57,7 +57,7 @@ public class PyAnnotateVariableTypeIntention extends PyBaseIntentionAction {
|
||||
return false;
|
||||
}
|
||||
|
||||
setText(PyBundle.message("INTN.annotate.types"));
|
||||
setText(PyBundle.message("INTN.add.type.hint.for.variable", resolved.get(0).getName()));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -343,7 +343,7 @@ public class PyTypeHintGenerationUtil {
|
||||
// In this order since PyCollectionTypeImpl implements PyClassType
|
||||
}
|
||||
else {
|
||||
throw new Pep484IncompatibleTypeException(PyBundle.message("INTN.annotate.variable.type.PEP484.incompatible.type", type.getName()));
|
||||
throw new Pep484IncompatibleTypeException(PyBundle.message("INTN.add.type.hint.for.variable.PEP484.incompatible.type", type.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -111,25 +111,28 @@ public abstract class TypeIntention extends PyBaseIntentionAction {
|
||||
}
|
||||
|
||||
private boolean isAvailableForReturn(@NotNull final PsiElement elementAt) {
|
||||
return resolvesToFunction(elementAt, input -> !isReturnTypeDefined(input));
|
||||
return findSuitableFunction(elementAt, input -> !isReturnTypeDefined(input)) != null;
|
||||
}
|
||||
|
||||
static boolean resolvesToFunction(@NotNull PsiElement elementAt, Function<PyFunction, Boolean> isAvailableForFunction) {
|
||||
@Nullable
|
||||
public static PyFunction findSuitableFunction(@NotNull PsiElement elementAt, Function<PyFunction, Boolean> isAvailableForFunction) {
|
||||
final PyFunction parentFunction = PsiTreeUtil.getParentOfType(elementAt, PyFunction.class);
|
||||
if (parentFunction != null) {
|
||||
final ASTNode nameNode = parentFunction.getNameNode();
|
||||
if (nameNode != null) {
|
||||
final PsiElement prev = elementAt.getContainingFile().findElementAt(elementAt.getTextOffset()-1);
|
||||
if (nameNode.getPsi() == elementAt || nameNode.getPsi() == prev) {
|
||||
return isAvailableForFunction.apply(parentFunction);
|
||||
if (isAvailableForFunction.apply(parentFunction)) {
|
||||
return parentFunction;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final PyCallExpression callExpression = getCallExpression(elementAt);
|
||||
if (callExpression == null) return false;
|
||||
if (callExpression == null) return null;
|
||||
final PyExpression callee = callExpression.getCallee();
|
||||
if (callee == null) return false;
|
||||
if (callee == null) return null;
|
||||
final PsiReference reference = callee.getReference();
|
||||
if (reference instanceof PsiPolyVariantReference) {
|
||||
final ResolveResult[] results = ((PsiPolyVariantReference)reference).multiResolve(false);
|
||||
@@ -137,18 +140,20 @@ public abstract class TypeIntention extends PyBaseIntentionAction {
|
||||
if (results[i].getElement() instanceof PyFunction) {
|
||||
final PsiElement result = results[i].getElement();
|
||||
final PsiFile psiFile = result.getContainingFile();
|
||||
if (psiFile == null) return false;
|
||||
if (psiFile == null) return null;
|
||||
final VirtualFile virtualFile = psiFile.getVirtualFile();
|
||||
if (virtualFile != null) {
|
||||
if (ProjectRootManager.getInstance(psiFile.getProject()).getFileIndex().isInLibraryClasses(virtualFile)) {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return isAvailableForFunction.apply((PyFunction)result);
|
||||
if (isAvailableForFunction.apply((PyFunction)result)) {
|
||||
return (PyFunction)result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
|
||||
protected boolean isReturnTypeDefined(@NotNull PyFunction function) {
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
def func(x):
|
||||
return 42
|
||||
|
||||
|
||||
va<caret>r = func('foo')
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
def func(x):
|
||||
return 42
|
||||
|
||||
|
||||
var: [int] = func('foo')
|
||||
@@ -20,17 +20,17 @@ public class PyAnnotateTypesIntentionTest extends PyIntentionTestCase {
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON34,
|
||||
() -> {
|
||||
doIntentionTest(PyBundle.message("INTN.annotate.types"), getTestName(true) + ".py", "foo_decl.py");
|
||||
doIntentionTest(PyBundle.message("INTN.add.type.hints.for.function.family"), getTestName(true) + ".py", "foo_decl.py");
|
||||
myFixture.checkResultByFile("foo_decl.py", "foo_decl_after.py", false);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public void testTypeComment() {
|
||||
doTest(PyBundle.message("INTN.annotate.types"), LanguageLevel.PYTHON27);
|
||||
doTest(PyBundle.message("INTN.add.type.hints.for.function.family"), LanguageLevel.PYTHON27);
|
||||
}
|
||||
|
||||
private void doTest() {
|
||||
doTest(PyBundle.message("INTN.annotate.types"), LanguageLevel.PYTHON34);
|
||||
doTest(PyBundle.message("INTN.add.type.hints.for.function.family"), LanguageLevel.PYTHON34);
|
||||
}
|
||||
}
|
||||
|
||||
+7
-3
@@ -227,6 +227,10 @@ public class PyAnnotateVariableTypeIntentionTest extends PyIntentionTestCase {
|
||||
doAnnotationTest();
|
||||
}
|
||||
|
||||
public void testConflictWithAnnotationFunctionTypeIntention() {
|
||||
doTest(LanguageLevel.PYTHON36);
|
||||
}
|
||||
|
||||
private void doAnnotationTest() {
|
||||
doTest(LanguageLevel.PYTHON36);
|
||||
}
|
||||
@@ -236,12 +240,12 @@ public class PyAnnotateVariableTypeIntentionTest extends PyIntentionTestCase {
|
||||
}
|
||||
|
||||
private void doNegativeTest() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, () -> doNegativeTest(PyBundle.message("INTN.annotate.types")));
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, () -> doNegativeTest(PyBundle.message("INTN.add.type.hint.for.variable.family")));
|
||||
}
|
||||
|
||||
public void doMultiFileAnnotationTest() {
|
||||
runWithLanguageLevel(LanguageLevel.PYTHON36, () -> {
|
||||
doMultiFileTest(PyBundle.message("INTN.annotate.types"));
|
||||
doMultiFileTest(PyBundle.message("INTN.add.type.hint.for.variable.family"));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -256,6 +260,6 @@ public class PyAnnotateVariableTypeIntentionTest extends PyIntentionTestCase {
|
||||
}
|
||||
|
||||
private void doTest(@NotNull LanguageLevel languageLevel) {
|
||||
doTest(PyBundle.message("INTN.annotate.types"), languageLevel);
|
||||
doTest(PyBundle.message("INTN.add.type.hint.for.variable.family"), languageLevel);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user