提交 57a081c3 编写于 作者: D Dmitriy Novozhilov 提交者: TeamCityServer

[FE] Prohibit inheritance of sealed classes in different module

KT-20423
上级 f8d6f79c
...@@ -20773,6 +20773,11 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirOldFronte ...@@ -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 ...@@ -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 { ...@@ -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
......
...@@ -634,6 +634,7 @@ public class DefaultErrorMessages { ...@@ -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( ...@@ -42,6 +42,7 @@ private val DEFAULT_DECLARATION_CHECKERS = listOf(
ContractDescriptionBlockChecker, ContractDescriptionBlockChecker,
PrivateInlineFunctionsReturningAnonymousObjectsChecker, PrivateInlineFunctionsReturningAnonymousObjectsChecker,
SealedInheritorInSamePackageChecker, SealedInheritorInSamePackageChecker,
SealedInheritorInSameModuleChecker,
SealedInterfaceAllowedChecker, SealedInterfaceAllowedChecker,
) )
......
/*
* 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))
}
}
}
}
package a
sealed class Base
sealed interface IBase
class A : Base(), IBase
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
// 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<!>()
// 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<!>()
// -- 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
}
}
// 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
// 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<!>
// -- 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
}
}
...@@ -20850,6 +20850,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTestWithFirVali ...@@ -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 ...@@ -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");
...@@ -20775,6 +20775,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing ...@@ -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 ...@@ -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");
...@@ -700,6 +700,12 @@ class CompileKotlinAgainstCustomBinariesTest : AbstractKotlinCompilerIntegration ...@@ -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)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册