[FIR] Add diagnostic for primary constructor not called
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
annotation class A() {
|
||||
<!ANNOTATION_CLASS_MEMBER!>constructor(s: Nothing?) {}<!>
|
||||
<!ANNOTATION_CLASS_MEMBER!><!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(s: Nothing?)<!> {}<!>
|
||||
<!ANNOTATION_CLASS_MEMBER!>init {}<!>
|
||||
<!ANNOTATION_CLASS_MEMBER!>fun foo() {}<!>
|
||||
<!ANNOTATION_CLASS_MEMBER!>val bar: Nothing?<!>
|
||||
|
||||
Vendored
+3
-3
@@ -42,16 +42,16 @@ class J<T> {
|
||||
}
|
||||
|
||||
class F(s: String) {
|
||||
constructor(i: Boolean) {}
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(i: Boolean)<!> {}
|
||||
constructor(i: Int) : <!CYCLIC_CONSTRUCTOR_DELEGATION_CALL!>this<!>(3) {}
|
||||
}
|
||||
|
||||
class G(x: Int) {
|
||||
constructor() {}
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor()<!> {}
|
||||
}
|
||||
|
||||
class H(x: Int) {
|
||||
constructor()
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor()<!>
|
||||
}
|
||||
|
||||
class K(x: Int) {
|
||||
|
||||
+30
-3
@@ -13,6 +13,8 @@ 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.FirResolvedNamedReference
|
||||
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
|
||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker() {
|
||||
@@ -22,11 +24,27 @@ object FirCyclicConstructorDelegationCallChecker : FirMemberDeclarationChecker()
|
||||
}
|
||||
|
||||
val cyclicConstructors = mutableSetOf<FirConstructor>()
|
||||
var hasPrimaryConstructor = false
|
||||
|
||||
for (it in declaration.declarations) {
|
||||
if (it is FirConstructor && !it.isPrimary) {
|
||||
it.findCycle(cyclicConstructors)?.let { visited ->
|
||||
cyclicConstructors += visited
|
||||
if (it is FirConstructor) {
|
||||
if (!it.isPrimary) {
|
||||
it.findCycle(cyclicConstructors)?.let { visited ->
|
||||
cyclicConstructors += visited
|
||||
}
|
||||
} else {
|
||||
hasPrimaryConstructor = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasPrimaryConstructor) {
|
||||
for (it in declaration.declarations) {
|
||||
if (
|
||||
it is FirConstructor && !it.isPrimary && it !in cyclicConstructors &&
|
||||
it.delegatedConstructor?.constructedTypeRef?.getType() != it.returnTypeRef.getType()
|
||||
) {
|
||||
reporter.reportPrimaryConstructorDelegationCallExpected(it.delegatedConstructor?.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,7 +78,16 @@ 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)) }
|
||||
}
|
||||
|
||||
private fun DiagnosticReporter.reportPrimaryConstructorDelegationCallExpected(source: FirSourceElement?) {
|
||||
source?.let { report(FirErrors.PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED.on(it)) }
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,7 @@ object FirErrors {
|
||||
val NOT_AN_ANNOTATION_CLASS by error1<FirSourceElement, PsiElement, String>()
|
||||
|
||||
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by warning0<FirSourceElement, PsiElement>()
|
||||
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by warning0<FirSourceElement, PsiElement>()
|
||||
|
||||
// Exposed visibility group
|
||||
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<FirSourceElement, PsiElement, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
|
||||
|
||||
+3
-3
@@ -2,7 +2,7 @@
|
||||
fun test(vararg x1: Int, vararg x2: Int) {
|
||||
fun test2(vararg x1: Int, vararg x2: Int) {
|
||||
class LocalClass(vararg x1: Int, vararg x2: Int) {
|
||||
constructor(vararg x1: Int, vararg x2: Int, xx: Int) {}
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(vararg x1: Int, vararg x2: Int, xx: Int)<!> {}
|
||||
}
|
||||
fun test3(vararg x1: Int, vararg x2: Int) {}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ abstract class C(vararg x1: Int, vararg x2: Int, b: Boolean) {
|
||||
abstract fun test2(vararg x1: Int, vararg x2: Int)
|
||||
|
||||
class CC(vararg x1: Int, vararg x2: Int, b: Boolean) {
|
||||
constructor(vararg x1: Int, vararg x2: Int) {}
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(vararg x1: Int, vararg x2: Int)<!> {}
|
||||
fun test(vararg x1: Int, vararg x2: Int) {}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ object O {
|
||||
fun test(vararg x1: Int, vararg x2: Int) {}
|
||||
|
||||
class CC(vararg x1: Int, vararg x2: Int, b: Boolean) {
|
||||
constructor(vararg x1: Int, vararg x2: Int) {}
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(vararg x1: Int, vararg x2: Int)<!> {}
|
||||
fun test(vararg x1: Int, vararg x2: Int) {}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ expect enum class En(x: Int) {
|
||||
E2(42),
|
||||
;
|
||||
|
||||
constructor(s: String)
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(s: String)<!>
|
||||
}
|
||||
|
||||
expect enum class En2 {
|
||||
|
||||
Vendored
+1
-1
@@ -9,7 +9,7 @@ expect class Foo(
|
||||
"no"
|
||||
}
|
||||
|
||||
constructor(s: String) {
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(s: String)<!> {
|
||||
"no"
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// FILE: common.kt
|
||||
|
||||
expect class Foo(zzz: Int) {
|
||||
constructor(aaa: Boolean)
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(aaa: Boolean)<!>
|
||||
|
||||
fun f1(xxx: String): String
|
||||
}
|
||||
|
||||
@@ -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): super(x, 1)
|
||||
constructor(x: String): <!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>super<!>(x, 1)
|
||||
}
|
||||
|
||||
enum class C {
|
||||
|
||||
Vendored
-8
@@ -1,8 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
class A(x: Int) {
|
||||
constructor()
|
||||
}
|
||||
open class B(x: Int)
|
||||
class C(x: Int) : B(x) {
|
||||
constructor(): super(1)
|
||||
}
|
||||
Vendored
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
class A(x: Int) {
|
||||
<!PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor()<!>
|
||||
|
||||
Vendored
+1
-1
@@ -2,6 +2,6 @@
|
||||
open class A(p1: String)
|
||||
|
||||
class B() : A("") {
|
||||
<!INAPPLICABLE_CANDIDATE!>constructor(s: String)<!> {
|
||||
<!INAPPLICABLE_CANDIDATE, PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED!>constructor(s: String)<!> {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user