FIR: Rework checking dispatch receivers applicability
Using `ownerLookupTag` might be wrong in case of private constuctors of inner classes: their owner is an Inner class, but expected dispach receiver is Outer
This commit is contained in:
+6
@@ -33496,6 +33496,12 @@ public class DiagnosisCompilerTestFE10TestdataTestGenerated extends AbstractDiag
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("innerClassDelegatingConstructorCallToPrivate.kt")
|
||||||
|
public void testInnerClassDelegatingConstructorCallToPrivate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/visibility/innerClassDelegatingConstructorCallToPrivate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("innerConstructorThroughSubclass.kt")
|
@TestMetadata("innerConstructorThroughSubclass.kt")
|
||||||
public void testInnerConstructorThroughSubclass() throws Exception {
|
public void testInnerConstructorThroughSubclass() throws Exception {
|
||||||
|
|||||||
+6
@@ -33496,6 +33496,12 @@ public class FirOldFrontendDiagnosticsTestGenerated extends AbstractFirDiagnosti
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("innerClassDelegatingConstructorCallToPrivate.kt")
|
||||||
|
public void testInnerClassDelegatingConstructorCallToPrivate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/visibility/innerClassDelegatingConstructorCallToPrivate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("innerConstructorThroughSubclass.kt")
|
@TestMetadata("innerConstructorThroughSubclass.kt")
|
||||||
public void testInnerConstructorThroughSubclass() throws Exception {
|
public void testInnerConstructorThroughSubclass() throws Exception {
|
||||||
|
|||||||
+6
@@ -33496,6 +33496,12 @@ public class FirOldFrontendDiagnosticsWithLightTreeTestGenerated extends Abstrac
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.+)\\.kt$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("innerClassDelegatingConstructorCallToPrivate.kt")
|
||||||
|
public void testInnerClassDelegatingConstructorCallToPrivate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/visibility/innerClassDelegatingConstructorCallToPrivate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("innerConstructorThroughSubclass.kt")
|
@TestMetadata("innerConstructorThroughSubclass.kt")
|
||||||
public void testInnerConstructorThroughSubclass() throws Exception {
|
public void testInnerConstructorThroughSubclass() throws Exception {
|
||||||
|
|||||||
@@ -17,9 +17,6 @@ import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier
|
|||||||
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
|
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
|
||||||
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
|
||||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
|
|
||||||
|
|
||||||
@NoMutableState
|
@NoMutableState
|
||||||
object FirJavaVisibilityChecker : FirVisibilityChecker() {
|
object FirJavaVisibilityChecker : FirVisibilityChecker() {
|
||||||
@@ -40,7 +37,7 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
|
|||||||
} else {
|
} else {
|
||||||
val ownerLookupTag = symbol.getOwnerLookupTag() ?: return false
|
val ownerLookupTag = symbol.getOwnerLookupTag() ?: return false
|
||||||
if (canSeeProtectedMemberOf(
|
if (canSeeProtectedMemberOf(
|
||||||
containingDeclarations, dispatchReceiver, ownerLookupTag, session,
|
symbol, containingDeclarations, dispatchReceiver, ownerLookupTag, session,
|
||||||
isVariableOrNamedFunction = symbol.isVariableOrNamedFunction(),
|
isVariableOrNamedFunction = symbol.isVariableOrNamedFunction(),
|
||||||
isSyntheticProperty = symbol.fir is FirSyntheticPropertyAccessor,
|
isSyntheticProperty = symbol.fir is FirSyntheticPropertyAccessor,
|
||||||
supertypeSupplier
|
supertypeSupplier
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
else -> {
|
else -> {
|
||||||
// Member: visible inside parent class, including all its member classes
|
// Member: visible inside parent class, including all its member classes
|
||||||
canSeePrivateMemberOf(
|
canSeePrivateMemberOf(
|
||||||
|
symbol,
|
||||||
containingDeclarations,
|
containingDeclarations,
|
||||||
ownerLookupTag,
|
ownerLookupTag,
|
||||||
dispatchReceiver,
|
dispatchReceiver,
|
||||||
@@ -191,7 +192,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
Visibilities.Protected -> {
|
Visibilities.Protected -> {
|
||||||
val ownerId = symbol.getOwnerLookupTag()
|
val ownerId = symbol.getOwnerLookupTag()
|
||||||
ownerId != null && canSeeProtectedMemberOf(
|
ownerId != null && canSeeProtectedMemberOf(
|
||||||
containingDeclarations, dispatchReceiver, ownerId, session,
|
symbol, containingDeclarations, dispatchReceiver, ownerId, session,
|
||||||
isVariableOrNamedFunction = symbol.isVariableOrNamedFunction(),
|
isVariableOrNamedFunction = symbol.isVariableOrNamedFunction(),
|
||||||
symbol.fir is FirSyntheticPropertyAccessor,
|
symbol.fir is FirSyntheticPropertyAccessor,
|
||||||
supertypeSupplier
|
supertypeSupplier
|
||||||
@@ -223,6 +224,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
): Boolean
|
): Boolean
|
||||||
|
|
||||||
private fun canSeePrivateMemberOf(
|
private fun canSeePrivateMemberOf(
|
||||||
|
symbol: FirBasedSymbol<*>,
|
||||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||||
ownerLookupTag: ConeClassLikeLookupTag,
|
ownerLookupTag: ConeClassLikeLookupTag,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: ReceiverValue?,
|
||||||
@@ -231,6 +233,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
): Boolean {
|
): Boolean {
|
||||||
ownerLookupTag.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
|
ownerLookupTag.ownerIfCompanion(session)?.let { companionOwnerLookupTag ->
|
||||||
return canSeePrivateMemberOf(
|
return canSeePrivateMemberOf(
|
||||||
|
symbol,
|
||||||
containingDeclarationOfUseSite,
|
containingDeclarationOfUseSite,
|
||||||
companionOwnerLookupTag,
|
companionOwnerLookupTag,
|
||||||
dispatchReceiver,
|
dispatchReceiver,
|
||||||
@@ -239,16 +242,25 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val ownerSymbol = ownerLookupTag.toSymbol(session) ?: return true
|
if (dispatchReceiver != null) {
|
||||||
|
val dispatchReceiverParameterClassSymbol =
|
||||||
|
(symbol.fir as? FirCallableDeclaration)
|
||||||
|
?.propertyIfAccessor?.propertyIfBackingField
|
||||||
|
?.dispatchReceiverClassOrNull()?.toSymbol(session)
|
||||||
|
?: return true
|
||||||
|
|
||||||
val dispatchReceiverValueOwnerLookupTag =
|
val dispatchReceiverParameterClassLookupTag = dispatchReceiverParameterClassSymbol.toLookupTag()
|
||||||
dispatchReceiver.ownerIfCompanion(session)
|
val dispatchReceiverValueOwnerLookupTag =
|
||||||
?: dispatchReceiver?.type?.findClassRepresentation(
|
dispatchReceiver.type.findClassRepresentation(
|
||||||
ownerLookupTag.constructClassType(Array(ownerSymbol.fir.typeParameters.size) { ConeStarProjection }, isNullable = true),
|
dispatchReceiverParameterClassLookupTag.constructClassType(
|
||||||
|
Array(dispatchReceiverParameterClassSymbol.fir.typeParameters.size) { ConeStarProjection },
|
||||||
|
isNullable = true
|
||||||
|
),
|
||||||
session,
|
session,
|
||||||
)
|
)
|
||||||
|
|
||||||
if (dispatchReceiverValueOwnerLookupTag != null && ownerLookupTag != dispatchReceiverValueOwnerLookupTag) return false
|
if (dispatchReceiverParameterClassLookupTag != dispatchReceiverValueOwnerLookupTag) return false
|
||||||
|
}
|
||||||
|
|
||||||
for (declaration in containingDeclarationOfUseSite) {
|
for (declaration in containingDeclarationOfUseSite) {
|
||||||
if (declaration !is FirClass) continue
|
if (declaration !is FirClass) continue
|
||||||
@@ -373,6 +385,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun canSeeProtectedMemberOf(
|
protected fun canSeeProtectedMemberOf(
|
||||||
|
usedSymbol: FirBasedSymbol<*>,
|
||||||
containingDeclarationOfUseSite: List<FirDeclaration>,
|
containingDeclarationOfUseSite: List<FirDeclaration>,
|
||||||
dispatchReceiver: ReceiverValue?,
|
dispatchReceiver: ReceiverValue?,
|
||||||
ownerLookupTag: ConeClassLikeLookupTag,
|
ownerLookupTag: ConeClassLikeLookupTag,
|
||||||
@@ -382,6 +395,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
|
|||||||
supertypeSupplier: SupertypeSupplier
|
supertypeSupplier: SupertypeSupplier
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (canSeePrivateMemberOf(
|
if (canSeePrivateMemberOf(
|
||||||
|
usedSymbol,
|
||||||
containingDeclarationOfUseSite,
|
containingDeclarationOfUseSite,
|
||||||
ownerLookupTag,
|
ownerLookupTag,
|
||||||
dispatchReceiver,
|
dispatchReceiver,
|
||||||
@@ -431,19 +445,21 @@ val FirSession.visibilityChecker: FirVisibilityChecker by FirSession.sessionComp
|
|||||||
fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
|
fun FirBasedSymbol<*>.getOwnerLookupTag(): ConeClassLikeLookupTag? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is FirBackingFieldSymbol -> fir.propertySymbol.getOwnerLookupTag()
|
is FirBackingFieldSymbol -> fir.propertySymbol.getOwnerLookupTag()
|
||||||
is FirClassLikeSymbol<*> -> {
|
is FirClassLikeSymbol<*> -> getContainingClassLookupTag()
|
||||||
if (classId.isLocal) {
|
|
||||||
(fir as? FirRegularClass)?.containingClassForLocal()
|
|
||||||
} else {
|
|
||||||
val ownerId = classId.outerClassId
|
|
||||||
ownerId?.let { ConeClassLikeLookupTagImpl(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
is FirCallableSymbol<*> -> containingClass()
|
is FirCallableSymbol<*> -> containingClass()
|
||||||
else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
|
else -> error("Unsupported owner search for ${fir.javaClass}: ${fir.render()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun FirClassLikeSymbol<*>.getContainingClassLookupTag(): ConeClassLikeLookupTag? {
|
||||||
|
return if (classId.isLocal) {
|
||||||
|
(fir as? FirRegularClass)?.containingClassForLocal()
|
||||||
|
} else {
|
||||||
|
val ownerId = classId.outerClassId
|
||||||
|
ownerId?.let { ConeClassLikeLookupTagImpl(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean {
|
fun FirBasedSymbol<*>.isVariableOrNamedFunction(): Boolean {
|
||||||
return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol
|
return this is FirVariableSymbol || this is FirNamedFunctionSymbol || this is FirPropertyAccessorSymbol
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir
|
package org.jetbrains.kotlin.fir
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
import org.jetbrains.kotlin.fir.declarations.utils.isLocal
|
||||||
import org.jetbrains.kotlin.fir.declarations.utils.modality
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
import org.jetbrains.kotlin.fir.symbols.ConeClassLikeLookupTag
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||||
@@ -127,3 +125,9 @@ private object CorrespondingProperty : FirDeclarationDataKey()
|
|||||||
* The corresponding [FirProperty] if the current value parameter is a `val` or `var` declared inside the primary constructor.
|
* The corresponding [FirProperty] if the current value parameter is a `val` or `var` declared inside the primary constructor.
|
||||||
*/
|
*/
|
||||||
var FirValueParameter.correspondingProperty: FirProperty? by FirDeclarationDataRegistry.data(CorrespondingProperty)
|
var FirValueParameter.correspondingProperty: FirProperty? by FirDeclarationDataRegistry.data(CorrespondingProperty)
|
||||||
|
|
||||||
|
val FirCallableDeclaration.propertyIfAccessor: FirCallableDeclaration
|
||||||
|
get() = (this as? FirPropertyAccessor)?.propertySymbol?.fir ?: this
|
||||||
|
|
||||||
|
val FirCallableDeclaration.propertyIfBackingField: FirCallableDeclaration
|
||||||
|
get() = (this as? FirBackingField)?.propertySymbol?.fir ?: this
|
||||||
|
|||||||
Vendored
+10
@@ -0,0 +1,10 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
|
// SKIP_TXT
|
||||||
|
|
||||||
|
val w: Int = 2
|
||||||
|
|
||||||
|
class Outer {
|
||||||
|
private inner class Inner private constructor(x: Int) {
|
||||||
|
constructor() : this(w)
|
||||||
|
}
|
||||||
|
}
|
||||||
Generated
+6
@@ -33586,6 +33586,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
|
|||||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/diagnostics/tests/visibility"), Pattern.compile("^(.*)\\.kts?$"), Pattern.compile("^(.+)\\.fir\\.kts?$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@TestMetadata("innerClassDelegatingConstructorCallToPrivate.kt")
|
||||||
|
public void testInnerClassDelegatingConstructorCallToPrivate() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/visibility/innerClassDelegatingConstructorCallToPrivate.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@TestMetadata("innerConstructorThroughSubclass.kt")
|
@TestMetadata("innerConstructorThroughSubclass.kt")
|
||||||
public void testInnerConstructorThroughSubclass() throws Exception {
|
public void testInnerConstructorThroughSubclass() throws Exception {
|
||||||
|
|||||||
Reference in New Issue
Block a user