diff --git a/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyException.kt b/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyException.kt index 4a6b4a76287..7a3c32ff4a0 100644 --- a/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyException.kt +++ b/compiler/fir/analysis-tests/testData/resolveWithStdlib/j+k/MyException.kt @@ -15,7 +15,7 @@ fun test(e: MyException, stream: PrintStream) { val result = e.getLocalizedMessage() } -fun test(e: YourException, stream: PrintStream) { +fun test(e: YourException, stream: PrintStream) { e.printStackTrace() e.printStackTrace(stream) val result = e.getLocalizedMessage() 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 77fd575c668..6e30abfcce5 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 @@ -10,6 +10,7 @@ import com.intellij.openapi.util.Ref import com.intellij.psi.PsiElement import com.intellij.psi.PsiNameIdentifierOwner import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.RelationToType import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClass @@ -17,8 +18,10 @@ 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.toSymbol import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.lexer.KtTokens +import org.jetbrains.kotlin.utils.addToStdlib.safeAs // TODO: check why coneTypeSafe is necessary at some points inside object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { @@ -37,7 +40,7 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { } private fun checkSupertypes(declaration: FirRegularClass, reporter: DiagnosticReporter) { - val classVisibility = declaration.firEffectiveVisibility(declaration.session) + val classVisibility = declaration.effectiveVisibility val supertypes = declaration.superTypeRefs val isInterface = declaration.classKind == ClassKind.INTERFACE for (supertypeRef in supertypes) { @@ -47,13 +50,13 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { if (superIsInterface != isInterface) { continue } - val restricting = supertype.leastPermissiveDescriptor(declaration.session, classVisibility) + val restricting = supertype.findVisibilityExposure(declaration.session, classVisibility) if (restricting != null) { reporter.reportExposure( if (isInterface) FirErrors.EXPOSED_SUPER_INTERFACE else FirErrors.EXPOSED_SUPER_CLASS, restricting, classVisibility, - restricting.firEffectiveVisibility(declaration.session), + restricting.effectiveVisibility, supertypeRef.source ?: declaration.source ) } @@ -61,16 +64,16 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { } private fun checkParameterBounds(declaration: FirRegularClass, reporter: DiagnosticReporter) { - val classVisibility = declaration.firEffectiveVisibility(declaration.session) + val classVisibility = declaration.effectiveVisibility for (parameter in declaration.typeParameters) { for (bound in parameter.symbol.fir.bounds) { - val restricting = bound.coneType.leastPermissiveDescriptor(declaration.session, classVisibility) + val restricting = bound.coneType.findVisibilityExposure(declaration.session, classVisibility) if (restricting != null) { reporter.reportExposure( FirErrors.EXPOSED_TYPE_PARAMETER_BOUND, restricting, classVisibility, - restricting.firEffectiveVisibility(declaration.session), + restricting.effectiveVisibility, bound.source ) } @@ -81,13 +84,13 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { private fun checkTypeAlias(declaration: FirTypeAlias, reporter: DiagnosticReporter) { val expandedType = declaration.expandedConeType val typeAliasVisibility = declaration.firEffectiveVisibility(declaration.session) - val restricting = expandedType?.leastPermissiveDescriptor(declaration.session, typeAliasVisibility) + val restricting = expandedType?.findVisibilityExposure(declaration.session, typeAliasVisibility) if (restricting != null) { reporter.reportExposure( FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE, restricting, typeAliasVisibility, - restricting.firEffectiveVisibility(declaration.session), + restricting.effectiveVisibility, declaration.source?.getIdentifierSource() ?: declaration.source ) } @@ -97,13 +100,13 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { val functionVisibility = (declaration as FirMemberDeclaration).effectiveVisibility if (declaration !is FirConstructor) { val restricting = declaration.returnTypeRef.coneTypeSafe() - ?.leastPermissiveDescriptor(declaration.session, functionVisibility) + ?.findVisibilityExposure(declaration.session, functionVisibility) if (restricting != null) { reporter.reportExposure( FirErrors.EXPOSED_FUNCTION_RETURN_TYPE, restricting, functionVisibility, - restricting.firEffectiveVisibility(declaration.session), + restricting.effectiveVisibility, declaration.source?.getIdentifierSource() ?: declaration.source ) } @@ -112,13 +115,13 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { if (i < declaration.valueParameters.size) { val restricting = valueParameter.returnTypeRef.coneTypeSafe() - ?.leastPermissiveDescriptor(declaration.session, functionVisibility) + ?.findVisibilityExposure(declaration.session, functionVisibility) if (restricting != null) { reporter.reportExposure( FirErrors.EXPOSED_PARAMETER_TYPE, restricting, functionVisibility, - restricting.firEffectiveVisibility(declaration.session), + restricting.effectiveVisibility, valueParameter.source ) } @@ -128,15 +131,16 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { } private fun checkProperty(declaration: FirProperty, reporter: DiagnosticReporter) { - val propertyVisibility = declaration.firEffectiveVisibility(declaration.session) + val propertyVisibility = declaration.effectiveVisibility val restricting = - declaration.returnTypeRef.coneTypeSafe()?.leastPermissiveDescriptor(declaration.session, propertyVisibility) + declaration.returnTypeRef.coneTypeSafe() + ?.findVisibilityExposure(declaration.session, propertyVisibility) if (restricting != null) { reporter.reportExposure( FirErrors.EXPOSED_PROPERTY_TYPE, restricting, propertyVisibility, - restricting.firEffectiveVisibility(declaration.session), + restricting.effectiveVisibility, declaration.source?.getIdentifierSource() ?: declaration.source ) } @@ -149,22 +153,52 @@ object FirExposedVisibilityChecker : FirMemberDeclarationChecker() { ) { if (typeRef == null || memberDeclaration == null) return val receiverParameterType = typeRef.coneType - val memberVisibility = memberDeclaration.firEffectiveVisibility(memberDeclaration.session) - val restricting = receiverParameterType.leastPermissiveDescriptor(memberDeclaration.session, memberVisibility) + val memberVisibility = memberDeclaration.effectiveVisibility + val restricting = receiverParameterType.findVisibilityExposure(memberDeclaration.session, memberVisibility) if (restricting != null) { reporter.reportExposure( FirErrors.EXPOSED_RECEIVER_TYPE, restricting, memberVisibility, - restricting.firEffectiveVisibility(memberDeclaration.session), + restricting.effectiveVisibility, typeRef.source ) } } + private fun ConeKotlinType.findVisibilityExposure(session: FirSession, base: FirEffectiveVisibility): FirMemberDeclaration? { + val type = this as? ConeClassLikeType + ?: return null + val fir = type.lookupTag.toSymbol(session) + ?.fir + ?: return null + + if ( + fir is FirMemberDeclaration && + fir.effectiveVisibility != FirEffectiveVisibility.Default // because abstract interface List returns it here + ) { + when (fir.effectiveVisibility.relation(base)) { + FirEffectiveVisibility.Permissiveness.LESS, + FirEffectiveVisibility.Permissiveness.UNKNOWN -> { + return fir + } + else -> { + } + } + } + + for (it in type.typeArguments) { + it.safeAs()?.findVisibilityExposure(session, base)?.let { + return it + } + } + + return null + } + private inline fun DiagnosticReporter.reportExposure( - error: FirDiagnosticFactory3, - restrictingDeclaration: DeclarationWithRelation, + error: FirDiagnosticFactory3, + restrictingDeclaration: FirMemberDeclaration, elementVisibility: FirEffectiveVisibility, restrictingVisibility: FirEffectiveVisibility, source: FirSourceElement? 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 806562eb769..6e0b8bfcf92 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 @@ -7,10 +7,9 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics import com.intellij.psi.PsiElement 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.declarations.FirDeclaration +import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.types.ConeKotlinType @@ -62,14 +61,14 @@ object FirErrors { val VAR_ANNOTATION_PARAMETER by existing(Errors.VAR_ANNOTATION_PARAMETER) // Exposed visibility group - val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3() - val EXPOSED_FUNCTION_RETURN_TYPE by error3() - val EXPOSED_RECEIVER_TYPE by error3() - val EXPOSED_PROPERTY_TYPE by error3() - 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 EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3() + val EXPOSED_FUNCTION_RETURN_TYPE by error3() + val EXPOSED_RECEIVER_TYPE by error3() + val EXPOSED_PROPERTY_TYPE by error3() + 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/cyclicHierarchy/javaKotlinJavaCycle.fir.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/javaKotlinJavaCycle.fir.kt index 0ee5c285c19..12cc4ee45a1 100644 --- a/compiler/testData/diagnostics/tests/cyclicHierarchy/javaKotlinJavaCycle.fir.kt +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/javaKotlinJavaCycle.fir.kt @@ -6,7 +6,7 @@ interface A extends C { // FILE: B.kt -interface B : A { +interface B : A { fun bar() } diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaCycle.fir.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaCycle.fir.kt index 8002261c5b9..c362c08bc1e 100644 --- a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaCycle.fir.kt +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaCycle.fir.kt @@ -6,6 +6,6 @@ class J extends K { // FILE: K.kt -class K : J() { +class K : J() { fun bar() {} } diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.fir.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.fir.kt index 1b48daaedd1..d4241960250 100644 --- a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.fir.kt +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaKotlinCycle.fir.kt @@ -12,6 +12,6 @@ class J extends I { // FILE: K.kt -open class K : J() { +open class K : J() { fun baz() {} } diff --git a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.fir.kt b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.fir.kt index cf752aecdd6..bcd66b00875 100644 --- a/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.fir.kt +++ b/compiler/testData/diagnostics/tests/cyclicHierarchy/kotlinJavaNestedCycle.fir.kt @@ -1,6 +1,6 @@ // FILE: ExceptionTracker.kt -interface ExceptionTracker : LockBasedStorageManager.ExceptionHandlingStrategy { +interface ExceptionTracker : LockBasedStorageManager.ExceptionHandlingStrategy { } // FILE: StorageManager.kt diff --git a/compiler/testData/diagnostics/tests/exposed/protectedJava.fir.kt b/compiler/testData/diagnostics/tests/exposed/protectedJava.fir.kt deleted file mode 100644 index 7dc16417a2e..00000000000 --- a/compiler/testData/diagnostics/tests/exposed/protectedJava.fir.kt +++ /dev/null @@ -1,16 +0,0 @@ -// FILE: Outer.java - -public abstract class Outer { - protected static class My {} - protected static class Your extends My {} - abstract protected Your foo(My my); -} - -// FILE: OuterDerived.kt - -class OuterDerived: Outer() { - // valid, My has better visibility - protected class His: Outer.My() - // valid, My and Your have better visibility - override fun foo(my: Outer.My) = Outer.Your() -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/exposed/protectedJava.kt b/compiler/testData/diagnostics/tests/exposed/protectedJava.kt index 29096cf0d16..670a699a786 100644 --- a/compiler/testData/diagnostics/tests/exposed/protectedJava.kt +++ b/compiler/testData/diagnostics/tests/exposed/protectedJava.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // FILE: Outer.java public abstract class Outer { diff --git a/compiler/testData/diagnostics/tests/j+k/packageVisibility.fir.kt b/compiler/testData/diagnostics/tests/j+k/packageVisibility.fir.kt index 31f7c726aad..ff2aed7313b 100644 --- a/compiler/testData/diagnostics/tests/j+k/packageVisibility.fir.kt +++ b/compiler/testData/diagnostics/tests/j+k/packageVisibility.fir.kt @@ -16,10 +16,10 @@ class MyJavaClass { //FILE:a.kt package a -val mc = MyJavaClass() +val mc = MyJavaClass() val x = MyJavaClass.staticMethod() val y = MyJavaClass.NestedClass.staticMethodOfNested() -val z = MyJavaClass.NestedClass() +val z = MyJavaClass.NestedClass() //FILE: b.kt package b diff --git a/compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.fir.kt index 55ad0bf66d9..66c2c487bc3 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/InaccessibleInternalClass.fir.kt @@ -10,6 +10,6 @@ package kotlin.sequences import p.* interface I { - val v1: FilteringSequence - val v2: IndexingSequence + val v1: FilteringSequence + val v2: IndexingSequence }