[FIR] Properly check for visibility in FirTypeIntersectionScopeContext

This fixes a false positive OVERRIDING_FINAL_MEMBER caused by a
package-private member in a different package being added to the
list of overridden symbols. However, in Java, package-private members
from different packages are effectively like private members in that
they cannot be overridden.

#KT-61696 Fixed
This commit is contained in:
Kirill Rakhman
2023-09-07 17:04:46 +02:00
committed by Space Team
parent d16f33cf5b
commit 2bc25d4f6e
10 changed files with 97 additions and 11 deletions
@@ -24825,6 +24825,12 @@ public class DiagnosticCompilerTestFE10TestdataTestGenerated extends AbstractDia
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/kt9550.kt");
}
@Test
@TestMetadata("packagePrivateAndPublic.kt")
public void testPackagePrivateAndPublic() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/packagePrivateAndPublic.kt");
}
@Test
@TestMetadata("returnTypeMismatch.kt")
public void testReturnTypeMismatch() throws Exception {
@@ -24825,6 +24825,12 @@ public class LLFirPreresolvedReversedDiagnosticCompilerFE10TestDataTestGenerated
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/kt9550.kt");
}
@Test
@TestMetadata("packagePrivateAndPublic.kt")
public void testPackagePrivateAndPublic() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/packagePrivateAndPublic.kt");
}
@Test
@TestMetadata("returnTypeMismatch.kt")
public void testReturnTypeMismatch() throws Exception {
@@ -24825,6 +24825,12 @@ public class FirLightTreeOldFrontendDiagnosticsTestGenerated extends AbstractFir
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/kt9550.kt");
}
@Test
@TestMetadata("packagePrivateAndPublic.kt")
public void testPackagePrivateAndPublic() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/packagePrivateAndPublic.kt");
}
@Test
@TestMetadata("returnTypeMismatch.kt")
public void testReturnTypeMismatch() throws Exception {
@@ -24831,6 +24831,12 @@ public class FirPsiOldFrontendDiagnosticsTestGenerated extends AbstractFirPsiDia
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/kt9550.kt");
}
@Test
@TestMetadata("packagePrivateAndPublic.kt")
public void testPackagePrivateAndPublic() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/packagePrivateAndPublic.kt");
}
@Test
@TestMetadata("returnTypeMismatch.kt")
public void testReturnTypeMismatch() throws Exception {
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.name.Name
object FirNativeSessionFactory : FirAbstractSessionFactory() {
@OptIn(SessionConfiguration::class)
fun createLibrarySession(
mainModuleName: Name,
resolvedLibraries: List<KotlinResolvedLibrary>,
@@ -39,6 +40,7 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() {
languageVersionSettings,
extensionRegistrars,
registerExtraComponents = { session ->
session.register(FirVisibilityChecker::class, FirVisibilityChecker.Default)
registerExtraComponents(session)
},
createKotlinScopeProvider = { FirKotlinScopeProvider() },
@@ -18,7 +18,6 @@ import org.jetbrains.kotlin.fir.declarations.utils.visibility
import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.resolve.SupertypeSupplier
import org.jetbrains.kotlin.fir.resolve.calls.FirSimpleSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.calls.ReceiverValue
import org.jetbrains.kotlin.fir.resolve.isSubclassOf
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -76,12 +75,12 @@ object FirJavaVisibilityChecker : FirVisibilityChecker() {
}
override fun platformOverrideVisibilityCheck(
candidateInDerivedClass: FirBasedSymbol<*>,
packageNameOfDerivedClass: FqName,
symbolInBaseClass: FirBasedSymbol<*>,
visibilityInBaseClass: Visibility,
): Boolean = when (visibilityInBaseClass) {
JavaVisibilities.ProtectedAndPackage, JavaVisibilities.ProtectedStaticVisibility -> true
JavaVisibilities.PackageVisibility -> symbolInBaseClass.isInPackage(candidateInDerivedClass.packageFqName())
JavaVisibilities.PackageVisibility -> symbolInBaseClass.isInPackage(packageNameOfDerivedClass)
else -> true
}
@@ -68,7 +68,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
}
override fun platformOverrideVisibilityCheck(
candidateInDerivedClass: FirBasedSymbol<*>,
packageNameOfDerivedClass: FqName,
symbolInBaseClass: FirBasedSymbol<*>,
visibilityInBaseClass: Visibility,
): Boolean {
@@ -151,13 +151,20 @@ abstract class FirVisibilityChecker : FirSessionComponent {
fun isVisibleForOverriding(
candidateInDerivedClass: FirMemberDeclaration,
candidateInBaseClass: FirMemberDeclaration
): Boolean = isVisibleForOverriding(candidateInDerivedClass.moduleData, candidateInDerivedClass.symbol, candidateInBaseClass)
candidateInBaseClass: FirMemberDeclaration,
): Boolean =
isVisibleForOverriding(candidateInDerivedClass.moduleData, candidateInDerivedClass.symbol.packageFqName(), candidateInBaseClass)
fun isVisibleForOverriding(
derivedClassModuleData: FirModuleData,
symbolFromDerivedClass: FirBasedSymbol<*>,
candidateInBaseClass: FirMemberDeclaration,
): Boolean = isVisibleForOverriding(derivedClassModuleData, symbolFromDerivedClass.packageFqName(), candidateInBaseClass)
fun isVisibleForOverriding(
derivedClassModuleData: FirModuleData,
packageNameOfDerivedClass: FqName,
candidateInBaseClass: FirMemberDeclaration,
): Boolean = when (candidateInBaseClass.visibility) {
Visibilities.Internal -> {
candidateInBaseClass.moduleData == derivedClassModuleData ||
@@ -166,7 +173,14 @@ abstract class FirVisibilityChecker : FirSessionComponent {
Visibilities.Private, Visibilities.PrivateToThis -> false
Visibilities.Protected -> true
else -> platformOverrideVisibilityCheck(symbolFromDerivedClass, candidateInBaseClass.symbol, candidateInBaseClass.visibility)
else -> {
platformOverrideVisibilityCheck(
packageNameOfDerivedClass,
candidateInBaseClass.symbol,
candidateInBaseClass.visibility
)
}
}
private fun isSpecificDeclarationVisible(
@@ -249,7 +263,7 @@ abstract class FirVisibilityChecker : FirSessionComponent {
): Boolean
protected abstract fun platformOverrideVisibilityCheck(
candidateInDerivedClass: FirBasedSymbol<*>,
packageNameOfDerivedClass: FqName,
symbolInBaseClass: FirBasedSymbol<*>,
visibilityInBaseClass: Visibility,
): Boolean
@@ -39,7 +39,8 @@ class FirTypeIntersectionScopeContext(
) {
private val overrideService = session.overrideService
private val isReceiverClassExpect = dispatchReceiverType.toRegularClassSymbol(session)?.isExpect == true
private val dispatchClassSymbol: FirRegularClassSymbol? = dispatchReceiverType.toRegularClassSymbol(session)
private val isReceiverClassExpect = dispatchClassSymbol?.isExpect == true
val intersectionOverrides: FirCache<FirCallableSymbol<*>, MemberWithBaseScope<FirCallableSymbol<*>>, ResultOfIntersection.NonTrivial<*>> =
session.intersectionOverrideStorage.cacheByScope.getValue(dispatchReceiverType)
@@ -150,9 +151,9 @@ class FirTypeIntersectionScopeContext(
val result = mutableListOf<ResultOfIntersection<D>>()
while (allMembersWithScope.size > 1) {
val groupWithPrivate =
val groupWithInvisible =
overrideService.extractBothWaysOverridable(allMembersWithScope.maxByVisibility(), allMembersWithScope, overrideChecker)
val group = groupWithPrivate.filter { !Visibilities.isPrivate(it.member.fir.visibility) }.ifEmpty { groupWithPrivate }
val group = groupWithInvisible.filter { it.isVisible() }.ifEmpty { groupWithInvisible }
val nonSubsumed = if (forClassUseSiteScope) group.nonSubsumed() else group
val mostSpecific = overrideService.selectMostSpecificMembers(nonSubsumed, ReturnTypeCalculatorForFullBodyResolve.Default)
val nonTrivial = if (forClassUseSiteScope) {
@@ -186,6 +187,17 @@ class FirTypeIntersectionScopeContext(
return result
}
private fun MemberWithBaseScope<*>.isVisible(): Boolean {
// Checking for private is not enough because package-private declarations can be hidden, too, if they're in a different package.
val dispatchClassSymbol = dispatchClassSymbol ?: return true
return session.visibilityChecker.isVisibleForOverriding(
dispatchClassSymbol.moduleData,
dispatchClassSymbol.classId.packageFqName,
member.fir
)
}
fun <D : FirCallableSymbol<*>> createIntersectionOverride(
mostSpecific: List<MemberWithBaseScope<D>>,
extractedOverrides: List<MemberWithBaseScope<D>>,
@@ -0,0 +1,29 @@
// FIR_IDENTICAL
// FILE: ViewModel.java
package viewmodel;
public class ViewModel {
final void clear() {
}
}
// FILE: samePackage.kt
package viewmodel
interface IMyViewModel {
fun clear()
}
class MyViewModel: ViewModel(), IMyViewModel {
<!OVERRIDING_FINAL_MEMBER!>override<!> fun clear() = Unit
}
// FILE: differentPackage.kt
package different
import viewmodel.IMyViewModel
import viewmodel.ViewModel
class MyViewModel: ViewModel(), IMyViewModel {
override fun clear() = Unit
}
@@ -26571,6 +26571,12 @@ public class DiagnosticTestGenerated extends AbstractDiagnosticTest {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/kt9550.kt");
}
@Test
@TestMetadata("packagePrivateAndPublic.kt")
public void testPackagePrivateAndPublic() throws Exception {
runTest("compiler/testData/diagnostics/tests/override/clashesOnInheritance/packagePrivateAndPublic.kt");
}
@Test
@TestMetadata("returnTypeMismatch.kt")
public void testReturnTypeMismatch() throws Exception {