FIR: Refine visibility check for private methods defined in a class

- use-site should be contained within the class that owns callee symbol
- class-representative of dispatch receiver value
should be exactly the same as a container class of a callee (not its subtype)
This commit is contained in:
Denis.Zharkov
2022-05-27 16:02:31 +03:00
committed by teamcity
parent ddb140cc51
commit ccc32b4e3b
6 changed files with 61 additions and 57 deletions
@@ -33502,6 +33502,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
runTest("compiler/testData/diagnostics/tests/visibility/innerNestedAndAnonymousClasses.kt"); 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 @Test
@TestMetadata("invisibleSetterOfJavaClass.kt") @TestMetadata("invisibleSetterOfJavaClass.kt")
public void testInvisibleSetterOfJavaClass() throws Exception { public void testInvisibleSetterOfJavaClass() throws Exception {
@@ -33502,6 +33502,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
runTest("compiler/testData/diagnostics/tests/visibility/innerNestedAndAnonymousClasses.kt"); 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 @Test
@TestMetadata("invisibleSetterOfJavaClass.kt") @TestMetadata("invisibleSetterOfJavaClass.kt")
public void testInvisibleSetterOfJavaClass() throws Exception { public void testInvisibleSetterOfJavaClass() throws Exception {
@@ -33502,6 +33502,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
runTest("compiler/testData/diagnostics/tests/visibility/innerNestedAndAnonymousClasses.kt"); 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 @Test
@TestMetadata("invisibleSetterOfJavaClass.kt") @TestMetadata("invisibleSetterOfJavaClass.kt")
public void testInvisibleSetterOfJavaClass() throws Exception { public void testInvisibleSetterOfJavaClass() throws Exception {
@@ -6,17 +6,17 @@
package org.jetbrains.kotlin.fir package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticPropertyAccessor
import org.jetbrains.kotlin.fir.declarations.utils.* import org.jetbrains.kotlin.fir.declarations.utils.*
import org.jetbrains.kotlin.fir.expressions.FirPropertyAccessExpression 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.references.FirSuperReference
import org.jetbrains.kotlin.fir.resolve.* 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.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
@@ -97,7 +97,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
session, session,
useSiteFile, useSiteFile,
containingDeclarations, containingDeclarations,
dispatchReceiver, dispatchReceiver = null,
isCallToPropertySetter, isCallToPropertySetter,
supertypeSupplier supertypeSupplier
) )
@@ -239,62 +239,26 @@ abstract class FirVisibilityChecker : FirSessionComponent {
) )
} }
fun matchWithContainingDeclarations(): Boolean { val ownerSymbol = ownerLookupTag.toSymbol(session) ?: return true
for (declaration in containingDeclarationOfUseSite) {
if (declaration !is FirClass) continue val dispatchReceiverValueOwnerLookupTag =
val boundSymbol = declaration.symbol dispatchReceiver.ownerIfCompanion(session)
if (boundSymbol.classId.isSame(ownerLookupTag.classId)) { ?: dispatchReceiver?.type?.findClassRepresentation(
return true 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) { return false
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()
}
} }
// 'local' isn't taken into account here // 'local' isn't taken into account here
@@ -0,0 +1,11 @@
// SKIP_TXT
abstract class A {
fun foo(b: B) {
b.<!INVISIBLE_REFERENCE!>prv<!>()
}
private fun prv() {}
}
abstract class B : A()
@@ -0,0 +1,11 @@
// SKIP_TXT
abstract class A {
fun foo(b: B) {
b.<!INVISIBLE_MEMBER!>prv<!>()
}
private fun prv() {}
}
abstract class B : A()