[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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testIncompatibleModifiers() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("primaryConstructorRequiredForDataClass.kt")
|
||||
public void testPrimaryConstructorRequiredForDataClass() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/primaryConstructorRequiredForDataClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("projectionsOnNonClassTypeArguments.kt")
|
||||
public void testProjectionsOnNonClassTypeArguments() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testIncompatibleModifiers() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("primaryConstructorRequiredForDataClass.kt")
|
||||
public void testPrimaryConstructorRequiredForDataClass() throws Exception {
|
||||
runTest("compiler/fir/analysis-tests/testData/resolve/diagnostics/primaryConstructorRequiredForDataClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("projectionsOnNonClassTypeArguments.kt")
|
||||
public void testProjectionsOnNonClassTypeArguments() throws Exception {
|
||||
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(
|
||||
FirInfixFunctionDeclarationChecker,
|
||||
FirExposedVisibilityDeclarationChecker,
|
||||
FirCyclicConstructorDelegationCallChecker,
|
||||
FirCommonConstructorDelegationIssuesChecker,
|
||||
FirSupertypeInitializedWithoutPrimaryConstructor,
|
||||
FirDelegationSuperCallInEnumConstructorChecker,
|
||||
FirPrimaryConstructorRequiredForDataClassChecker,
|
||||
)
|
||||
|
||||
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.FirMemberDeclaration
|
||||
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.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker() {
|
||||
object FirCommonConstructorDelegationIssuesChecker : FirMemberDeclarationChecker() {
|
||||
override fun check(declaration: FirMemberDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration !is FirRegularClass) {
|
||||
return
|
||||
@@ -26,9 +26,15 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
||||
val cyclicConstructors = mutableSetOf<FirConstructor>()
|
||||
var hasPrimaryConstructor = false
|
||||
|
||||
// secondary; non-cyclic;
|
||||
// candidates for further analysis
|
||||
val otherConstructors = mutableSetOf<FirConstructor>()
|
||||
|
||||
for (it in declaration.declarations) {
|
||||
if (it is FirConstructor) {
|
||||
if (!it.isPrimary) {
|
||||
otherConstructors += it
|
||||
|
||||
it.findCycle(cyclicConstructors)?.let { visited ->
|
||||
cyclicConstructors += visited
|
||||
}
|
||||
@@ -38,15 +44,26 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
||||
}
|
||||
}
|
||||
|
||||
otherConstructors -= cyclicConstructors
|
||||
|
||||
if (hasPrimaryConstructor) {
|
||||
for (it in declaration.declarations) {
|
||||
if (
|
||||
it is FirConstructor && !it.isPrimary && it !in cyclicConstructors &&
|
||||
it.delegatedConstructor?.constructedTypeRef?.getType() != it.returnTypeRef.getType()
|
||||
) {
|
||||
for (it in otherConstructors) {
|
||||
if (it.delegatedConstructor?.isThis == false) {
|
||||
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 {
|
||||
@@ -78,11 +95,6 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
||||
?.resolvedSymbol
|
||||
?.fir.safeAs()
|
||||
|
||||
private fun FirTypeRef.getType() = when (this) {
|
||||
is FirResolvedTypeRef -> type
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportCyclicConstructorDelegationCall(source: FirSourceElement?) {
|
||||
source?.let { report(FirErrors.CYCLIC_CONSTRUCTOR_DELEGATION_CALL.on(it)) }
|
||||
}
|
||||
@@ -90,4 +102,8 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
||||
private fun DiagnosticReporter.reportPrimaryConstructorDelegationCallExpected(source: FirSourceElement?) {
|
||||
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 PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED 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
|
||||
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 {
|
||||
<!NONE_APPLICABLE!>constructor(i: Int)<!>
|
||||
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor(i: Int)<!>
|
||||
|
||||
constructor() : super("B")
|
||||
}
|
||||
|
||||
+2
-2
@@ -7,8 +7,8 @@ data class A2(val y: String, val z: Int) {
|
||||
constructor(x: String): this(x, 0)
|
||||
}
|
||||
|
||||
data class A3 {
|
||||
<!PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS!>data class A3 {
|
||||
constructor()
|
||||
}
|
||||
}<!>
|
||||
|
||||
data class A4 internal constructor()
|
||||
|
||||
@@ -6,7 +6,7 @@ enum class A {
|
||||
constructor(x: Int)
|
||||
constructor(x: Int, y: Int): this(x+y)
|
||||
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) {
|
||||
@@ -14,7 +14,7 @@ enum class B(x: Int) {
|
||||
|
||||
constructor(x: Int, y: Int): this(x+y)
|
||||
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 {
|
||||
|
||||
Vendored
+1
-1
@@ -26,7 +26,7 @@ open class B2 {
|
||||
}
|
||||
|
||||
class A2 : B2 {
|
||||
<!NONE_APPLICABLE!>constructor()<!>
|
||||
<!EXPLICIT_DELEGATION_CALL_REQUIRED, NONE_APPLICABLE!>constructor()<!>
|
||||
constructor(x: Int) : <!NONE_APPLICABLE!>super<!>()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -6,5 +6,5 @@ open class B(x: Double) {
|
||||
interface C
|
||||
class A : B, C {
|
||||
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