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:
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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 {
|
||||
|
||||
+6
@@ -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
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// SKIP_TXT
|
||||
|
||||
abstract class A {
|
||||
fun foo(b: B) {
|
||||
b.<!INVISIBLE_REFERENCE!>prv<!>()
|
||||
}
|
||||
|
||||
private fun prv() {}
|
||||
}
|
||||
|
||||
abstract class B : A()
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// SKIP_TXT
|
||||
|
||||
abstract class A {
|
||||
fun foo(b: B) {
|
||||
b.<!INVISIBLE_MEMBER!>prv<!>()
|
||||
}
|
||||
|
||||
private fun prv() {}
|
||||
}
|
||||
|
||||
abstract class B : A()
|
||||
Reference in New Issue
Block a user