[FIR] Implement PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL
^KT-59382 Fixed
This commit is contained in:
committed by
Space Team
parent
00fb927624
commit
4bba93f633
+7
@@ -724,6 +724,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL) { firDiagnostic ->
|
||||||
|
ProtectedConstructorNotInSuperCallImpl(
|
||||||
|
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||||
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
}
|
||||||
add(FirErrors.SUPERTYPE_NOT_INITIALIZED) { firDiagnostic ->
|
add(FirErrors.SUPERTYPE_NOT_INITIALIZED) { firDiagnostic ->
|
||||||
SupertypeNotInitializedImpl(
|
SupertypeNotInitializedImpl(
|
||||||
firDiagnostic as KtPsiDiagnostic,
|
firDiagnostic as KtPsiDiagnostic,
|
||||||
|
|||||||
+5
@@ -542,6 +542,11 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = PrimaryConstructorDelegationCallExpected::class
|
override val diagnosticClass get() = PrimaryConstructorDelegationCallExpected::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ProtectedConstructorNotInSuperCall : KtFirDiagnostic<KtExpression> {
|
||||||
|
override val diagnosticClass get() = ProtectedConstructorNotInSuperCall::class
|
||||||
|
val symbol: KtSymbol
|
||||||
|
}
|
||||||
|
|
||||||
interface SupertypeNotInitialized : KtFirDiagnostic<KtTypeReference> {
|
interface SupertypeNotInitialized : KtFirDiagnostic<KtTypeReference> {
|
||||||
override val diagnosticClass get() = SupertypeNotInitialized::class
|
override val diagnosticClass get() = SupertypeNotInitialized::class
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -640,6 +640,12 @@ internal class PrimaryConstructorDelegationCallExpectedImpl(
|
|||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.PrimaryConstructorDelegationCallExpected
|
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.PrimaryConstructorDelegationCallExpected
|
||||||
|
|
||||||
|
internal class ProtectedConstructorNotInSuperCallImpl(
|
||||||
|
override val symbol: KtSymbol,
|
||||||
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
|
token: KtLifetimeToken,
|
||||||
|
) : KtAbstractFirDiagnostic<KtExpression>(firDiagnostic, token), KtFirDiagnostic.ProtectedConstructorNotInSuperCall
|
||||||
|
|
||||||
internal class SupertypeNotInitializedImpl(
|
internal class SupertypeNotInitializedImpl(
|
||||||
firDiagnostic: KtPsiDiagnostic,
|
firDiagnostic: KtPsiDiagnostic,
|
||||||
token: KtLifetimeToken,
|
token: KtLifetimeToken,
|
||||||
|
|||||||
+3
@@ -259,6 +259,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
|||||||
val NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED by error<PsiElement>()
|
val NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED by error<PsiElement>()
|
||||||
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by error<PsiElement>()
|
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by error<PsiElement>()
|
||||||
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by error<PsiElement>(PositioningStrategy.SECONDARY_CONSTRUCTOR_DELEGATION_CALL)
|
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by error<PsiElement>(PositioningStrategy.SECONDARY_CONSTRUCTOR_DELEGATION_CALL)
|
||||||
|
val PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL by error<KtExpression> {
|
||||||
|
parameter<FirBasedSymbol<*>>("symbol")
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: change it to KtSuperTypeEntry when possible (after re-targeter implementation)
|
// TODO: change it to KtSuperTypeEntry when possible (after re-targeter implementation)
|
||||||
val SUPERTYPE_NOT_INITIALIZED by error<KtTypeReference>()
|
val SUPERTYPE_NOT_INITIALIZED by error<KtTypeReference>()
|
||||||
|
|||||||
@@ -224,6 +224,7 @@ object FirErrors {
|
|||||||
val NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED by error0<PsiElement>()
|
val NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED by error0<PsiElement>()
|
||||||
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by error0<PsiElement>()
|
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by error0<PsiElement>()
|
||||||
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL)
|
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.SECONDARY_CONSTRUCTOR_DELEGATION_CALL)
|
||||||
|
val PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL by error1<KtExpression, FirBasedSymbol<*>>()
|
||||||
val SUPERTYPE_NOT_INITIALIZED by error0<KtTypeReference>()
|
val SUPERTYPE_NOT_INITIALIZED by error0<KtTypeReference>()
|
||||||
val SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR by error0<PsiElement>()
|
val SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR by error0<PsiElement>()
|
||||||
val DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR by error0<PsiElement>()
|
val DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR by error0<PsiElement>()
|
||||||
|
|||||||
+1
@@ -70,6 +70,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
FirNamedVarargChecker,
|
FirNamedVarargChecker,
|
||||||
FirUnderscoredTypeArgumentSyntaxChecker,
|
FirUnderscoredTypeArgumentSyntaxChecker,
|
||||||
FirContractNotFirstStatementChecker,
|
FirContractNotFirstStatementChecker,
|
||||||
|
FirProtectedConstructorNotInSuperCallChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
|
override val propertyAccessExpressionCheckers: Set<FirPropertyAccessExpressionChecker>
|
||||||
|
|||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.expression
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
|
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.getConstructedClass
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.isJavaOrEnhancement
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.originalIfFakeOverride
|
||||||
|
import org.jetbrains.kotlin.fir.packageFqName
|
||||||
|
import org.jetbrains.kotlin.fir.references.isError
|
||||||
|
import org.jetbrains.kotlin.fir.references.resolved
|
||||||
|
import org.jetbrains.kotlin.fir.references.toResolvedConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.util.PrivateForInline
|
||||||
|
|
||||||
|
object FirProtectedConstructorNotInSuperCallChecker : FirFunctionCallChecker() {
|
||||||
|
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val reference = expression.calleeReference.resolved ?: return
|
||||||
|
val symbol = reference.toResolvedConstructorSymbol() ?: return
|
||||||
|
val constructedClass = symbol.getConstructedClass(context.session)
|
||||||
|
|
||||||
|
if (
|
||||||
|
!shouldAllowSuchCallNonetheless(symbol, context) &&
|
||||||
|
symbol.visibility.normalize() == Visibilities.Protected &&
|
||||||
|
// Prevent reporting for already invisible references
|
||||||
|
!reference.isError() &&
|
||||||
|
context.containingDeclarations.none { it.symbol == constructedClass }
|
||||||
|
) {
|
||||||
|
reporter.reportOn(expression.calleeReference.source, FirErrors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL, symbol, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(PrivateForInline::class)
|
||||||
|
private fun shouldAllowSuchCallNonetheless(symbol: FirConstructorSymbol, context: CheckerContext): Boolean {
|
||||||
|
val containingFile = context.containingFile ?: return false
|
||||||
|
val original = symbol.originalIfFakeOverride() ?: symbol
|
||||||
|
return original.origin.isJavaOrEnhancement && original.callableId.packageName == containingFile.packageFqName
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -476,6 +476,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_WITH_NO_
|
|||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CALL_FROM_PUBLIC_INLINE_ERROR
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.QUALIFIED_SUPERTYPE_EXTENDED_BY_OTHER_SUPERTYPE
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_IMPLICIT_TYPES
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_IMPLICIT_TYPES
|
||||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_INLINE
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.RECURSION_IN_INLINE
|
||||||
@@ -841,6 +842,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
|||||||
map.put(NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED, "Constructor must be private or protected in sealed class")
|
map.put(NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED, "Constructor must be private or protected in sealed class")
|
||||||
map.put(CYCLIC_CONSTRUCTOR_DELEGATION_CALL, "There's a cycle in the delegation calls chain")
|
map.put(CYCLIC_CONSTRUCTOR_DELEGATION_CALL, "There's a cycle in the delegation calls chain")
|
||||||
map.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, "Primary constructor call expected")
|
map.put(PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED, "Primary constructor call expected")
|
||||||
|
map.put(PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL, "Protected constructor ''{0}'' from other classes can only be used in super-call", SYMBOL)
|
||||||
map.put(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, "Supertype initialization is impossible without primary constructor")
|
map.put(SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, "Supertype initialization is impossible without primary constructor")
|
||||||
map.put(DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, "Call to super is not allowed in enum constructor")
|
map.put(DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR, "Call to super is not allowed in enum constructor")
|
||||||
map.put(PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS, "Primary constructor required for data class")
|
map.put(PRIMARY_CONSTRUCTOR_REQUIRED_FOR_DATA_CLASS, "Primary constructor required for data class")
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
// FILE: GA.kt
|
|
||||||
|
|
||||||
package test.x
|
|
||||||
|
|
||||||
open class GA<T> protected constructor()
|
|
||||||
|
|
||||||
// FILE: Main.kt
|
|
||||||
package test
|
|
||||||
|
|
||||||
import test.x.GA
|
|
||||||
|
|
||||||
class C : GA<Any>() {
|
|
||||||
companion object {
|
|
||||||
fun bar() = GA<Any>() // Should be error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
C.bar()
|
|
||||||
}
|
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
// FILE: GA.kt
|
// FILE: GA.kt
|
||||||
|
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ open class Foo protected constructor()
|
|||||||
inline fun foo(f: () -> Unit) = object: Foo() {}
|
inline fun foo(f: () -> Unit) = object: Foo() {}
|
||||||
|
|
||||||
class A : Foo() {
|
class A : Foo() {
|
||||||
inline fun foo(f: () -> Unit) = <!PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE!>Foo<!>()
|
inline fun foo(f: () -> Unit) = <!PROTECTED_CONSTRUCTOR_CALL_FROM_PUBLIC_INLINE, PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL!>Foo<!>()
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
-26
@@ -1,26 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
open class A protected constructor(x: Int) {
|
|
||||||
protected constructor() : this(1)
|
|
||||||
public constructor(x: Double) : this(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
class B4 : A(1) {
|
|
||||||
init {
|
|
||||||
A()
|
|
||||||
A(1)
|
|
||||||
A(5.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun foo() {
|
|
||||||
A()
|
|
||||||
A(1)
|
|
||||||
A(5.0)
|
|
||||||
|
|
||||||
object : A() {}
|
|
||||||
object : A(1) {}
|
|
||||||
object : A(5.0) {}
|
|
||||||
|
|
||||||
class Local : A()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
open class A protected constructor(x: Int) {
|
open class A protected constructor(x: Int) {
|
||||||
|
|||||||
-32
@@ -1,32 +0,0 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
|
||||||
|
|
||||||
// FILE: abc/A.java
|
|
||||||
package abc;
|
|
||||||
public class A {
|
|
||||||
protected A() {}
|
|
||||||
protected A(int x) {}
|
|
||||||
public A(double x) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FILE: main.kt
|
|
||||||
import abc.*
|
|
||||||
|
|
||||||
class B4 : A(1) {
|
|
||||||
init {
|
|
||||||
A()
|
|
||||||
A(1)
|
|
||||||
A(5.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun foo() {
|
|
||||||
A()
|
|
||||||
A(1)
|
|
||||||
A(5.0)
|
|
||||||
|
|
||||||
object : A() {}
|
|
||||||
object : A(1) {}
|
|
||||||
object : A(5.0) {}
|
|
||||||
|
|
||||||
class Local : A()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+1
@@ -1,3 +1,4 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
|
||||||
// FILE: abc/A.java
|
// FILE: abc/A.java
|
||||||
|
|||||||
+2
-2
@@ -21,8 +21,8 @@ val test3a = MyClass(1.0)
|
|||||||
class MyDerived : MyClass(1.0) {
|
class MyDerived : MyClass(1.0) {
|
||||||
val test4 = <!INVISIBLE_REFERENCE!>MyAlias<!>(1)
|
val test4 = <!INVISIBLE_REFERENCE!>MyAlias<!>(1)
|
||||||
val test4a = <!INVISIBLE_REFERENCE!>MyClass<!>(1)
|
val test4a = <!INVISIBLE_REFERENCE!>MyClass<!>(1)
|
||||||
val test5 = MyAlias("")
|
val test5 = <!PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL!>MyAlias<!>("")
|
||||||
val test5a = MyClass("")
|
val test5a = <!PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL!>MyClass<!>("")
|
||||||
val test6 = MyAlias(1.0)
|
val test6 = MyAlias(1.0)
|
||||||
val test6a = MyClass(1.0)
|
val test6a = MyClass(1.0)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user