[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");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritorInDifferentModule.kt")
|
||||
public void testInheritorInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritorInDifferentModule.kt")
|
||||
public void testInheritorInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||
public void testSealedInterfacesDisabled() throws Exception {
|
||||
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_IN_LOCAL_CLASS = DiagnosticFactory0.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);
|
||||
|
||||
// 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_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_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(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton");
|
||||
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,
|
||||
PrivateInlineFunctionsReturningAnonymousObjectsChecker,
|
||||
SealedInheritorInSamePackageChecker,
|
||||
SealedInheritorInSameModuleChecker,
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritorInDifferentModule.kt")
|
||||
public void testInheritorInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritorInDifferentModule.kt")
|
||||
public void testInheritorInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||
public void testSealedInterfacesDisabled() throws Exception {
|
||||
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");
|
||||
}
|
||||
|
||||
@TestMetadata("inheritorInDifferentModule.kt")
|
||||
public void testInheritorInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("Local.kt")
|
||||
public void testLocal() throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
@TestMetadata("inheritorInDifferentModule.kt")
|
||||
public void testInheritorInDifferentModule() throws Exception {
|
||||
runTest("compiler/testData/diagnostics/tests/sealed/interfaces/inheritorInDifferentModule.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("sealedInterfacesDisabled.kt")
|
||||
public void testSealedInterfacesDisabled() throws Exception {
|
||||
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)
|
||||
}
|
||||
|
||||
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
|
||||
fun testPreReleaseFlagIsConsistentBetweenBootstrapAndCurrentCompiler() {
|
||||
val bootstrapCompiler = JarFile(PathUtil.kotlinPathsForCompiler.compilerPath)
|
||||
|
||||
Reference in New Issue
Block a user