[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
@@ -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
}