[FIR] Add SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC
This commit is contained in:
committed by
teamcityserver
parent
55990f65cb
commit
dd46c36b24
+1
-1
@@ -34,7 +34,7 @@ class Derived : Protected() {
|
||||
Nested().<!INVISIBLE_REFERENCE!>bar<!>() // hidden
|
||||
|
||||
fromCompanion()
|
||||
protectedFromCompanion()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>protectedFromCompanion<!>()
|
||||
}
|
||||
|
||||
private class NestedDerived : Nested() {
|
||||
|
||||
+1
-1
@@ -5,5 +5,5 @@ abstract class A {
|
||||
}
|
||||
|
||||
class B : A() {
|
||||
val y: String = PROTECTED_CONST
|
||||
val y: String = <!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>PROTECTED_CONST<!>
|
||||
}
|
||||
|
||||
+1
@@ -163,5 +163,6 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
||||
DefaultMethodsCallFromJava6TargetError,
|
||||
PositioningStrategy.REFERENCE_BY_QUALIFIED
|
||||
)
|
||||
val SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -110,5 +110,6 @@ object FirJvmErrors {
|
||||
val JVM_SYNTHETIC_ON_DELEGATE by error0<KtAnnotationEntry>()
|
||||
val DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET by deprecationError0<PsiElement>(DefaultMethodsCallFromJava6TargetError, SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val INTERFACE_STATIC_METHOD_CALL_FROM_JAVA6_TARGET by deprecationError0<PsiElement>(DefaultMethodsCallFromJava6TargetError, SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
val SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
|
||||
|
||||
}
|
||||
|
||||
+6
-4
@@ -5,13 +5,15 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.jvm.checkers
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessExpressionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.*
|
||||
|
||||
object JvmExpressionCheckers : ExpressionCheckers() {
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
get() = setOf(
|
||||
FirJvmProtectedInSuperClassCompanionCallChecker
|
||||
)
|
||||
|
||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||
get() = setOf(
|
||||
FirInterfaceDefaultMethodCallChecker
|
||||
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirQualifiedAccessChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingDeclarationSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.getAnnotationByClassId
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.isCompanion
|
||||
import org.jetbrains.kotlin.fir.declarations.utils.visibility
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirVariableAssignment
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.toResolvedCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
import org.jetbrains.kotlin.resolve.annotations.JVM_STATIC_ANNOTATION_CLASS_ID
|
||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
||||
|
||||
object FirJvmProtectedInSuperClassCompanionCallChecker : FirQualifiedAccessChecker() {
|
||||
override fun check(expression: FirQualifiedAccess, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val dispatchReceiver = expression.dispatchReceiver
|
||||
if (dispatchReceiver is FirNoReceiverExpression) return
|
||||
val dispatchClassSymbol = dispatchReceiver.typeRef.toRegularClassSymbol(context.session) ?: return
|
||||
val resolvedSymbol = expression.calleeReference.toResolvedCallableSymbol() ?: return
|
||||
|
||||
val visibility = if (resolvedSymbol is FirPropertySymbol) {
|
||||
if (expression is FirVariableAssignment)
|
||||
resolvedSymbol.setterSymbol?.visibility ?: resolvedSymbol.visibility
|
||||
else
|
||||
resolvedSymbol.getterSymbol?.visibility ?: resolvedSymbol.visibility
|
||||
} else {
|
||||
resolvedSymbol.visibility
|
||||
}
|
||||
if (visibility != Visibilities.Protected) return
|
||||
if (resolvedSymbol.getAnnotationByClassId(JVM_STATIC_ANNOTATION_CLASS_ID) != null) return
|
||||
if (!dispatchClassSymbol.isCompanion) return
|
||||
val companionContainingClassSymbol =
|
||||
dispatchClassSymbol.getContainingDeclarationSymbol(context.session) as? FirRegularClassSymbol ?: return
|
||||
|
||||
// Called from within a derived class
|
||||
val companionContainingType = companionContainingClassSymbol.defaultType()
|
||||
if (context.findClosest<FirClass> {
|
||||
AbstractTypeChecker.isSubtypeOf(context.session.typeContext, it.symbol.defaultType(), companionContainingType)
|
||||
} == null
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
// Called not within the same companion object or its owner class
|
||||
if (context.findClosest<FirClass> {
|
||||
it.symbol == dispatchClassSymbol || it.symbol == companionContainingClassSymbol
|
||||
} == null
|
||||
) {
|
||||
reporter.reportOn(expression.calleeReference.source, FirJvmErrors.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.resolve.annotations
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
||||
@@ -26,6 +27,7 @@ import org.jetbrains.kotlin.resolve.constants.ErrorValue
|
||||
// This annotation is declared here in frontend (as opposed to frontend.java) because it's used in MainFunctionDetector.
|
||||
// If you wish to add another JVM-related annotation and has/find utility methods, please proceed to jvmAnnotationUtil.kt
|
||||
val JVM_STATIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmStatic")
|
||||
val JVM_STATIC_ANNOTATION_CLASS_ID = ClassId.topLevel(JVM_STATIC_ANNOTATION_FQ_NAME)
|
||||
|
||||
fun DeclarationDescriptor.hasJvmStaticAnnotation(): Boolean {
|
||||
return annotations.findAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) != null
|
||||
|
||||
@@ -28,6 +28,6 @@ class B: A() {
|
||||
devNull(A.internal_val)
|
||||
devNull(A.public_val)
|
||||
devNull(A.<!INVISIBLE_REFERENCE!>private_val<!>)
|
||||
devNull(A.protected_val)
|
||||
devNull(A.<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>protected_val<!>)
|
||||
}
|
||||
}
|
||||
|
||||
+12
-12
@@ -3,7 +3,7 @@ open class VeryBase {
|
||||
}
|
||||
|
||||
open class Base {
|
||||
protected fun foo() {
|
||||
protected fun foo() {
|
||||
bar() // Ok
|
||||
baz() // Ok
|
||||
}
|
||||
@@ -25,14 +25,14 @@ open class Base {
|
||||
baz() // Ok
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object : VeryBase() {
|
||||
var prop = 42
|
||||
protected set
|
||||
|
||||
protected fun bar() {}
|
||||
|
||||
@JvmStatic protected fun gav() {}
|
||||
@JvmStatic protected fun gav() {}
|
||||
|
||||
class Nested {
|
||||
fun fromNested() {
|
||||
@@ -47,27 +47,27 @@ class Derived : Base() {
|
||||
fun test() {
|
||||
foo() // Ok
|
||||
gav() // Ok
|
||||
bar()
|
||||
baz()
|
||||
prop = 0
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>prop<!> = 0
|
||||
}
|
||||
|
||||
inner class DerivedInner {
|
||||
fun fromDerivedInner() {
|
||||
foo() // Ok
|
||||
gav() // Ok
|
||||
bar()
|
||||
baz()
|
||||
prop = 0
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>prop<!> = 0
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun test2() {
|
||||
gav() // Ok
|
||||
bar()
|
||||
baz()
|
||||
prop = 0
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
|
||||
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>prop<!> = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -3,7 +3,7 @@ open class VeryBase {
|
||||
}
|
||||
|
||||
open class Base {
|
||||
protected fun foo() {
|
||||
protected fun foo() {
|
||||
bar() // Ok
|
||||
baz() // Ok
|
||||
}
|
||||
@@ -25,14 +25,14 @@ open class Base {
|
||||
baz() // Ok
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object : VeryBase() {
|
||||
var prop = 42
|
||||
protected set
|
||||
|
||||
protected fun bar() {}
|
||||
|
||||
@JvmStatic protected fun gav() {}
|
||||
@JvmStatic protected fun gav() {}
|
||||
|
||||
class Nested {
|
||||
fun fromNested() {
|
||||
|
||||
+6
@@ -4028,4 +4028,10 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC) { firDiagnostic ->
|
||||
SubclassCantCallCompanionProtectedNonStaticImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -2803,4 +2803,8 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = InterfaceStaticMethodCallFromJava6TargetWarning::class
|
||||
}
|
||||
|
||||
abstract class SubclassCantCallCompanionProtectedNonStatic : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = SubclassCantCallCompanionProtectedNonStatic::class
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+7
@@ -4559,3 +4559,10 @@ internal class InterfaceStaticMethodCallFromJava6TargetWarningImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class SubclassCantCallCompanionProtectedNonStaticImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.SubclassCantCallCompanionProtectedNonStatic(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user