mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Highlight the case when type comment and annotation are both specified (PY-20530)
This commit is contained in:
@@ -102,6 +102,25 @@ class PyTypeHintsInspection : PyInspection() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPyElement(node: PyElement?) {
|
||||
super.visitPyElement(node)
|
||||
|
||||
if (node is PyTypeCommentOwner && node is PyAnnotationOwner && node.typeCommentAnnotation != null) {
|
||||
val message = "Type(s) specified both in type comment and annotation"
|
||||
|
||||
if (node is PyFunction) {
|
||||
if (node.annotationValue != null || node.parameterList.parameters.any { it is PyNamedParameter && it.annotationValue != null }) {
|
||||
registerProblem(node.typeComment, message, RemoveElementQuickFix("Remove type comment"))
|
||||
registerProblem(node.nameIdentifier, message, RemoveFunctionAnnotations())
|
||||
}
|
||||
}
|
||||
else if (node.annotationValue != null) {
|
||||
registerProblem(node.typeComment, message, RemoveElementQuickFix("Remove type comment"))
|
||||
registerProblem(node.annotation, message, RemoveElementQuickFix("Remove annotation"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkTypeVarPlacement(call: PyCallExpression, target: PyExpression?) {
|
||||
if (target == null) {
|
||||
registerProblem(call, "A 'TypeVar()' expression must always directly be assigned to a variable")
|
||||
@@ -509,6 +528,29 @@ class PyTypeHintsInspection : PyInspection() {
|
||||
}
|
||||
}
|
||||
|
||||
private class RemoveElementQuickFix(private val description: String) : LocalQuickFix {
|
||||
|
||||
override fun getFamilyName() = description
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) = descriptor.psiElement.delete()
|
||||
}
|
||||
|
||||
private class RemoveFunctionAnnotations : LocalQuickFix {
|
||||
|
||||
override fun getFamilyName() = "Remove function annotations"
|
||||
|
||||
override fun applyFix(project: Project, descriptor: ProblemDescriptor) {
|
||||
val function = (descriptor.psiElement.parent as? PyFunction) ?: return
|
||||
|
||||
function.annotation?.delete()
|
||||
|
||||
function.parameterList.parameters
|
||||
.asSequence()
|
||||
.filterIsInstance<PyNamedParameter>()
|
||||
.mapNotNull { it.annotation }
|
||||
.forEach { it.delete() }
|
||||
}
|
||||
}
|
||||
|
||||
private class ReplaceWithTargetNameQuickFix(private val targetName: String) : LocalQuickFix {
|
||||
|
||||
override fun getFamilyName() = "Replace with target name"
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
def <warning descr="Type(s) specified both in type comment and annotation">b<caret>ar</warning>(a: int) -> int:
|
||||
<warning descr="Type(s) specified both in type comment and annotation"># type: (int) -> int</warning>
|
||||
pass
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
def bar(a):
|
||||
# type: (int) -> int
|
||||
pass
|
||||
@@ -584,6 +584,32 @@ public class PyTypeHintsInspectionTest extends PyInspectionTestCase {
|
||||
"e2, (f2, g2), h2 = undefined() # type: <warning descr=\"Type comment cannot be matched with unpacked variables\">int, (str), str</warning>");
|
||||
}
|
||||
|
||||
// PY-20530
|
||||
public void testAnnotationAndTypeComment() {
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON36,
|
||||
() -> doTestByText(
|
||||
"a<warning descr=\"Type(s) specified both in type comment and annotation\">: int</warning> = None <warning descr=\"Type(s) specified both in type comment and annotation\"># type: int</warning>\n" +
|
||||
"\n" +
|
||||
"def foo(a<warning descr=\"Type(s) specified both in type comment and annotation\">: int</warning> <warning descr=\"Type(s) specified both in type comment and annotation\"># type: int</warning>\n" +
|
||||
" ,):\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"def <warning descr=\"Type(s) specified both in type comment and annotation\">bar</warning>(a: int) -> int:\n" +
|
||||
" <warning descr=\"Type(s) specified both in type comment and annotation\"># type: (int) -> int</warning>\n" +
|
||||
" pass\n" +
|
||||
" \n" +
|
||||
"def <warning descr=\"Type(s) specified both in type comment and annotation\">baz1</warning>(a: int):\n" +
|
||||
" <warning descr=\"Type(s) specified both in type comment and annotation\"># type: (int) -> int</warning>\n" +
|
||||
" pass\n" +
|
||||
" \n" +
|
||||
"def <warning descr=\"Type(s) specified both in type comment and annotation\">baz2</warning>(a) -> int:\n" +
|
||||
" <warning descr=\"Type(s) specified both in type comment and annotation\"># type: (int) -> int</warning>\n" +
|
||||
" pass"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
@@ -95,4 +95,9 @@ class PyTypeHintsQuickFixTest : PyQuickFixTestCase() {
|
||||
fun testSelfInTypeComment() {
|
||||
doQuickFixTest(PyTypeHintsInspection::class.java, "Replace with type name")
|
||||
}
|
||||
|
||||
// PY-20530
|
||||
fun testFunctionAnnotationAndTypeComment() {
|
||||
doQuickFixTest(PyTypeHintsInspection::class.java, "Remove function annotations", LanguageLevel.PYTHON35)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user