[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,
|
||||
)
|
||||
}
|
||||
add(FirErrors.PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL) { firDiagnostic ->
|
||||
ProtectedConstructorNotInSuperCallImpl(
|
||||
firSymbolBuilder.buildSymbol(firDiagnostic.a),
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.SUPERTYPE_NOT_INITIALIZED) { firDiagnostic ->
|
||||
SupertypeNotInitializedImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+5
@@ -542,6 +542,11 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = PrimaryConstructorDelegationCallExpected::class
|
||||
}
|
||||
|
||||
interface ProtectedConstructorNotInSuperCall : KtFirDiagnostic<KtExpression> {
|
||||
override val diagnosticClass get() = ProtectedConstructorNotInSuperCall::class
|
||||
val symbol: KtSymbol
|
||||
}
|
||||
|
||||
interface SupertypeNotInitialized : KtFirDiagnostic<KtTypeReference> {
|
||||
override val diagnosticClass get() = SupertypeNotInitialized::class
|
||||
}
|
||||
|
||||
+6
@@ -640,6 +640,12 @@ internal class PrimaryConstructorDelegationCallExpectedImpl(
|
||||
token: KtLifetimeToken,
|
||||
) : 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(
|
||||
firDiagnostic: KtPsiDiagnostic,
|
||||
token: KtLifetimeToken,
|
||||
|
||||
+3
@@ -259,6 +259,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val NON_PRIVATE_OR_PROTECTED_CONSTRUCTOR_IN_SEALED 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 PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL by error<KtExpression> {
|
||||
parameter<FirBasedSymbol<*>>("symbol")
|
||||
}
|
||||
|
||||
// TODO: change it to KtSuperTypeEntry when possible (after re-targeter implementation)
|
||||
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 CYCLIC_CONSTRUCTOR_DELEGATION_CALL by error0<PsiElement>()
|
||||
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_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR by error0<PsiElement>()
|
||||
val DELEGATION_SUPER_CALL_IN_ENUM_CONSTRUCTOR by error0<PsiElement>()
|
||||
|
||||
+1
@@ -70,6 +70,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirNamedVarargChecker,
|
||||
FirUnderscoredTypeArgumentSyntaxChecker,
|
||||
FirContractNotFirstStatementChecker,
|
||||
FirProtectedConstructorNotInSuperCallChecker,
|
||||
)
|
||||
|
||||
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_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_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.RECURSION_IN_IMPLICIT_TYPES
|
||||
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(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(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(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")
|
||||
|
||||
@@ -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
|
||||
// FILE: GA.kt
|
||||
|
||||
|
||||
@@ -5,5 +5,5 @@ open class Foo protected constructor()
|
||||
inline fun foo(f: () -> Unit) = object: 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
|
||||
|
||||
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
|
||||
|
||||
// FILE: abc/A.java
|
||||
|
||||
+2
-2
@@ -21,8 +21,8 @@ val test3a = MyClass(1.0)
|
||||
class MyDerived : MyClass(1.0) {
|
||||
val test4 = <!INVISIBLE_REFERENCE!>MyAlias<!>(1)
|
||||
val test4a = <!INVISIBLE_REFERENCE!>MyClass<!>(1)
|
||||
val test5 = MyAlias("")
|
||||
val test5a = MyClass("")
|
||||
val test5 = <!PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL!>MyAlias<!>("")
|
||||
val test5a = <!PROTECTED_CONSTRUCTOR_NOT_IN_SUPER_CALL!>MyClass<!>("")
|
||||
val test6 = MyAlias(1.0)
|
||||
val test6a = MyClass(1.0)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user