diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java index fdab662b4f1..8fe122e1837 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/diagnostic/compiler/based/DiagnosisCompilerTestFE10TestdataTestGenerated.java @@ -33502,6 +33502,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag runTest("compiler/testData/diagnostics/tests/visibility/innerNestedAndAnonymousClasses.kt"); } + @Test + @TestMetadata("invisiblePrivateThroughSubClass.kt") + public void testInvisiblePrivateThroughSubClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.kt"); + } + @Test @TestMetadata("invisibleSetterOfJavaClass.kt") public void testInvisibleSetterOfJavaClass() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java index aaa45f61a06..fc98b201c50 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsTestGenerated.java @@ -33502,6 +33502,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti runTest("compiler/testData/diagnostics/tests/visibility/innerNestedAndAnonymousClasses.kt"); } + @Test + @TestMetadata("invisiblePrivateThroughSubClass.kt") + public void testInvisiblePrivateThroughSubClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.kt"); + } + @Test @TestMetadata("invisibleSetterOfJavaClass.kt") public void testInvisibleSetterOfJavaClass() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java index dc473f2d5ac..6a9ef8f6b59 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendDiagnosticsWithLightTreeTestGenerated.java @@ -33502,6 +33502,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac runTest("compiler/testData/diagnostics/tests/visibility/innerNestedAndAnonymousClasses.kt"); } + @Test + @TestMetadata("invisiblePrivateThroughSubClass.kt") + public void testInvisiblePrivateThroughSubClass() throws Exception { + runTest("compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.kt"); + } + @Test @TestMetadata("invisibleSetterOfJavaClass.kt") public void testInvisibleSetterOfJavaClass() throws Exception { diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt index adc07e3bd65..78cee0354d5 100644 --- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt +++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/FirVisibilityChecker.kt @@ -6,17 +6,17 @@ package org.jetbrains.kotlin.fir import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression -import org.jetbrains.kotlin.fir.expressions.FirThisReceiverExpression import org.jetbrains.kotlin.fir.references.FirSuperReference import org.jetbrains.kotlin.fir.resolve.* -import org.jetbrains.kotlin.fir.resolve.calls.* +import org.jetbrains.kotlin.fir.resolve.calls.ExpressionReceiverValue +import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticFunctionSymbol +import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag @@ -97,7 +97,7 @@ abstract class FirVisibilityChecker : FirSessionComponent { session, useSiteFile, containingDeclarations, - dispatchReceiver, + dispatchReceiver = null, isCallToPropertySetter, supertypeSupplier ) @@ -239,62 +239,26 @@ abstract class FirVisibilityChecker : FirSessionComponent { ) } - fun matchWithContainingDeclarations(): Boolean { - for (declaration in containingDeclarationOfUseSite) { - if (declaration !is FirClass) continue - val boundSymbol = declaration.symbol - if (boundSymbol.classId.isSame(ownerLookupTag.classId)) { - return true - } + val ownerSymbol = ownerLookupTag.toSymbol(session) ?: return true + + val dispatchReceiverValueOwnerLookupTag = + dispatchReceiver.ownerIfCompanion(session) + ?: dispatchReceiver?.type?.findClassRepresentation( + ownerLookupTag.constructClassType(Array(ownerSymbol.fir.typeParameters.size) { ConeStarProjection }, isNullable = true), + session, + ) + + if (dispatchReceiverValueOwnerLookupTag != null && ownerLookupTag != dispatchReceiverValueOwnerLookupTag) return false + + for (declaration in containingDeclarationOfUseSite) { + if (declaration !is FirClass) continue + val boundSymbol = declaration.symbol + if (boundSymbol.classId.isSame(ownerLookupTag.classId)) { + return true } - return false } - return if (isVariableOrNamedFunction && dispatchReceiver?.type is ConeClassLikeType) { - if (dispatchReceiver is ImplicitDispatchReceiverValue) { - val dispatchReceiverOwnerClassId = dispatchReceiver.ownerIfCompanion(session)?.classId ?: dispatchReceiver.type.classId - var isMemberFound = false - for (declaration in containingDeclarationOfUseSite) { - if (declaration !is FirClass) continue - - val boundSymbol = declaration.symbol - var isSameClasses = false - if (!isMemberFound) { - isSameClasses = boundSymbol.classId.isSame(ownerLookupTag.classId) - if (isSameClasses) { - isMemberFound = true - } - } - if (isMemberFound) { - if (!isSameClasses && !( - declaration.isInner || - (declaration.containingNonLocalClass(session) as? FirRegularClass)?.classKind == ClassKind.OBJECT) - ) { - // It should not be ordinary classes between use site and declaration - return false - } - if (boundSymbol.classId.isSame(dispatchReceiverOwnerClassId!!)) { - return true - } - } - } - isMemberFound - } else { - val receiverExpression = dispatchReceiver.receiverExpression - if (receiverExpression is FirThisReceiverExpression && - receiverExpression.source != null && - (containingDeclarationOfUseSite.lastOrNull() as? FirFunction)?.symbol?.isExtension != true - ) { - // Processing of explicit no extension `this` - val dispatchReceiverOwnerClassId = dispatchReceiver.ownerIfCompanion(session)?.classId ?: dispatchReceiver.type.classId - dispatchReceiverOwnerClassId?.isSame(ownerLookupTag.classId) == true - } else { - matchWithContainingDeclarations() - } - } - } else { - matchWithContainingDeclarations() - } + return false } // 'local' isn't taken into account here diff --git a/compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.fir.kt b/compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.fir.kt new file mode 100644 index 00000000000..67926efbe53 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.fir.kt @@ -0,0 +1,11 @@ +// SKIP_TXT + +abstract class A { + fun foo(b: B) { + b.prv() + } + + private fun prv() {} +} + +abstract class B : A() diff --git a/compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.kt b/compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.kt new file mode 100644 index 00000000000..f5d39d9bc57 --- /dev/null +++ b/compiler/testData/diagnostics/tests/visibility/invisiblePrivateThroughSubClass.kt @@ -0,0 +1,11 @@ +// SKIP_TXT + +abstract class A { + fun foo(b: B) { + b.prv() + } + + private fun prv() {} +} + +abstract class B : A()