mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Consider fields defined via field function while inspecting their order (PY-27398)
This commit is contained in:
@@ -68,7 +68,20 @@ class PyDataclassInspection : PyInspection() {
|
||||
processPostInitDefinition(postInit, dataclassParameters, initVars)
|
||||
}
|
||||
|
||||
PyNamedTupleInspection.inspectFieldsOrder(node, myTypeEvalContext, this::registerProblem)
|
||||
PyNamedTupleInspection.inspectFieldsOrder(
|
||||
node,
|
||||
this::registerProblem,
|
||||
{ !PyTypingTypeProvider.isClassVar(it, myTypeEvalContext) },
|
||||
{
|
||||
val fieldStub = PyDataclassFieldStubImpl.create(it)
|
||||
if (fieldStub != null) {
|
||||
fieldStub.hasDefault() || fieldStub.hasDefaultFactory()
|
||||
}
|
||||
else {
|
||||
it.hasAssignedValue()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,18 +9,19 @@ import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.ResolveState
|
||||
import com.intellij.psi.scope.PsiScopeProcessor
|
||||
import com.jetbrains.python.codeInsight.stdlib.PyStdlibTypeProvider
|
||||
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.psi.PyClass
|
||||
import com.jetbrains.python.psi.PyTargetExpression
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext
|
||||
import java.util.*
|
||||
|
||||
class PyNamedTupleInspection : PyInspection() {
|
||||
|
||||
companion object {
|
||||
fun inspectFieldsOrder(cls: PyClass, context: TypeEvalContext, callback: (PsiElement, String, ProblemHighlightType) -> Unit) {
|
||||
val fieldsProcessor = FieldsProcessor(context)
|
||||
fun inspectFieldsOrder(cls: PyClass,
|
||||
callback: (PsiElement, String, ProblemHighlightType) -> Unit,
|
||||
filter: (PyTargetExpression) -> Boolean = { true },
|
||||
hasAssignedValue: (PyTargetExpression) -> Boolean = PyTargetExpression::hasAssignedValue) {
|
||||
val fieldsProcessor = FieldsProcessor(filter, hasAssignedValue)
|
||||
|
||||
cls.processClassLevelDeclarations(fieldsProcessor)
|
||||
|
||||
@@ -54,12 +55,13 @@ class PyNamedTupleInspection : PyInspection() {
|
||||
if (node != null &&
|
||||
LanguageLevel.forElement(node).isAtLeast(LanguageLevel.PYTHON36) &&
|
||||
PyStdlibTypeProvider.isTypingNamedTupleDirectInheritor(node, myTypeEvalContext)) {
|
||||
inspectFieldsOrder(node, myTypeEvalContext, this::registerProblem)
|
||||
inspectFieldsOrder(node, this::registerProblem)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FieldsProcessor(private val context: TypeEvalContext) : PsiScopeProcessor {
|
||||
private class FieldsProcessor(private val filter: (PyTargetExpression) -> Boolean,
|
||||
private val hasAssignedValue: (PyTargetExpression) -> Boolean) : PsiScopeProcessor {
|
||||
|
||||
val lastFieldWithoutDefaultValue: PyTargetExpression?
|
||||
get() = lastFieldWithoutDefaultValueBox.result
|
||||
@@ -74,13 +76,9 @@ class PyNamedTupleInspection : PyInspection() {
|
||||
}
|
||||
|
||||
override fun execute(element: PsiElement, state: ResolveState): Boolean {
|
||||
if (element is PyTargetExpression) {
|
||||
if (PyTypingTypeProvider.isClassVar(element, context)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (element is PyTargetExpression && filter(element)) {
|
||||
when {
|
||||
element.findAssignedValue() != null -> fieldsWithDefaultValue.add(element)
|
||||
hasAssignedValue(element) -> fieldsWithDefaultValue.add(element)
|
||||
else -> lastFieldWithoutDefaultValueBox.apply(element)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,4 +36,22 @@ class A4:
|
||||
foo1: int
|
||||
bar2: ClassVar = 2
|
||||
baz2: int
|
||||
foo2: int = 3
|
||||
foo2: int = 3
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class B1:
|
||||
a: int = dataclasses.field()
|
||||
b: int
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class B2:
|
||||
<error descr="Fields with a default value must come after any fields without a default.">a</error>: int = dataclasses.field(default=1)
|
||||
b: int = dataclasses.field()
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class B3:
|
||||
<error descr="Fields with a default value must come after any fields without a default.">a</error>: int = dataclasses.field(default_factory=int)
|
||||
b: int = dataclasses.field()
|
||||
Reference in New Issue
Block a user