[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
|
Nested().<!INVISIBLE_REFERENCE!>bar<!>() // hidden
|
||||||
|
|
||||||
fromCompanion()
|
fromCompanion()
|
||||||
protectedFromCompanion()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>protectedFromCompanion<!>()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NestedDerived : Nested() {
|
private class NestedDerived : Nested() {
|
||||||
|
|||||||
+1
-1
@@ -5,5 +5,5 @@ abstract class A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class B : 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,
|
DefaultMethodsCallFromJava6TargetError,
|
||||||
PositioningStrategy.REFERENCE_BY_QUALIFIED
|
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 JVM_SYNTHETIC_ON_DELEGATE by error0<KtAnnotationEntry>()
|
||||||
val DEFAULT_METHOD_CALL_FROM_JAVA6_TARGET by deprecationError0<PsiElement>(DefaultMethodsCallFromJava6TargetError, SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
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 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
|
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.*
|
||||||
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.jvm.checkers.expression.*
|
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.*
|
||||||
|
|
||||||
object JvmExpressionCheckers : ExpressionCheckers() {
|
object JvmExpressionCheckers : ExpressionCheckers() {
|
||||||
|
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||||
|
get() = setOf(
|
||||||
|
FirJvmProtectedInSuperClassCompanionCallChecker
|
||||||
|
)
|
||||||
|
|
||||||
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
override val qualifiedAccessExpressionCheckers: Set<FirQualifiedAccessExpressionChecker>
|
||||||
get() = setOf(
|
get() = setOf(
|
||||||
FirInterfaceDefaultMethodCallChecker
|
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.DeclarationDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
|
||||||
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue
|
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.
|
// 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
|
// 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_FQ_NAME = FqName("kotlin.jvm.JvmStatic")
|
||||||
|
val JVM_STATIC_ANNOTATION_CLASS_ID = ClassId.topLevel(JVM_STATIC_ANNOTATION_FQ_NAME)
|
||||||
|
|
||||||
fun DeclarationDescriptor.hasJvmStaticAnnotation(): Boolean {
|
fun DeclarationDescriptor.hasJvmStaticAnnotation(): Boolean {
|
||||||
return annotations.findAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) != null
|
return annotations.findAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) != null
|
||||||
|
|||||||
@@ -28,6 +28,6 @@ class B: A() {
|
|||||||
devNull(A.internal_val)
|
devNull(A.internal_val)
|
||||||
devNull(A.public_val)
|
devNull(A.public_val)
|
||||||
devNull(A.<!INVISIBLE_REFERENCE!>private_val<!>)
|
devNull(A.<!INVISIBLE_REFERENCE!>private_val<!>)
|
||||||
devNull(A.protected_val)
|
devNull(A.<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>protected_val<!>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -47,27 +47,27 @@ class Derived : Base() {
|
|||||||
fun test() {
|
fun test() {
|
||||||
foo() // Ok
|
foo() // Ok
|
||||||
gav() // Ok
|
gav() // Ok
|
||||||
bar()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
|
||||||
baz()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
|
||||||
prop = 0
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>prop<!> = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
inner class DerivedInner {
|
inner class DerivedInner {
|
||||||
fun fromDerivedInner() {
|
fun fromDerivedInner() {
|
||||||
foo() // Ok
|
foo() // Ok
|
||||||
gav() // Ok
|
gav() // Ok
|
||||||
bar()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
|
||||||
baz()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
|
||||||
prop = 0
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>prop<!> = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun test2() {
|
fun test2() {
|
||||||
gav() // Ok
|
gav() // Ok
|
||||||
bar()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>bar<!>()
|
||||||
baz()
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>baz<!>()
|
||||||
prop = 0
|
<!SUBCLASS_CANT_CALL_COMPANION_PROTECTED_NON_STATIC!>prop<!> = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
@@ -4028,4 +4028,10 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
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
|
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)
|
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