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");
}
@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 {
@@ -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 {
@@ -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 {
@@ -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
@@ -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()