[FIR] By default, only hide members from mapped scope but not overrides
This affects methods like List.getFirst/getLast where it was decided to keep them hidden but to make them visible on overrides like ArrayList or LinkedList. The goal is to prevent a breaking change since some implementations like LinkedList had this method before JDK 21. #KT-65438
This commit is contained in:
committed by
Space Team
parent
fbe8db4b45
commit
fc6d25e50f
@@ -134,7 +134,7 @@ class JvmMappedScope(
|
||||
|
||||
if (jdkMemberStatus == JDKMemberStatus.DROP) return@processor
|
||||
// hidden methods in final class can't be overridden or called with 'super'
|
||||
if (jdkMemberStatus == JDKMemberStatus.HIDDEN && firKotlinClass.isFinal) return@processor
|
||||
if ((jdkMemberStatus == JDKMemberStatus.HIDDEN || jdkMemberStatus == JDKMemberStatus.HIDDEN_IN_DECLARING_CLASS_ONLY) && firKotlinClass.isFinal) return@processor
|
||||
|
||||
val newSymbol = mappedSymbolCache.mappedFunctions.getValue(symbol, this to jdkMemberStatus)
|
||||
processor(newSymbol)
|
||||
@@ -201,12 +201,13 @@ class JvmMappedScope(
|
||||
}
|
||||
}
|
||||
|
||||
// For unknown methods, we use HIDDEN policy by default
|
||||
return JDKMemberStatus.HIDDEN
|
||||
// For unknown methods, we use HIDDEN_IN_DECLARING_CLASS_ONLY policy by default,
|
||||
// meaning they are hidden in the declaring class but visible with deprecation in overrides.
|
||||
return JDKMemberStatus.HIDDEN_IN_DECLARING_CLASS_ONLY
|
||||
}
|
||||
|
||||
internal enum class JDKMemberStatus {
|
||||
HIDDEN, VISIBLE, DROP
|
||||
HIDDEN, VISIBLE, DROP, HIDDEN_IN_DECLARING_CLASS_ONLY,
|
||||
}
|
||||
|
||||
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
|
||||
@@ -228,7 +229,9 @@ class JvmMappedScope(
|
||||
newSource = oldFunction.source,
|
||||
).apply {
|
||||
if (jdkMemberStatus == JDKMemberStatus.HIDDEN) {
|
||||
isHiddenEverywhereBesideSuperCalls = true
|
||||
isHiddenEverywhereBesideSuperCalls = HiddenEverywhereBesideSuperCallsStatus.HIDDEN
|
||||
} else if (jdkMemberStatus == JDKMemberStatus.HIDDEN_IN_DECLARING_CLASS_ONLY) {
|
||||
isHiddenEverywhereBesideSuperCalls = HiddenEverywhereBesideSuperCallsStatus.HIDDEN_IN_DECLARING_CLASS_ONLY
|
||||
}
|
||||
}
|
||||
return newSymbol
|
||||
|
||||
+14
-2
@@ -15,7 +15,6 @@ import org.jetbrains.kotlin.fir.caches.FirCachesFactory
|
||||
import org.jetbrains.kotlin.fir.caches.firCachesFactory
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||
import org.jetbrains.kotlin.fir.references.FirNamedReference
|
||||
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
|
||||
@@ -327,12 +326,25 @@ fun FirBasedSymbol<*>.isDeprecationLevelHidden(languageVersionSettings: Language
|
||||
|
||||
private object IsHiddenEverywhereBesideSuperCalls : FirDeclarationDataKey()
|
||||
|
||||
var FirCallableDeclaration.isHiddenEverywhereBesideSuperCalls: Boolean? by FirDeclarationDataRegistry.data(
|
||||
var FirCallableDeclaration.isHiddenEverywhereBesideSuperCalls: HiddenEverywhereBesideSuperCallsStatus? by FirDeclarationDataRegistry.data(
|
||||
IsHiddenEverywhereBesideSuperCalls
|
||||
)
|
||||
|
||||
enum class HiddenEverywhereBesideSuperCallsStatus(val affectsOverrides: Boolean) {
|
||||
HIDDEN(true), HIDDEN_IN_DECLARING_CLASS_ONLY(false)
|
||||
}
|
||||
|
||||
private object IsHiddenToOvercomeSignatureClash : FirDeclarationDataKey()
|
||||
|
||||
var FirCallableDeclaration.isHiddenToOvercomeSignatureClash: Boolean? by FirDeclarationDataRegistry.data(
|
||||
IsHiddenToOvercomeSignatureClash
|
||||
)
|
||||
|
||||
fun FirCallableSymbol<*>.isHidden(isSuperCall: Boolean, isOverridden: Boolean): Boolean {
|
||||
val fir = fir
|
||||
return when {
|
||||
fir.isHiddenToOvercomeSignatureClash == true -> true
|
||||
!isSuperCall && fir.isHiddenEverywhereBesideSuperCalls?.let { it.affectsOverrides || !isOverridden } == true -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
@@ -264,8 +264,8 @@ class FirSyntheticPropertiesScope private constructor(
|
||||
var result = Incompatible
|
||||
|
||||
val visited = mutableSetOf<MemberWithBaseScope<FirNamedFunctionSymbol>>()
|
||||
fun checkJavaOrigin(symbol: FirNamedFunctionSymbol, scope: FirTypeScope) {
|
||||
if (symbol.fir.isHiddenEverywhereBesideSuperCalls == true) {
|
||||
fun checkJavaOrigin(symbol: FirNamedFunctionSymbol, scope: FirTypeScope, isOverridden: Boolean) {
|
||||
if (symbol.isHidden(isSuperCall = false, isOverridden = isOverridden)) {
|
||||
isHiddenEverywhereBesideSuperCalls = true
|
||||
}
|
||||
|
||||
@@ -286,11 +286,11 @@ class FirSyntheticPropertiesScope private constructor(
|
||||
|
||||
overriddenWithScope.forEach {
|
||||
if (!visited.add(it)) return@forEach
|
||||
checkJavaOrigin(it.member, it.baseScope)
|
||||
checkJavaOrigin(it.member, it.baseScope, isOverridden = true)
|
||||
}
|
||||
}
|
||||
|
||||
checkJavaOrigin(this, baseScope)
|
||||
checkJavaOrigin(this, baseScope, isOverridden = false)
|
||||
|
||||
return when {
|
||||
isHiddenEverywhereBesideSuperCalls -> Incompatible
|
||||
|
||||
@@ -768,13 +768,13 @@ internal object CheckHiddenDeclaration : ResolutionStage() {
|
||||
): Boolean {
|
||||
val isSuperCall = callInfo.callSite.isSuperCall(session)
|
||||
if (symbol.fir.dispatchReceiverType == null || symbol !is FirNamedFunctionSymbol) return false
|
||||
if (symbol.isHidden(isSuperCall)) return true
|
||||
if (symbol.isHidden(isSuperCall, isOverridden = false)) return true
|
||||
|
||||
val scope = candidate.originScope as? FirTypeScope ?: return false
|
||||
|
||||
var result = false
|
||||
scope.processOverriddenFunctions(symbol) {
|
||||
if (it.isHidden(isSuperCall)) {
|
||||
if (it.isHidden(isSuperCall, isOverridden = true)) {
|
||||
result = true
|
||||
ProcessorAction.STOP
|
||||
} else {
|
||||
@@ -788,10 +788,6 @@ internal object CheckHiddenDeclaration : ResolutionStage() {
|
||||
private fun FirElement.isSuperCall(session: FirSession): Boolean =
|
||||
this is FirQualifiedAccessExpression && explicitReceiver?.toReference(session) is FirSuperReference
|
||||
|
||||
private fun FirCallableSymbol<*>.isHidden(isSuperCall: Boolean): Boolean {
|
||||
val fir = fir
|
||||
return !isSuperCall && fir.isHiddenEverywhereBesideSuperCalls == true || fir.isHiddenToOvercomeSignatureClash == true
|
||||
}
|
||||
}
|
||||
|
||||
private val DYNAMIC_EXTENSION_ANNOTATION_CLASS_ID: ClassId = ClassId.topLevel(DYNAMIC_EXTENSION_FQ_NAME)
|
||||
|
||||
Vendored
+8
-8
@@ -1,11 +1,11 @@
|
||||
fun foo(ll: java.util.LinkedList<String>, al: ArrayList<String>, ad: ArrayDeque<String>, jad: java.util.ArrayDeque<String>) {
|
||||
ll.addFirst("")
|
||||
ll.addLast("")
|
||||
ll.<!UNRESOLVED_REFERENCE!>getFirst<!>()
|
||||
ll.<!INVISIBLE_REFERENCE!>first<!> // synthetic property for getFirst()
|
||||
ll.getFirst()
|
||||
ll.first // synthetic property for getFirst()
|
||||
ll.first() // stdlib extension on List
|
||||
ll.<!UNRESOLVED_REFERENCE!>getLast<!>()
|
||||
ll.<!INVISIBLE_REFERENCE!>last<!>
|
||||
ll.getLast()
|
||||
ll.last
|
||||
ll.last()
|
||||
ll.removeFirst()
|
||||
ll.removeLast()
|
||||
@@ -13,11 +13,11 @@ fun foo(ll: java.util.LinkedList<String>, al: ArrayList<String>, ad: ArrayDeque<
|
||||
|
||||
al.addFirst("")
|
||||
al.addLast("")
|
||||
al.<!UNRESOLVED_REFERENCE!>getFirst<!>()
|
||||
al.<!FUNCTION_CALL_EXPECTED!>first<!>
|
||||
al.getFirst()
|
||||
al.first
|
||||
al.first()
|
||||
al.<!UNRESOLVED_REFERENCE!>getLast<!>()
|
||||
al.<!FUNCTION_CALL_EXPECTED!>last<!>
|
||||
al.getLast()
|
||||
al.last
|
||||
al.last()
|
||||
al.removeFirst()
|
||||
al.removeLast()
|
||||
|
||||
-16
@@ -5,19 +5,3 @@
|
||||
/newListMethods.fir.kt:(704,711): error: Unresolved reference 'getLast'.
|
||||
|
||||
/newListMethods.fir.kt:(720,724): error: Function invocation 'last()' expected.
|
||||
|
||||
/newListMethods.fir.kt:(838,846): error: Unresolved reference 'getFirst'.
|
||||
|
||||
/newListMethods.fir.kt:(855,860): error: Function invocation 'first()' expected.
|
||||
|
||||
/newListMethods.fir.kt:(881,888): error: Unresolved reference 'getLast'.
|
||||
|
||||
/newListMethods.fir.kt:(897,901): error: Function invocation 'last()' expected.
|
||||
|
||||
/newListMethods.fir.kt:(1015,1023): error: Unresolved reference 'getFirst'.
|
||||
|
||||
/newListMethods.fir.kt:(1032,1037): error: Function invocation 'first()' expected.
|
||||
|
||||
/newListMethods.fir.kt:(1058,1065): error: Unresolved reference 'getLast'.
|
||||
|
||||
/newListMethods.fir.kt:(1074,1078): error: Function invocation 'last()' expected.
|
||||
|
||||
@@ -34,11 +34,11 @@ fun foo(x: MutableList<String>, y: ArrayList<String>, z: A<String>) {
|
||||
|
||||
y.addFirst("")
|
||||
y.addLast("")
|
||||
y.<!UNRESOLVED_REFERENCE!>getFirst<!>()
|
||||
y.<!FUNCTION_CALL_EXPECTED!>first<!>
|
||||
y.getFirst()
|
||||
y.first
|
||||
y.first()
|
||||
y.<!UNRESOLVED_REFERENCE!>getLast<!>()
|
||||
y.<!FUNCTION_CALL_EXPECTED!>last<!>
|
||||
y.getLast()
|
||||
y.last
|
||||
y.last()
|
||||
y.<!DEBUG_INFO_CALL("fqName: java.util.ArrayList.removeFirst; typeCall: function")!>removeFirst()<!>
|
||||
y.<!DEBUG_INFO_CALL("fqName: java.util.ArrayList.removeLast; typeCall: function")!>removeLast()<!>
|
||||
@@ -46,11 +46,11 @@ fun foo(x: MutableList<String>, y: ArrayList<String>, z: A<String>) {
|
||||
|
||||
z.addFirst("")
|
||||
z.addLast("")
|
||||
z.<!UNRESOLVED_REFERENCE!>getFirst<!>()
|
||||
z.<!FUNCTION_CALL_EXPECTED!>first<!>
|
||||
z.getFirst()
|
||||
z.first
|
||||
z.first()
|
||||
z.<!UNRESOLVED_REFERENCE!>getLast<!>()
|
||||
z.<!FUNCTION_CALL_EXPECTED!>last<!>
|
||||
z.getLast()
|
||||
z.last
|
||||
z.last()
|
||||
z.<!DEBUG_INFO_CALL("fqName: A.removeFirst; typeCall: function")!>removeFirst()<!>
|
||||
z.<!DEBUG_INFO_CALL("fqName: A.removeLast; typeCall: function")!>removeLast()<!>
|
||||
|
||||
+1
-1
@@ -146,7 +146,7 @@ class FirScopeDumpHandler(testServices: TestServices) : FirAnalysisHandler(testS
|
||||
private fun SmartPrinter.printInfo(declaration: FirCallableDeclaration, scope: FirTypeScope, counter: SymbolCounter) {
|
||||
val origin = declaration.origin.takeUnless { it == FirDeclarationOrigin.BuiltIns } ?: FirDeclarationOrigin.Library
|
||||
print("[$origin]: ")
|
||||
if (declaration.isHiddenEverywhereBesideSuperCalls == true) {
|
||||
if (declaration.isHiddenEverywhereBesideSuperCalls != null) {
|
||||
print("/* hidden beside supers */ ")
|
||||
} else if (declaration.isHiddenToOvercomeSignatureClash == true) {
|
||||
print("/* hidden due to clash */ ")
|
||||
|
||||
Reference in New Issue
Block a user