[FIR] Fix incorrect diagnostic behaviour + several enum diagnostics
This commit is contained in:
Vendored
+6
@@ -0,0 +1,6 @@
|
|||||||
|
enum class A {
|
||||||
|
A(1), B(2), C("test");
|
||||||
|
|
||||||
|
constructor(x: Int) : <!DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR!>super<!>()
|
||||||
|
constructor(t: String) : this(10)
|
||||||
|
}
|
||||||
Vendored
+38
@@ -0,0 +1,38 @@
|
|||||||
|
FILE: delegationSuperCallInEnumConstructor.kt
|
||||||
|
public final enum class A : R|kotlin/Enum<A>| {
|
||||||
|
public final static enum entry A: R|A| = object : R|A| {
|
||||||
|
private constructor(): R|<anonymous>| {
|
||||||
|
super<R|A|>(Int(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static enum entry B: R|A| = object : R|A| {
|
||||||
|
private constructor(): R|<anonymous>| {
|
||||||
|
super<R|A|>(Int(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static enum entry C: R|A| = object : R|A| {
|
||||||
|
private constructor(): R|<anonymous>| {
|
||||||
|
super<R|A|>(String(test))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor(x: R|kotlin/Int|): R|A| {
|
||||||
|
super<R|kotlin/Enum<A>|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor(t: R|kotlin/String|): R|A| {
|
||||||
|
this<R|A|>(Int(10))
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static fun values(): R|kotlin/Array<A>| {
|
||||||
|
}
|
||||||
|
|
||||||
|
public final static fun valueOf(value: R|kotlin/String|): R|A| {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
class A(x: Int) {
|
||||||
|
constructor(z: String) : this(10)
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A {
|
||||||
|
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor()<!>
|
||||||
|
constructor(z: String) : this()
|
||||||
|
}
|
||||||
|
|
||||||
|
<!SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>class C : A(20) {
|
||||||
|
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor()<!>
|
||||||
|
constructor(z: String) : this()
|
||||||
|
}<!>
|
||||||
|
|
||||||
|
class D() : A(20) {
|
||||||
|
<!NONE_APPLICABLE, PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(x: Int)<!>
|
||||||
|
constructor(z: String) : this()
|
||||||
|
}
|
||||||
Vendored
+45
@@ -0,0 +1,45 @@
|
|||||||
|
FILE: explicitDelegationCallRequired.kt
|
||||||
|
public final class A : R|kotlin/Any| {
|
||||||
|
public constructor(x: R|kotlin/Int|): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(z: R|kotlin/String|): R|A| {
|
||||||
|
this<R|A|>(Int(10))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class B : R|A| {
|
||||||
|
public constructor(): R|B| {
|
||||||
|
super<R|A|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(z: R|kotlin/String|): R|B| {
|
||||||
|
this<R|B|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class C : R|A| {
|
||||||
|
public constructor(): R|C| {
|
||||||
|
super<R|A|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(z: R|kotlin/String|): R|C| {
|
||||||
|
this<R|C|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final class D : R|A| {
|
||||||
|
public constructor(): R|D| {
|
||||||
|
super<R|A|>(Int(20))
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(x: R|kotlin/Int|): R|D| {
|
||||||
|
super<R|A|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(z: R|kotlin/String|): R|D| {
|
||||||
|
this<R|D|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Vendored
+9
@@ -0,0 +1,9 @@
|
|||||||
|
data class A {}
|
||||||
|
|
||||||
|
<!PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS!>data class B {
|
||||||
|
constructor()
|
||||||
|
}<!>
|
||||||
|
|
||||||
|
<!PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS!>data class C {
|
||||||
|
constructor(x: Int)
|
||||||
|
}<!>
|
||||||
Vendored
+21
@@ -0,0 +1,21 @@
|
|||||||
|
FILE: primaryConstructorRequiredForDataClass.kt
|
||||||
|
public final data class A : R|kotlin/Any| {
|
||||||
|
public constructor(): R|A| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
public final fun copy(): R|A|
|
||||||
|
|
||||||
|
}
|
||||||
|
public final data class B : R|kotlin/Any| {
|
||||||
|
public constructor(): R|B| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public final data class C : R|kotlin/Any| {
|
||||||
|
public constructor(x: R|kotlin/Int|): R|C| {
|
||||||
|
super<R|kotlin/Any|>()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Generated
+15
@@ -921,6 +921,16 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/cyclicConstructorDelegationCall.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/cyclicConstructorDelegationCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegationSuperCallInEnumConstructor.kt")
|
||||||
|
public void testDelegationSuperCallInEnumConstructor() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/delegationSuperCallInEnumConstructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("explicitDelegationCallRequired.kt")
|
||||||
|
public void testExplicitDelegationCallRequired() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/explicitDelegationCallRequired.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("incompatibleModifiers.kt")
|
@TestMetadata("incompatibleModifiers.kt")
|
||||||
public void testIncompatibleModifiers() throws Exception {
|
public void testIncompatibleModifiers() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
||||||
@@ -951,6 +961,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest {
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("primaryConstructorRequiredForDataClass.kt")
|
||||||
|
public void testPrimaryConstructorRequiredForDataClass() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/primaryConstructorRequiredForDataClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("projectionsOnNonClassTypeArguments.kt")
|
@TestMetadata("projectionsOnNonClassTypeArguments.kt")
|
||||||
public void testProjectionsOnNonClassTypeArguments() throws Exception {
|
public void testProjectionsOnNonClassTypeArguments() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/projectionsOnNonClassTypeArguments.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/projectionsOnNonClassTypeArguments.kt");
|
||||||
|
|||||||
+15
@@ -921,6 +921,16 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/cyclicConstructorDelegationCall.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/cyclicConstructorDelegationCall.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("delegationSuperCallInEnumConstructor.kt")
|
||||||
|
public void testDelegationSuperCallInEnumConstructor() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/delegationSuperCallInEnumConstructor.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("explicitDelegationCallRequired.kt")
|
||||||
|
public void testExplicitDelegationCallRequired() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/explicitDelegationCallRequired.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("incompatibleModifiers.kt")
|
@TestMetadata("incompatibleModifiers.kt")
|
||||||
public void testIncompatibleModifiers() throws Exception {
|
public void testIncompatibleModifiers() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/incompatibleModifiers.kt");
|
||||||
@@ -951,6 +961,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos
|
|||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/notASupertype.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("primaryConstructorRequiredForDataClass.kt")
|
||||||
|
public void testPrimaryConstructorRequiredForDataClass() throws Exception {
|
||||||
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/primaryConstructorRequiredForDataClass.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("projectionsOnNonClassTypeArguments.kt")
|
@TestMetadata("projectionsOnNonClassTypeArguments.kt")
|
||||||
public void testProjectionsOnNonClassTypeArguments() throws Exception {
|
public void testProjectionsOnNonClassTypeArguments() throws Exception {
|
||||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/projectionsOnNonClassTypeArguments.kt");
|
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/projectionsOnNonClassTypeArguments.kt");
|
||||||
|
|||||||
+3
-1
@@ -20,8 +20,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf(
|
override val memberDeclarationCheckers: List<FirMemberDeclarationChecker> = listOf(
|
||||||
FirInfixFunctionDeclarationChecker,
|
FirInfixFunctionDeclarationChecker,
|
||||||
FirExposedVisibilityDeclarationChecker,
|
FirExposedVisibilityDeclarationChecker,
|
||||||
FirCyclicConstructorDelegationCallChecker,
|
FirCommonConstructorDelegationIssuesChecker,
|
||||||
FirSupertypeInitializedWithoutPrimaryConstructor,
|
FirSupertypeInitializedWithoutPrimaryConstructor,
|
||||||
|
FirDelegationSuperCallInEnumConstructorChecker,
|
||||||
|
FirPrimaryConstructorRequiredForDataClassChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val constructorCheckers: List<FirConstructorChecker> = listOf(
|
override val constructorCheckers: List<FirConstructorChecker> = listOf(
|
||||||
|
|||||||
+29
-13
@@ -12,12 +12,12 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
|||||||
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker() {
|
object FirCommonConstructorDelegationIssuesChecker : FirMemberDeclarationChecker() {
|
||||||
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
if (declaration !is FirRegularClass) {
|
if (declaration !is FirRegularClass) {
|
||||||
return
|
return
|
||||||
@@ -26,9 +26,15 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
|||||||
val cyclicConstructors = mutableSetOf<FirConstructor>()
|
val cyclicConstructors = mutableSetOf<FirConstructor>()
|
||||||
var hasPrimaryConstructor = false
|
var hasPrimaryConstructor = false
|
||||||
|
|
||||||
|
// secondary; non-cyclic;
|
||||||
|
// candidates for further analysis
|
||||||
|
val otherConstructors = mutableSetOf<FirConstructor>()
|
||||||
|
|
||||||
for (it in declaration.declarations) {
|
for (it in declaration.declarations) {
|
||||||
if (it is FirConstructor) {
|
if (it is FirConstructor) {
|
||||||
if (!it.isPrimary) {
|
if (!it.isPrimary) {
|
||||||
|
otherConstructors += it
|
||||||
|
|
||||||
it.findCycle(cyclicConstructors)?.let { visited ->
|
it.findCycle(cyclicConstructors)?.let { visited ->
|
||||||
cyclicConstructors += visited
|
cyclicConstructors += visited
|
||||||
}
|
}
|
||||||
@@ -38,15 +44,26 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
otherConstructors -= cyclicConstructors
|
||||||
|
|
||||||
if (hasPrimaryConstructor) {
|
if (hasPrimaryConstructor) {
|
||||||
for (it in declaration.declarations) {
|
for (it in otherConstructors) {
|
||||||
if (
|
if (it.delegatedConstructor?.isThis == false) {
|
||||||
it is FirConstructor && !it.isPrimary && it !in cyclicConstructors &&
|
|
||||||
it.delegatedConstructor?.constructedTypeRef?.getType() != it.returnTypeRef.getType()
|
|
||||||
) {
|
|
||||||
reporter.reportPrimaryConstructorDelegationCallExpected(it.delegatedConstructor?.source)
|
reporter.reportPrimaryConstructorDelegationCallExpected(it.delegatedConstructor?.source)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for (it in otherConstructors) {
|
||||||
|
val callee = it.delegatedConstructor?.calleeReference
|
||||||
|
|
||||||
|
// couldn't find proper super() constructor implicitly
|
||||||
|
if (
|
||||||
|
callee is FirErrorNamedReference && callee.diagnostic is ConeAmbiguityError &&
|
||||||
|
it.delegatedConstructor?.source?.startOffset == it.delegatedConstructor?.source?.endOffset
|
||||||
|
) {
|
||||||
|
reporter.reportExplicitDelegationCallRequired(it.source)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cyclicConstructors.forEach {
|
cyclicConstructors.forEach {
|
||||||
@@ -78,11 +95,6 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
|||||||
?.resolvedSymbol
|
?.resolvedSymbol
|
||||||
?.fir.safeAs()
|
?.fir.safeAs()
|
||||||
|
|
||||||
private fun FirTypeRef.getType() = when (this) {
|
|
||||||
is FirResolvedTypeRef -> type
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun DiagnosticReporter.reportCyclicConstructorDelegationCall(source: FirSourceElement?) {
|
private fun DiagnosticReporter.reportCyclicConstructorDelegationCall(source: FirSourceElement?) {
|
||||||
source?.let { report(FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(it)) }
|
source?.let { report(FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(it)) }
|
||||||
}
|
}
|
||||||
@@ -90,4 +102,8 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
|||||||
private fun DiagnosticReporter.reportPrimaryConstructorDelegationCallExpected(source: FirSourceElement?) {
|
private fun DiagnosticReporter.reportPrimaryConstructorDelegationCallExpected(source: FirSourceElement?) {
|
||||||
source?.let { report(FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(it)) }
|
source?.let { report(FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun DiagnosticReporter.reportExplicitDelegationCallRequired(source: FirSourceElement?) {
|
||||||
|
source?.let { report(FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED.on(it)) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+40
@@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
|
||||||
|
object FirDelegationSuperCallInEnumConstructorChecker : FirMemberDeclarationChecker() {
|
||||||
|
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if (declaration !is FirRegularClass || declaration.classKind != ClassKind.ENUM_CLASS) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (it in declaration.declarations) {
|
||||||
|
// checking offsets is needed because we
|
||||||
|
// still have a real source element ("") here,
|
||||||
|
// even if the user hasn't written anything
|
||||||
|
if (
|
||||||
|
it is FirConstructor && !it.isPrimary &&
|
||||||
|
it.delegatedConstructor?.isThis == false &&
|
||||||
|
it.delegatedConstructor?.source?.startOffset != it.delegatedConstructor?.source?.endOffset
|
||||||
|
) {
|
||||||
|
reporter.report(it.delegatedConstructor?.source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DiagnosticReporter.report(source: FirSourceElement?) {
|
||||||
|
source?.let { report(FirErrors.DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR.on(it)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirConstructor
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.isData
|
||||||
|
|
||||||
|
object FirPrimaryConstructorRequiredForDataClassChecker : FirMemberDeclarationChecker() {
|
||||||
|
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
if (declaration !is FirRegularClass || declaration.classKind != ClassKind.CLASS || !declaration.isData) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasPrimaryConstructor = declaration.declarations.any { it is FirConstructor && it.isPrimary }
|
||||||
|
|
||||||
|
if (!hasPrimaryConstructor) {
|
||||||
|
reporter.report(declaration.source)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun DiagnosticReporter.report(source: FirSourceElement?) {
|
||||||
|
source?.let { report(FirErrors.PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS.on(it)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -67,6 +67,9 @@ object FirErrors {
|
|||||||
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by warning0<FirSourceElement, PsiElement>()
|
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by warning0<FirSourceElement, PsiElement>()
|
||||||
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by warning0<FirSourceElement, PsiElement>()
|
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by warning0<FirSourceElement, PsiElement>()
|
||||||
val SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR by warning0<FirSourceElement, PsiElement>()
|
val SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR by warning0<FirSourceElement, PsiElement>()
|
||||||
|
val DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR by warning0<FirSourceElement, PsiElement>()
|
||||||
|
val PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS by warning0<FirSourceElement, PsiElement>()
|
||||||
|
val EXPLICIT_DELEGATION_CALL_REQUIRED by warning0<FirSourceElement, PsiElement>()
|
||||||
|
|
||||||
// Exposed visibility group
|
// Exposed visibility group
|
||||||
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<FirSourceElement, PsiElement, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
|
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<FirSourceElement, PsiElement, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
|
||||||
|
|||||||
Vendored
+1
-1
@@ -8,7 +8,7 @@ expect open class A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
expect class B : A {
|
expect class B : A {
|
||||||
<!NONE_APPLICABLE!>constructor(i: Int)<!>
|
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor(i: Int)<!>
|
||||||
|
|
||||||
constructor() : super("B")
|
constructor() : super("B")
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -7,8 +7,8 @@ data class A2(val y: String, val z: Int) {
|
|||||||
constructor(x: String): this(x, 0)
|
constructor(x: String): this(x, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
data class A3 {
|
<!PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS!>data class A3 {
|
||||||
constructor()
|
constructor()
|
||||||
}
|
}<!>
|
||||||
|
|
||||||
data class A4 internal constructor()
|
data class A4 internal constructor()
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ enum class A {
|
|||||||
constructor(x: Int)
|
constructor(x: Int)
|
||||||
constructor(x: Int, y: Int): this(x+y)
|
constructor(x: Int, y: Int): this(x+y)
|
||||||
constructor(x: Double): this(x.toInt(), 1)
|
constructor(x: Double): this(x.toInt(), 1)
|
||||||
constructor(x: String): super(x, 1)
|
constructor(x: String): <!DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR!>super<!>(x, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class B(x: Int) {
|
enum class B(x: Int) {
|
||||||
@@ -14,7 +14,7 @@ enum class B(x: Int) {
|
|||||||
|
|
||||||
constructor(x: Int, y: Int): this(x+y)
|
constructor(x: Int, y: Int): this(x+y)
|
||||||
constructor(x: Double): this(x.toInt(), 1)
|
constructor(x: Double): this(x.toInt(), 1)
|
||||||
constructor(x: String): <!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>super<!>(x, 1)
|
constructor(x: String): <!DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>super<!>(x, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class C {
|
enum class C {
|
||||||
|
|||||||
Vendored
+1
-1
@@ -26,7 +26,7 @@ open class B2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class A2 : B2 {
|
class A2 : B2 {
|
||||||
<!NONE_APPLICABLE!>constructor()<!>
|
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor()<!>
|
||||||
constructor(x: Int) : <!NONE_APPLICABLE!>super<!>()
|
constructor(x: Int) : <!NONE_APPLICABLE!>super<!>()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -6,5 +6,5 @@ open class B(x: Double) {
|
|||||||
interface C
|
interface C
|
||||||
class A : B, C {
|
class A : B, C {
|
||||||
constructor(): <!NONE_APPLICABLE!>super<!>(' ')
|
constructor(): <!NONE_APPLICABLE!>super<!>(' ')
|
||||||
<!NONE_APPLICABLE!>constructor(x: Int)<!>
|
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor(x: Int)<!>
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user