[FIR] Report inherited java members referencing FunctionN

^KT-60000 Fixed
This commit is contained in:
Nikolay Lunyak
2023-08-07 14:38:22 +03:00
committed by Space Team
parent 0c35e97a8d
commit 70e98c9c2b
12 changed files with 96 additions and 23 deletions
@@ -657,6 +657,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION) { firDiagnostic ->
UnsupportedInheritanceFromJavaMemberReferencingKotlinFunctionImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a),
firDiagnostic as KtPsiDiagnostic,
token,
)
}
add(FirErrors.CYCLIC_INHERITANCE_HIERARCHY) { firDiagnostic ->
CyclicInheritanceHierarchyImpl(
firDiagnostic as KtPsiDiagnostic,
@@ -502,6 +502,11 @@ sealed interface KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
val reason: String
}
interface UnsupportedInheritanceFromJavaMemberReferencingKotlinFunction : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = UnsupportedInheritanceFromJavaMemberReferencingKotlinFunction::class
val symbol: KtSymbol
}
interface CyclicInheritanceHierarchy : KtFirDiagnostic<PsiElement> {
override val diagnosticClass get() = CyclicInheritanceHierarchy::class
}
@@ -590,6 +590,12 @@ internal class SupertypeNotAClassOrInterfaceImpl(
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<KtElement>(firDiagnostic, token), KtFirDiagnostic.SupertypeNotAClassOrInterface
internal class UnsupportedInheritanceFromJavaMemberReferencingKotlinFunctionImpl(
override val symbol: KtSymbol,
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
) : KtAbstractFirDiagnostic<PsiElement>(firDiagnostic, token), KtFirDiagnostic.UnsupportedInheritanceFromJavaMemberReferencingKotlinFunction
internal class CyclicInheritanceHierarchyImpl(
firDiagnostic: KtPsiDiagnostic,
token: KtLifetimeToken,
@@ -248,6 +248,9 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error<KtElement> {
parameter<String>("reason")
}
val UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION by error<PsiElement>(PositioningStrategy.DECLARATION_NAME) {
parameter<FirBasedSymbol<*>>("symbol")
}
val CYCLIC_INHERITANCE_HIERARCHY by error<PsiElement>()
val EXPANDED_TYPE_CANNOT_BE_INHERITED by error<KtTypeReference> {
parameter<ConeKotlinType>("type")
@@ -214,6 +214,7 @@ object FirErrors {
val SEALED_INHERITOR_IN_DIFFERENT_MODULE by error0<KtTypeReference>()
val CLASS_INHERITS_JAVA_SEALED_CLASS by error0<KtTypeReference>()
val SUPERTYPE_NOT_A_CLASS_OR_INTERFACE by error1<KtElement, String>()
val UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION by error1<PsiElement, FirBasedSymbol<*>>(SourceElementPositioningStrategies.DECLARATION_NAME)
val CYCLIC_INHERITANCE_HIERARCHY by error0<PsiElement>()
val EXPANDED_TYPE_CANNOT_BE_INHERITED by error1<KtTypeReference, ConeKotlinType>()
val PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE by error0<KtModifierListOwner>(SourceElementPositioningStrategies.VARIANCE_MODIFIER)
@@ -105,6 +105,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirPrimaryConstructorSuperTypeChecker,
FirDynamicSupertypeChecker,
FirEnumCompanionInEnumConstructorCallChecker,
FirBadInheritedJavaSignaturesChecker,
)
override val regularClassCheckers: Set<FirRegularClassChecker>
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2020 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.declaration
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.checkers.unsubstitutedScope
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.isJavaOrEnhancement
import org.jetbrains.kotlin.fir.scopes.processAllCallables
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.classId
import org.jetbrains.kotlin.fir.types.contains
import org.jetbrains.kotlin.name.StandardClassIds.Annotations.FunctionN
object FirBadInheritedJavaSignaturesChecker : FirClassChecker() {
override fun check(declaration: FirClass, context: CheckerContext, reporter: DiagnosticReporter) {
fun containsFunctionN(type: ConeKotlinType) = type.classId == FunctionN
declaration.unsubstitutedScope(context).processAllCallables { symbol ->
if (!symbol.isJavaOrEnhancement) {
return@processAllCallables
}
val hasBadReturnType = symbol.resolvedReturnType.contains(::containsFunctionN)
// NB: This case with receiver is not covered with tests
// and was replicated, because it's present in the original
// checker.
val hasBadReceiverType = symbol.resolvedReceiverTypeRef?.type?.contains(::containsFunctionN) == true
val hasBadValueParameter = symbol is FirFunctionSymbol<*> && symbol.valueParameterSymbols.any { valueParameter ->
valueParameter.resolvedReturnType.contains(::containsFunctionN)
}
if (hasBadReturnType || hasBadReceiverType || hasBadValueParameter) {
reporter.reportOn(
declaration.source,
FirErrors.UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION,
symbol, context,
)
}
}
}
}
@@ -608,6 +608,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CLASS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_CONTEXTUAL_DECLARATION_CALL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_FEATURE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_SUSPEND_TEST
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNUSED_VARIABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_IS_EXTENSION_FUNCTION_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UPPER_BOUND_VIOLATED
@@ -820,6 +821,11 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
map.put(CLASS_INHERITS_JAVA_SEALED_CLASS, "Inheritance of Java sealed classes is prohibited")
map.put(SUPERTYPE_NOT_A_CLASS_OR_INTERFACE, "Supertype is not a class or interface", TO_STRING)
map.put(
UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION,
"Inheritance of a Java member referencing 'kotlin.jvm.functions.FunctionN': {0} is unsupported",
TO_STRING,
)
map.put(CYCLIC_INHERITANCE_HIERARCHY, "There's a cycle in the inheritance hierarchy for this type")
map.put(
EXPANDED_TYPE_CANNOT_BE_INHERITED,
@@ -1,4 +1,3 @@
// FILE: A.java
import kotlin.jvm.functions.FunctionN;
@@ -7,10 +6,16 @@ public class A {
public void foo(FunctionN<?> w) { }
}
public class A2 {
public FunctionN<?> foo() { }
}
// FILE: main.kt
class B : A()
<!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>class B<!> : A()
<!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>class B2<!> : A2()
fun foo() {
object : A() {}
<!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>object<!> : A() {}
<!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>object<!> : A2() {}
}
@@ -1,4 +1,3 @@
// FILE: A.java
import kotlin.jvm.functions.FunctionN;
@@ -7,10 +6,16 @@ public class A {
public void foo(FunctionN<?> w) { }
}
public class A2 {
public FunctionN<?> foo() { }
}
// FILE: main.kt
class <!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>B<!> : A()
class <!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>B2<!> : A2()
fun foo() {
<!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>object<!> : A() {}
<!UNSUPPORTED_INHERITANCE_FROM_JAVA_MEMBER_REFERENCING_KOTLIN_FUNCTION!>object<!> : A2() {}
}
@@ -1,19 +0,0 @@
package
public fun foo(): kotlin.Unit
public open class A {
public constructor A()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open fun foo(/*0*/ w: kotlin.jvm.functions.FunctionN<*>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class B : A {
public constructor B()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun foo(/*0*/ w: kotlin.jvm.functions.FunctionN<*>!): kotlin.Unit
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@@ -14,6 +14,7 @@ object StandardClassIds {
val BASE_RANGES_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("ranges"))
val BASE_JVM_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("jvm"))
val BASE_JVM_INTERNAL_PACKAGE = BASE_JVM_PACKAGE.child(Name.identifier("internal"))
val BASE_JVM_FUNCTIONS_PACKAGE = BASE_JVM_PACKAGE.child(Name.identifier("functions"))
val BASE_ANNOTATION_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("annotation"))
val BASE_INTERNAL_PACKAGE = BASE_KOTLIN_PACKAGE.child(Name.identifier("internal"))
val BASE_INTERNAL_IR_PACKAGE = BASE_INTERNAL_PACKAGE.child(Name.identifier("ir"))
@@ -183,6 +184,8 @@ object StandardClassIds {
val FlexibleMutability = "FlexibleMutability".internalIrId()
val EnhancedNullability = "EnhancedNullability".jvmInternalId()
val FunctionN = "FunctionN".jvmFunctionsId()
val InlineOnly = "InlineOnly".internalId()
val OnlyInputTypes = "OnlyInputTypes".internalId()
@@ -265,6 +268,7 @@ private fun String.rangesId() = ClassId(StandardClassIds.BASE_RANGES_PACKAGE, Na
private fun String.annotationId() = ClassId(StandardClassIds.BASE_ANNOTATION_PACKAGE, Name.identifier(this))
private fun String.jvmId() = ClassId(StandardClassIds.BASE_JVM_PACKAGE, Name.identifier(this))
private fun String.jvmInternalId() = ClassId(StandardClassIds.BASE_JVM_INTERNAL_PACKAGE, Name.identifier(this))
private fun String.jvmFunctionsId() = ClassId(StandardClassIds.BASE_JVM_FUNCTIONS_PACKAGE, Name.identifier(this))
private fun String.internalId() = ClassId(StandardClassIds.BASE_INTERNAL_PACKAGE, Name.identifier(this))
private fun String.internalIrId() = ClassId(StandardClassIds.BASE_INTERNAL_IR_PACKAGE, Name.identifier(this))
private fun String.coroutinesId() = ClassId(StandardClassIds.BASE_COROUTINES_PACKAGE, Name.identifier(this))