diff --git a/python/src/com/jetbrains/python/inspections/PyDataclassInspection.kt b/python/src/com/jetbrains/python/inspections/PyDataclassInspection.kt
index d5e2d8058b4e..ca19fb8f64fd 100644
--- a/python/src/com/jetbrains/python/inspections/PyDataclassInspection.kt
+++ b/python/src/com/jetbrains/python/inspections/PyDataclassInspection.kt
@@ -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()
+ }
+ }
+ )
}
}
}
diff --git a/python/src/com/jetbrains/python/inspections/PyNamedTupleInspection.kt b/python/src/com/jetbrains/python/inspections/PyNamedTupleInspection.kt
index ebfe57ae331f..a69ac569fb5a 100644
--- a/python/src/com/jetbrains/python/inspections/PyNamedTupleInspection.kt
+++ b/python/src/com/jetbrains/python/inspections/PyNamedTupleInspection.kt
@@ -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)
}
}
diff --git a/python/testData/inspections/PyDataclassInspection/fieldsOrder.py b/python/testData/inspections/PyDataclassInspection/fieldsOrder.py
index 514f23bb0d65..06c0c3cf6492 100644
--- a/python/testData/inspections/PyDataclassInspection/fieldsOrder.py
+++ b/python/testData/inspections/PyDataclassInspection/fieldsOrder.py
@@ -36,4 +36,22 @@ class A4:
foo1: int
bar2: ClassVar = 2
baz2: int
- foo2: int = 3
\ No newline at end of file
+ foo2: int = 3
+
+
+@dataclasses.dataclass
+class B1:
+ a: int = dataclasses.field()
+ b: int
+
+
+@dataclasses.dataclass
+class B2:
+ a: int = dataclasses.field(default=1)
+ b: int = dataclasses.field()
+
+
+@dataclasses.dataclass
+class B3:
+ a: int = dataclasses.field(default_factory=int)
+ b: int = dataclasses.field()
\ No newline at end of file