diff --git a/compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.kt b/compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.kt new file mode 100644 index 00000000000..aac91cbe755 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.kt @@ -0,0 +1,35 @@ +private open class A + +internal open class B + +public open class C { + protected open class D +} + +public open class E + +// invalid, A is private +public class Test1A> + +// valid, both type parameters is public +public class Test2 + +// invalid, D is protected +public class Test3C.D> + +// valid, B is internal +internal class Test4 + +// valid, B is internal +private class Test5 + +public class Container : C { + // valid, D is protected in C + protected class Test6 + + // invalid, B is internal + protected class Test7B> +} + +// invalid, A is private, B is internal, D is protected +public interface Test8A, P: B, F: C, N: C.D, M: E> \ No newline at end of file diff --git a/compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.txt b/compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.txt new file mode 100644 index 00000000000..77a615e827d --- /dev/null +++ b/compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.txt @@ -0,0 +1,84 @@ +FILE: exposedTypeParameters.kt + private open class A : R|kotlin/Any| { + public[private] constructor(): R|A| { + super() + } + + } + internal open class B : R|kotlin/Any| { + public[internal] constructor(): R|B| { + super() + } + + } + public open class C : R|kotlin/Any| { + public constructor(): R|C| { + super() + } + + protected open class D : R|kotlin/Any| { + public[protected] constructor(): R|C.D| { + super() + } + + } + + } + public open class E : R|kotlin/Any| { + public constructor(): R|E| { + super() + } + + } + public final class Test1 : R|kotlin/Any| { + public constructor(): R|Test1| { + super() + } + + } + public final class Test2 : R|kotlin/Any| { + public constructor(): R|Test2| { + super() + } + + } + public final class Test3 : R|kotlin/Any| { + public constructor(): R|Test3| { + super() + } + + } + internal final class Test4 : R|kotlin/Any| { + public[internal] constructor(): R|Test4| { + super() + } + + } + private final class Test5 : R|kotlin/Any| { + public[private] constructor(): R|Test5| { + super() + } + + } + public final class Container : R|C| { + public constructor(): R|Container| { + super() + } + + protected final class Test6 : R|kotlin/Any| { + public[protected] constructor(): R|Container.Test6| { + super() + } + + } + + protected final class Test7 : R|kotlin/Any| { + public[protected] constructor(): R|Container.Test7| { + super() + } + + } + + } + public abstract interface Test8 : R|kotlin/Any| { + } diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java index 77b2cc42e10..a481248a52e 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsTestGenerated.java @@ -2193,6 +2193,11 @@ public class FirDiagnosticsTestGenerated extends AbstractFirDiagnosticsTest { runTest("compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeAlias.kt"); } + @TestMetadata("exposedTypeParameters.kt") + public void testExposedTypeParameters() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.kt"); + } + @TestMetadata("protectedInCompanion.kt") public void testProtectedInCompanion() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/visibility/protectedInCompanion.kt"); diff --git a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java index aee80db0405..b6de05db993 100644 --- a/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests/org/jetbrains/kotlin/fir/FirDiagnosticsWithLightTreeTestGenerated.java @@ -2193,6 +2193,11 @@ public class FirDiagnosticsWithLightTreeTestGenerated extends AbstractFirDiagnos runTest("compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeAlias.kt"); } + @TestMetadata("exposedTypeParameters.kt") + public void testExposedTypeParameters() throws Exception { + runTest("compiler/fir/analysis-tests/testData/resolve/visibility/exposedTypeParameters.kt"); + } + @TestMetadata("protectedInCompanion.kt") public void testProtectedInCompanion() throws Exception { runTest("compiler/fir/analysis-tests/testData/resolve/visibility/protectedInCompanion.kt"); diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityChecker.kt index 99c76ea8b79..a0998c6b6ed 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExposedVisibilityChecker.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory3 import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.declarations.* +import org.jetbrains.kotlin.fir.resolve.firSymbolProvider import org.jetbrains.kotlin.fir.types.ConeClassLikeType import org.jetbrains.kotlin.fir.types.ConeKotlinType import org.jetbrains.kotlin.fir.types.FirTypeRef @@ -29,10 +30,15 @@ object FirExposedVisibilityChecker : FirDeclarationChecker is FirTypeAlias -> checkTypeAlias(declaration, reporter) is FirProperty -> checkProperty(declaration, reporter) is FirFunction<*> -> checkFunction(declaration, reporter) - is FirRegularClass -> checkSupertypes(declaration, reporter) + is FirRegularClass -> checkClass(declaration, reporter) } } + private fun checkClass(declaration: FirRegularClass, reporter: DiagnosticReporter) { + checkSupertypes(declaration, reporter) + checkParameterBounds(declaration, reporter) + } + private fun checkSupertypes(declaration: FirRegularClass, reporter: DiagnosticReporter) { val classVisibility = declaration.firEffectiveVisibility(declaration.session) val supertypes = declaration.superTypeRefs @@ -57,6 +63,24 @@ object FirExposedVisibilityChecker : FirDeclarationChecker } } + private fun checkParameterBounds(declaration: FirRegularClass, reporter: DiagnosticReporter) { + val classVisibility = declaration.firEffectiveVisibility(declaration.session) + for (parameter in declaration.typeParameters) { + for (bound in parameter.symbol.fir.bounds) { + val restricting = bound.coneTypeSafe()?.leastPermissiveDescriptor(declaration.session, classVisibility) + if (restricting != null) { + reporter.reportExposure( + FirErrors.EXPOSED_TYPE_PARAMETER_BOUND, + restricting, + classVisibility, + restricting.firEffectiveVisibility(declaration.session), + bound.source + ) + } + } + } + } + private fun checkTypeAlias(declaration: FirTypeAlias, reporter: DiagnosticReporter) { val expandedType = declaration.expandedConeType val typeAliasVisibility = declaration.firEffectiveVisibility(declaration.session) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 74fa45384a0..97d92c209b8 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -6,17 +6,17 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.descriptors.DescriptorWithRelation +import org.jetbrains.kotlin.descriptors.EffectiveVisibility +import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3 import org.jetbrains.kotlin.diagnostics.Errors import org.jetbrains.kotlin.fir.DeclarationWithRelation import org.jetbrains.kotlin.fir.FirEffectiveVisibility import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType -import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.lexer.KtModifierKeywordToken -import org.jetbrains.kotlin.psi.KtParameter -import org.jetbrains.kotlin.psi.KtSuperTypeListEntry -import org.jetbrains.kotlin.psi.KtTypeReference +import org.jetbrains.kotlin.psi.* object FirErrors { val UNRESOLVED_REFERENCE by error1() @@ -61,6 +61,7 @@ object FirErrors { val EXPOSED_PARAMETER_TYPE by error3() val EXPOSED_SUPER_INTERFACE by error3() val EXPOSED_SUPER_CLASS by error3() + val EXPOSED_TYPE_PARAMETER_BOUND by error3() val REPEATED_MODIFIER by error1() val REDUNDANT_MODIFIER by error2() diff --git a/compiler/testData/diagnostics/tests/exposed/simple.fir.kt b/compiler/testData/diagnostics/tests/exposed/simple.fir.kt index ea8031abf45..0112ddeec17 100644 --- a/compiler/testData/diagnostics/tests/exposed/simple.fir.kt +++ b/compiler/testData/diagnostics/tests/exposed/simple.fir.kt @@ -6,7 +6,7 @@ public interface Your: My { fun foo(): T } -public class Derived(val x: My): Base() { +public class DerivedMy>(val x: My): Base() { constructor(xx: My?, x: My): this(xx ?: x) diff --git a/compiler/testData/diagnostics/tests/exposed/typeArgs.fir.kt b/compiler/testData/diagnostics/tests/exposed/typeArgs.fir.kt index 91ab7d42a03..5fd5d12cb40 100644 --- a/compiler/testData/diagnostics/tests/exposed/typeArgs.fir.kt +++ b/compiler/testData/diagnostics/tests/exposed/typeArgs.fir.kt @@ -9,7 +9,7 @@ abstract class Your { interface His: List // invalid, My is internal -interface Generic +interface GenericMy> interface Our { // invalid, Generic is effectively internal