From 7e9704e50d299f73996f8f05708078c631ca3fd9 Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Wed, 29 Aug 2018 15:01:51 +0300 Subject: [PATCH] Prohibit inheritance of Java members containing FunctionN types #KT-25855 Fixed --- .../BadInheritedJavaSignaturesChecker.kt | 53 +++++++++++++++++++ .../jvm/platform/JvmPlatformConfigurator.kt | 3 +- .../java/inheritedFunctionN.kt | 16 ++++++ .../java/inheritedFunctionN.txt | 19 +++++++ .../DiagnosticsTestWithStdLibGenerated.java | 5 ++ ...ticsTestWithStdLibUsingJavacGenerated.java | 5 ++ 6 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/BadInheritedJavaSignaturesChecker.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt create mode 100644 compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/BadInheritedJavaSignaturesChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/BadInheritedJavaSignaturesChecker.kt new file mode 100644 index 00000000000..3845f716f82 --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/BadInheritedJavaSignaturesChecker.kt @@ -0,0 +1,53 @@ +/* + * Copyright 2010-2018 JetBrains s.r.o. 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.resolve.jvm.checkers + +import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap +import org.jetbrains.kotlin.descriptors.CallableDescriptor +import org.jetbrains.kotlin.descriptors.ClassDescriptor +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.load.java.DeprecationCausedByFunctionN +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.renderer.DescriptorRenderer +import org.jetbrains.kotlin.resolve.DEPRECATED_FUNCTION_KEY +import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker +import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult + +object BadInheritedJavaSignaturesChecker : DeclarationChecker { + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) { + if (descriptor !is ClassDescriptor) return + + val badSignatureOverriddenDescriptor = + descriptor.unsubstitutedMemberScope.getContributedDescriptors().firstNotNullResult(::findFirstBadJavaSignatureOverridden) + + if (badSignatureOverriddenDescriptor != null) { + val reportOn = + when (declaration) { + is KtClass -> declaration.nameIdentifier ?: declaration.getClassOrInterfaceKeyword() + is KtObjectDeclaration -> declaration.getObjectKeyword() + else -> null + } ?: declaration + + val renderedDescriptor = DescriptorRenderer.COMPACT_WITH_SHORT_TYPES.render(badSignatureOverriddenDescriptor) + context.trace.report( + Errors.UNSUPPORTED.on( + reportOn, + "Inheritance of a Java member referencing '${JavaToKotlinClassMap.FUNCTION_N_FQ_NAME}': $renderedDescriptor" + ) + ) + } + } +} + +private fun findFirstBadJavaSignatureOverridden(descriptor: DeclarationDescriptor): DeclarationDescriptor? { + if (descriptor !is CallableDescriptor) return null + + return descriptor.overriddenDescriptors.firstOrNull { + overridden -> overridden.getUserData(DEPRECATED_FUNCTION_KEY) is DeprecationCausedByFunctionN + } +} diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 6a03fd1b93f..2d656b66dbc 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -46,7 +46,8 @@ object JvmPlatformConfigurator : PlatformConfigurator( JvmSyntheticApplicabilityChecker(), StrictfpApplicabilityChecker(), ExpectedActualDeclarationChecker, - JvmAnnotationsTargetNonExistentAccessorChecker() + JvmAnnotationsTargetNonExistentAccessorChecker(), + BadInheritedJavaSignaturesChecker ), additionalCallCheckers = listOf( diff --git a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt new file mode 100644 index 00000000000..899e91e412a --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt @@ -0,0 +1,16 @@ + +// FILE: A.java + +import kotlin.jvm.functions.FunctionN; + +public class A { + public void foo(FunctionN w) { } +} + +// FILE: main.kt + +class !\): Unit defined in A)!>B : A() + +fun foo() { + !\): Unit defined in A)!>object : A() {} +} diff --git a/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt new file mode 100644 index 00000000000..b07070c18f4 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.txt @@ -0,0 +1,19 @@ +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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 0526f3353de..a46ae753aab 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -2622,6 +2622,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/java/functionN.kt"); } + @TestMetadata("inheritedFunctionN.kt") + public void testInheritedFunctionN() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt"); + } + @TestMetadata("patternCompileCallableReference.kt") public void testPatternCompileCallableReference() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/java/patternCompileCallableReference.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 4d698d8e045..7a141bb18f9 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -2622,6 +2622,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/java/functionN.kt"); } + @TestMetadata("inheritedFunctionN.kt") + public void testInheritedFunctionN() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/java/inheritedFunctionN.kt"); + } + @TestMetadata("patternCompileCallableReference.kt") public void testPatternCompileCallableReference() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/java/patternCompileCallableReference.kt");