[FE] Prohibit inheritance of sealed classes in different module
KT-20423
This commit is contained in:
committed by
TeamCityServer
parent
f8d6f79c17
commit
57a081c399
+10
@@ -20773,6 +20773,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
|||||||
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritorInDifferentModule.kt")
|
||||||
|
public void testInheritorInDifferentModule() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Local.kt")
|
@TestMetadata("Local.kt")
|
||||||
public void testLocal() throws Exception {
|
public void testLocal() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
|
||||||
@@ -20910,6 +20915,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritorInDifferentModule.kt")
|
||||||
|
public void testInheritorInDifferentModule() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/inheritorInDifferentModule.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||||
public void testSealedInterfacesDisabled() throws Exception {
|
public void testSealedInterfacesDisabled() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
||||||
|
|||||||
@@ -427,6 +427,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory0<KtTypeReference> SEALED_SUPERTYPE = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtTypeReference> SEALED_SUPERTYPE = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtTypeReference> SEALED_SUPERTYPE_IN_LOCAL_CLASS = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtTypeReference> SEALED_SUPERTYPE_IN_LOCAL_CLASS = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory2<KtTypeReference, FqName, FqName> SEALED_INHERITOR_IN_DIFFERENT_PACKAGE = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<KtTypeReference, FqName, FqName> SEALED_INHERITOR_IN_DIFFERENT_PACKAGE = DiagnosticFactory2.create(ERROR);
|
||||||
|
DiagnosticFactory0<KtTypeReference> SEALED_INHERITOR_IN_DIFFERENT_MODULE = DiagnosticFactory0.create(ERROR);
|
||||||
DiagnosticFactory0<KtTypeReference> CLASS_INHERITS_JAVA_SEALED_CLASS = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtTypeReference> CLASS_INHERITS_JAVA_SEALED_CLASS = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
// Companion objects
|
// Companion objects
|
||||||
|
|||||||
+1
@@ -634,6 +634,7 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(SEALED_SUPERTYPE, "This type is sealed, so it can be inherited by only its own nested classes or objects");
|
MAP.put(SEALED_SUPERTYPE, "This type is sealed, so it can be inherited by only its own nested classes or objects");
|
||||||
MAP.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class");
|
MAP.put(SEALED_SUPERTYPE_IN_LOCAL_CLASS, "Local class cannot extend a sealed class");
|
||||||
MAP.put(SEALED_INHERITOR_IN_DIFFERENT_PACKAGE, "Inheritor of sealed class or interface declared in package {1} but it must be in package {2} where base class is declared", TO_STRING, TO_STRING);
|
MAP.put(SEALED_INHERITOR_IN_DIFFERENT_PACKAGE, "Inheritor of sealed class or interface declared in package {1} but it must be in package {2} where base class is declared", TO_STRING, TO_STRING);
|
||||||
|
MAP.put(SEALED_INHERITOR_IN_DIFFERENT_MODULE, "Inheritance of sealed classes or interfaces from different module is prohibited");
|
||||||
MAP.put(CLASS_INHERITS_JAVA_SEALED_CLASS, "Inheritance of java sealed classes is prohibited");
|
MAP.put(CLASS_INHERITS_JAVA_SEALED_CLASS, "Inheritance of java sealed classes is prohibited");
|
||||||
MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton");
|
MAP.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton");
|
||||||
MAP.put(CLASS_CANNOT_BE_EXTENDED_DIRECTLY, "Class {0} cannot be extended directly", NAME);
|
MAP.put(CLASS_CANNOT_BE_EXTENDED_DIRECTLY, "Class {0} cannot be extended directly", NAME);
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
|
|||||||
ContractDescriptionBlockChecker,
|
ContractDescriptionBlockChecker,
|
||||||
PrivateInlineFunctionsReturningAnonymousObjectsChecker,
|
PrivateInlineFunctionsReturningAnonymousObjectsChecker,
|
||||||
SealedInheritorInSamePackageChecker,
|
SealedInheritorInSamePackageChecker,
|
||||||
|
SealedInheritorInSameModuleChecker,
|
||||||
SealedInterfaceAllowedChecker,
|
SealedInterfaceAllowedChecker,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* 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.resolve.checkers
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.isSealed
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||||
|
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||||
|
import org.jetbrains.kotlin.resolve.bindingContextUtil.getAbbreviatedTypeOrType
|
||||||
|
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||||
|
|
||||||
|
object SealedInheritorInSameModuleChecker : DeclarationChecker {
|
||||||
|
override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, context: DeclarationCheckerContext) {
|
||||||
|
if (descriptor !is ClassDescriptor || declaration !is KtClassOrObject) return
|
||||||
|
val currentModule = descriptor.module
|
||||||
|
for (superTypeListEntry in declaration.superTypeListEntries) {
|
||||||
|
val typeReference = superTypeListEntry.typeReference ?: continue
|
||||||
|
val superType = typeReference.getAbbreviatedTypeOrType(context.trace.bindingContext)?.unwrap() ?: continue
|
||||||
|
val superClass = superType.constructor.declarationDescriptor ?: continue
|
||||||
|
if (superClass.isSealed() && superClass.module != currentModule) {
|
||||||
|
context.trace.report(Errors.SEALED_INHERITOR_IN_DIFFERENT_MODULE.on(typeReference))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+7
@@ -0,0 +1,7 @@
|
|||||||
|
package a
|
||||||
|
|
||||||
|
sealed class Base
|
||||||
|
|
||||||
|
sealed interface IBase
|
||||||
|
|
||||||
|
class A : Base(), IBase
|
||||||
Vendored
+5
@@ -0,0 +1,5 @@
|
|||||||
|
// ISSUE: KT-20423
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
class B : Base(), IBase
|
||||||
Vendored
+20
@@ -0,0 +1,20 @@
|
|||||||
|
warning: ATTENTION!
|
||||||
|
This build uses unsafe internal compiler arguments:
|
||||||
|
|
||||||
|
-XXLanguage:+FreedomForSealedClasses
|
||||||
|
-XXLanguage:+SealedInterfaces
|
||||||
|
|
||||||
|
This mode is not recommended for production use,
|
||||||
|
as no stability/compatibility guarantees are given on
|
||||||
|
compiler or generated code. Use it at your own risk!
|
||||||
|
|
||||||
|
compiler/testData/compileKotlinAgainstCustomBinaries/sealedInheritorInDifferentModule/main.kt:5:11: error: cannot access '<init>': it is internal in 'Base'
|
||||||
|
class B : Base(), IBase
|
||||||
|
^
|
||||||
|
compiler/testData/compileKotlinAgainstCustomBinaries/sealedInheritorInDifferentModule/main.kt:5:11: error: inheritance of sealed classes or interfaces from different module is prohibited
|
||||||
|
class B : Base(), IBase
|
||||||
|
^
|
||||||
|
compiler/testData/compileKotlinAgainstCustomBinaries/sealedInheritorInDifferentModule/main.kt:5:19: error: inheritance of sealed classes or interfaces from different module is prohibited
|
||||||
|
class B : Base(), IBase
|
||||||
|
^
|
||||||
|
COMPILATION_ERROR
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// ISSUE: KT-20423
|
||||||
|
// !LANGUAGE: +SealedInterfaces +FreedomForSealedClasses
|
||||||
|
|
||||||
|
// MODULE: m1
|
||||||
|
// FILE: a.kt
|
||||||
|
package a
|
||||||
|
|
||||||
|
sealed class Base
|
||||||
|
|
||||||
|
class A : Base()
|
||||||
|
|
||||||
|
// MODULE: m2(m1)
|
||||||
|
// FILE: b.kt
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
class B : <!HIDDEN!>Base<!>()
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
// ISSUE: KT-20423
|
||||||
|
// !LANGUAGE: +SealedInterfaces +FreedomForSealedClasses
|
||||||
|
|
||||||
|
// MODULE: m1
|
||||||
|
// FILE: a.kt
|
||||||
|
package a
|
||||||
|
|
||||||
|
sealed class Base
|
||||||
|
|
||||||
|
class A : Base()
|
||||||
|
|
||||||
|
// MODULE: m2(m1)
|
||||||
|
// FILE: b.kt
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
class B : <!INVISIBLE_MEMBER, SEALED_INHERITOR_IN_DIFFERENT_MODULE!>Base<!>()
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// -- Module: <m1> --
|
||||||
|
package
|
||||||
|
|
||||||
|
package a {
|
||||||
|
|
||||||
|
public final class A : a.Base {
|
||||||
|
public constructor A()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class Base {
|
||||||
|
internal constructor Base()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -- Module: <m2> --
|
||||||
|
package
|
||||||
|
|
||||||
|
package a {
|
||||||
|
|
||||||
|
public final class B : a.Base {
|
||||||
|
public constructor B()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// ISSUE: KT-20423
|
||||||
|
// !LANGUAGE: +SealedInterfaces +FreedomForSealedClasses
|
||||||
|
|
||||||
|
// MODULE: m1
|
||||||
|
// FILE: a.kt
|
||||||
|
package a
|
||||||
|
|
||||||
|
sealed interface Base
|
||||||
|
|
||||||
|
interface A : Base
|
||||||
|
|
||||||
|
// MODULE: m2(m1)
|
||||||
|
// FILE: b.kt
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
interface B : Base
|
||||||
+17
@@ -0,0 +1,17 @@
|
|||||||
|
// ISSUE: KT-20423
|
||||||
|
// !LANGUAGE: +SealedInterfaces +FreedomForSealedClasses
|
||||||
|
|
||||||
|
// MODULE: m1
|
||||||
|
// FILE: a.kt
|
||||||
|
package a
|
||||||
|
|
||||||
|
sealed interface Base
|
||||||
|
|
||||||
|
interface A : Base
|
||||||
|
|
||||||
|
// MODULE: m2(m1)
|
||||||
|
// FILE: b.kt
|
||||||
|
|
||||||
|
package a
|
||||||
|
|
||||||
|
interface B : <!SEALED_INHERITOR_IN_DIFFERENT_MODULE!>Base<!>
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
// -- Module: <m1> --
|
||||||
|
package
|
||||||
|
|
||||||
|
package a {
|
||||||
|
|
||||||
|
public interface A : a.Base {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed interface Base {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// -- Module: <m2> --
|
||||||
|
package
|
||||||
|
|
||||||
|
package a {
|
||||||
|
|
||||||
|
public interface B : a.Base {
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
+10
@@ -20850,6 +20850,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
|||||||
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritorInDifferentModule.kt")
|
||||||
|
public void testInheritorInDifferentModule() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Local.kt")
|
@TestMetadata("Local.kt")
|
||||||
public void testLocal() throws Exception {
|
public void testLocal() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
|
||||||
@@ -20987,6 +20992,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritorInDifferentModule.kt")
|
||||||
|
public void testInheritorInDifferentModule() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/inheritorInDifferentModule.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||||
public void testSealedInterfacesDisabled() throws Exception {
|
public void testSealedInterfacesDisabled() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
||||||
|
|||||||
Generated
+10
@@ -20775,6 +20775,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/ExhaustiveWithFreedom.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritorInDifferentModule.kt")
|
||||||
|
public void testInheritorInDifferentModule() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("Local.kt")
|
@TestMetadata("Local.kt")
|
||||||
public void testLocal() throws Exception {
|
public void testLocal() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/Local.kt");
|
||||||
@@ -20912,6 +20917,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/sealed/interfaces"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inheritorInDifferentModule.kt")
|
||||||
|
public void testInheritorInDifferentModule() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/inheritorInDifferentModule.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||||
public void testSealedInterfacesDisabled() throws Exception {
|
public void testSealedInterfacesDisabled() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/sealedInterfacesDisabled.kt");
|
||||||
|
|||||||
+6
@@ -700,6 +700,12 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration
|
|||||||
compileKotlin("main.kt", tmpdir, listOf(library), additionalOptions = features)
|
compileKotlin("main.kt", tmpdir, listOf(library), additionalOptions = features)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testSealedInheritorInDifferentModule() {
|
||||||
|
val features = listOf("-XXLanguage:+FreedomForSealedClasses", "-XXLanguage:+SealedInterfaces")
|
||||||
|
val library = compileLibrary("library", additionalOptions = features, checkKotlinOutput = {})
|
||||||
|
compileKotlin("main.kt", tmpdir, listOf(library), additionalOptions = features)
|
||||||
|
}
|
||||||
|
|
||||||
// If this test fails, then bootstrap compiler most likely should be advanced
|
// If this test fails, then bootstrap compiler most likely should be advanced
|
||||||
fun testPreReleaseFlagIsConsistentBetweenBootstrapAndCurrentCompiler() {
|
fun testPreReleaseFlagIsConsistentBetweenBootstrapAndCurrentCompiler() {
|
||||||
val bootstrapCompiler = JarFile(PathUtil.kotlinPathsForCompiler.compilerPath)
|
val bootstrapCompiler = JarFile(PathUtil.kotlinPathsForCompiler.compilerPath)
|
||||||
|
|||||||
Reference in New Issue
Block a user