~~ DO NOT MERGE: Refactoring of the processFunctionsByName
diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt
index e2fe00a..6e4bd24 100644
--- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt
+++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/scopes/JavaClassUseSiteMemberScope.kt
@@ -346,11 +346,9 @@
private fun FirNamedFunctionSymbol.doesOverrideRenamedBuiltins(): Boolean {
// e.g. 'removeAt' or 'toInt'
val builtinName = SpecialGenericSignatures.getBuiltinFunctionNamesByJvmName(name) ?: return false
- val builtinSpecialFromSuperTypes = supertypeScopeContext.collectFunctions(builtinName)
- .flatMap { result ->
- result.overriddenMembers.filter { (symbol, scope) ->
- symbol.doesOverrideBuiltinWithDifferentJvmName(scope, session)
- }.map { it.member }
+ val builtinSpecialFromSuperTypes = supertypeScopeContext.collectMembersGroupedByScope(builtinName, FirScope::processFunctionsByName)
+ .flatMap { (scope, symbols) ->
+ symbols.filter { it.doesOverrideBuiltinWithDifferentJvmName(scope, session) }
}
if (builtinSpecialFromSuperTypes.isEmpty()) return false
@@ -388,7 +386,7 @@
*/
private fun FirNamedFunctionSymbol.shouldBeVisibleAsOverrideOfBuiltInWithErasedValueParameters(): Boolean {
if (!name.sameAsBuiltinMethodWithErasedValueParameters) return false
- val candidatesToOverride = supertypeScopeContext.collectFunctions(name)
+ val candidatesToOverride = supertypeScopeContext.collectIntersectionResultsForCallables(name, FirScope::processFunctionsByName)
.flatMap { it.overriddenMembers }
.filterNot { (member, _) ->
member.valueParameterSymbols.all { it.resolvedReturnType.lowerBoundIfFlexible().isAny }
@@ -432,7 +430,7 @@
collectDeclaredFunctions(name, result)
val explicitlyDeclaredFunctions = result.toSet()
- val functionsWithScopeFromSupertypes = supertypeScopeContext.collectFunctions(name).map { it.overriddenMembers.first().baseScope to listOf(it.chosenSymbol) }
+ val functionsWithScopeFromSupertypes = supertypeScopeContext.collectMembersGroupedByScope(name, FirScope::processFunctionsByName)
if (
!name.sameAsRenamedInJvmBuiltin &&
diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt
index a193e25..ed1df87 100644
--- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt
+++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/scopes/jvm/JvmMappedScope.kt
@@ -116,79 +116,81 @@
}
}
- override fun collectFunctionsByName(name: Name): List<FirNamedFunctionSymbol> {
+ override fun collectFunctionsByName(name: Name): List<FirNamedFunctionSymbol> {
val result = mutableListOf<FirNamedFunctionSymbol>()
-
- // Collect declared functions
- val declared = declaredMemberScope.collectFunctionsByName(name).filter { symbol ->
- !filterOutJvmPlatformDeclarations || FirJvmPlatformDeclarationFilter.isFunctionAvailable(
- symbol.fir,
- javaMappedClassUseSiteScope,
- session
- )
+ val declared = mutableListOf<FirNamedFunctionSymbol>()
+ declaredMemberScope.processFunctionsByName(name) { symbol ->
+ if (!filterOutJvmPlatformDeclarations || FirJvmPlatformDeclarationFilter.isFunctionAvailable(
+ symbol.fir,
+ javaMappedClassUseSiteScope,
+ session
+ )
+ ) {
+ declared += symbol
+ result.add(symbol)
+ }
}
- result.addAll(declared)
- // Collect declared signatures
- val declaredSignatures = buildSet {
- declared.mapTo(this) { it.fir.computeJvmDescriptor() }
- declaredScopeOfMutableVersion?.collectFunctionsByName(name)?.forEach {
- add(it.fir.computeJvmDescriptor())
+ val declaredSignatures: Set<String> by lazy {
+ buildSet {
+ declared.mapTo(this) { it.fir.computeJvmDescriptor() }
+ declaredScopeOfMutableVersion?.processFunctionsByName(name) {
+ add(it.fir.computeJvmDescriptor())
+ }
}
}
var needsHiddenFake = isList && (name == GET_FIRST_NAME || name == GET_LAST_NAME)
- // Process Java mapped functions
- javaMappedClassUseSiteScope.collectFunctionsByName(name)
- .filter { symbol ->
- symbol.isDeclaredInMappedJavaClass() &&
- (symbol.fir.status as FirResolvedDeclarationStatus).visibility.isPublicAPI
- }
- .forEach { symbol ->
- val jvmDescriptor = symbol.fir.computeJvmDescriptor()
-
- // Skip if already declared or special cases
- if (jvmDescriptor in declaredSignatures ||
- isRenamedJdkMethod(jvmDescriptor) ||
- symbol.isOverrideOfKotlinBuiltinPropertyGetter() ||
- isOverrideOfKotlinDeclaredFunction(symbol) ||
- isMutabilityViolation(symbol, jvmDescriptor)
- ) {
- return@forEach
- }
-
- val jdkMemberStatus = getJdkMethodStatus(jvmDescriptor)
-
- // Skip based on JDK member status
- if (jdkMemberStatus == JDKMemberStatus.DROP ||
- ((jdkMemberStatus == JDKMemberStatus.HIDDEN || jdkMemberStatus == JDKMemberStatus.HIDDEN_IN_DECLARING_CLASS_ONLY) && firKotlinClass.isFinal)
- ) {
- return@forEach
- }
-
- val newSymbol = mappedSymbolCache.mappedFunctions.getValue(symbol, this to jdkMemberStatus)
-
- if (needsHiddenFake &&
- allJavaMappedSuperClassIds.any {
- SignatureBuildingComponents.signature(it, jvmDescriptor) in JvmBuiltInsSignatures.DEPRECATED_LIST_METHODS
- }
- ) {
- needsHiddenFake = false
- }
-
- result.add(newSymbol)
+ javaMappedClassUseSiteScope.processFunctionsByName(name) processor@{ symbol ->
+ if (!symbol.isDeclaredInMappedJavaClass() || !(symbol.fir.status as FirResolvedDeclarationStatus).visibility.isPublicAPI) {
+ return@processor
}
- if (needsHiddenFake) {
- // Add hidden fake function for List methods in JDK < 21
- result.add(mappedSymbolCache.hiddenFakeFunctions.getValue(name, this))
+ val jvmDescriptor = symbol.fir.computeJvmDescriptor()
+ // We don't need adding what is already declared
+ if (jvmDescriptor in declaredSignatures) return@processor
+
+ // That condition means that the member is already declared in the built-in class, but has a non-trivially mapped JVM descriptor
+ if (isRenamedJdkMethod(jvmDescriptor) || symbol.isOverrideOfKotlinBuiltinPropertyGetter()) return@processor
+
+ // If it's java.lang.List.contains(Object) it being loaded as contains(E) and treated as an override
+ // of kotlin.collections.Collection.contains(E), thus we're not loading it as an additional JDK member
+ if (isOverrideOfKotlinDeclaredFunction(symbol)) return@processor
+
+ if (isMutabilityViolation(symbol, jvmDescriptor)) return@processor
+
+ val jdkMemberStatus = getJdkMethodStatus(jvmDescriptor)
+
+ if (jdkMemberStatus == JDKMemberStatus.DROP) return@processor
+ // hidden methods in final class can't be overridden or called with 'super'
+ if ((jdkMemberStatus == JDKMemberStatus.HIDDEN || jdkMemberStatus == JDKMemberStatus.HIDDEN_IN_DECLARING_CLASS_ONLY) && firKotlinClass.isFinal) return@processor
+
+ val newSymbol = mappedSymbolCache.mappedFunctions.getValue(symbol, this to jdkMemberStatus)
+
+ if (needsHiddenFake &&
+ allJavaMappedSuperClassIds.any {
+ SignatureBuildingComponents.signature(it, jvmDescriptor) in JvmBuiltInsSignatures.DEPRECATED_LIST_METHODS
+ }
+ ) {
+ needsHiddenFake = false
+ }
+
+ result.add(newSymbol)
}
+ if (needsHiddenFake) {
+ // We're in JDK < 21, i.e., getFirst/getLast don't exist in the List interface yet.
+ // We create a fake version of them for the sole purpose of reporting deprecations on to-become-overrides like in LinkedList.
+ // This is because we want to rename these two methods in the future,
+ // and we want to warn users of older JDKs of a potential breaking change caused by upgrading to JDK >= 21.
+ // See KT-65440.
+ val fakeSymbol = mappedSymbolCache.hiddenFakeFunctions.getValue(name, this)
+ result.add(fakeSymbol)
+ }
return result
}
-
private fun createHiddenFakeFunction(name: Name): FirNamedFunctionSymbol {
return buildSimpleFunction {
moduleData = firKotlinClass.moduleData
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt
index 9911ae1..5d4f341 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/resolve/calls/Synthetics.kt
@@ -74,13 +74,13 @@
val getterNames = syntheticNamesProvider.possibleGetterNamesByPropertyName(name)
var getterFound = false
for (getterName in getterNames) {
- baseScope.collectFunctionsByName(getterName).forEach {
+ baseScope.processFunctionsByName(getterName) {
checkGetAndCreateSynthetic(name, getterName, it, needCheckForSetter = true, processor)
getterFound = true
}
}
if (!getterFound && shouldSearchForJavaRecordComponents()) {
- baseScope.collectFunctionsByName(name).forEach {
+ baseScope.processFunctionsByName(name) {
if (it.fir.isJavaRecordComponent == true) {
checkGetAndCreateSynthetic(name, name, it, needCheckForSetter = false, processor)
}
@@ -136,16 +136,17 @@
var matchingSetter: FirSimpleFunction? = null
if (needCheckForSetter && getterReturnType != null) {
val setterName = syntheticNamesProvider.setterNameByGetterName(getterName)
- baseScope.collectFunctionsByName(setterName).forEach { setterSymbol ->
- if (matchingSetter != null) return@forEach
+ baseScope.processFunctionsByName(setterName, fun(setterSymbol: FirNamedFunctionSymbol) {
+ if (matchingSetter != null) return
val setter = setterSymbol.fir
- if (setter.typeParameters.isNotEmpty() || setter.isStatic) return@forEach
- val parameter = setter.valueParameters.singleOrNull() ?: return@forEach
- val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.coneType ?: return@forEach
- if (!setterTypeIsConsistentWithGetterType(propertyName, getterSymbol, setterSymbol, parameterType)) return@forEach
+ if (setter.typeParameters.isNotEmpty() || setter.isStatic) return
+ val parameter = setter.valueParameters.singleOrNull() ?: return
+ if (parameter.isVararg) return
+ val parameterType = (parameter.returnTypeRef as? FirResolvedTypeRef)?.coneType ?: return
+ if (!setterTypeIsConsistentWithGetterType(propertyName, getterSymbol, setterSymbol, parameterType)) return
matchingSetter = setterSymbol.fir
- }
+ })
}
val property = buildSyntheticProperty(propertyName, getter, matchingSetter, getterCompatibility, deprecatedOverrideOfHidden)
@@ -404,3 +405,4 @@
val FirSimpleSyntheticPropertySymbol.deprecatedOverrideOfHidden: Boolean
get() = (fir as FirSyntheticProperty).deprecatedOverrideOfHidden == true
+
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt
index ecc0ee5..4c02a4a 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirAbstractImportingScope.kt
@@ -115,10 +115,6 @@
)
}
- protected fun processFunctionsByName(name: Name?, imports: List<FirResolvedImport>, processor: (FirNamedFunctionSymbol) -> Unit) {
- collectFunctionsByName(name, imports).forEach(processor)
- }
-
protected fun processPropertiesByName(name: Name?, imports: List<FirResolvedImport>, processor: (FirVariableSymbol<*>) -> Unit) {
processCallablesFromImportsByName(
name,
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirActualizingScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirActualizingScope.kt
index 3a9f382..0b49664 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirActualizingScope.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirActualizingScope.kt
@@ -50,13 +50,13 @@
@Suppress("UNCHECKED_CAST")
private fun <S : FirCallableSymbol<*>> collectCallableSymbols(
name: Name,
- collect: () -> List<S>
+ collect: (Name) -> List<S>
): List<S> {
val filteredSymbols = mutableSetOf<S>()
// All matched `expect` callables should be preserved to make it possible to filter them out later if corresponding actuals are found
val ignoredExpectSymbols = mutableSetOf<FirBasedSymbol<*>>()
- collect().forEach { symbol ->
+ collect(name).forEach { symbol ->
if (symbol.isActual) {
val matchedExpectSymbol = symbol.getSingleMatchedExpectForActualOrNull()
if (matchedExpectSymbol != null) {
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt
index 8399aba..2af112d 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScope.kt
@@ -35,24 +35,27 @@
override fun collectFunctionsByName(name: Name): List<FirNamedFunctionSymbol> {
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getCallableNames()) return emptyList()
-
- val callablesWithOverridden = intersectionContext.collectFunctions(name)
-
- return callablesWithOverridden.map { resultOfIntersection ->
- val symbol = resultOfIntersection.chosenSymbol
- overriddenSymbols[symbol] = resultOfIntersection.overriddenMembers
- symbol
+ return buildList {
+ processCallablesByName(name, processor = {
+ this.add(it)
+ }, processCallables = { name, proc ->
+ collectFunctionsByName(name).forEach(proc)
+ })
}
}
override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
// Important optimization: avoid creating cache keys for names that are definitely absent
if (name !in getCallableNames()) return
+ processCallablesByName(name, processor, FirScope::processPropertiesByName)
+ }
- val callablesWithOverridden = intersectionContext.collectIntersectionResultsForCallables(
- name,
- FirScope::processPropertiesByName
- )
+ private inline fun <D : FirCallableSymbol<*>> processCallablesByName(
+ name: Name,
+ noinline processor: (D) -> Unit,
+ processCallables: FirScope.(Name, (D) -> Unit) -> Unit
+ ) {
+ val callablesWithOverridden = intersectionContext.collectIntersectionResultsForCallables(name, processCallables)
for (resultOfIntersection in callablesWithOverridden) {
val symbol = resultOfIntersection.chosenSymbol
diff --git a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt
index 0c148b5..0a1ffe9 100644
--- a/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt
+++ b/compiler/fir/providers/src/org/jetbrains/kotlin/fir/scopes/impl/FirTypeIntersectionScopeContext.kt
@@ -103,11 +103,9 @@
}
fun collectFunctions(name: Name): List<ResultOfIntersection<FirNamedFunctionSymbol>> {
- val membersByScope = scopes.mapNotNull { scope ->
- val members = scope.collectFunctionsByName(name)
- if (members.isNotEmpty()) scope to members else null
- }
- return convertGroupedCallablesToIntersectionResults(membersByScope)
+ return collectIntersectionResultsForCallables(name, processCallables = { name, proc ->
+ collectFunctionsByName(name).forEach(proc)
+ })
}
inline fun <D : FirCallableSymbol<*>> collectMembersGroupedByScope(
diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt
index 1b46064..0e9bde6 100644
--- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt
+++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/scopes/FirScope.kt
@@ -22,7 +22,7 @@
}
- @Deprecated("Obsolete API, please use collectFunctionsByName instead", ReplaceWith("collectFunctionsByName()"), DeprecationLevel.ERROR)
+ //@Deprecated("Obsolete API, please use collectFunctionsByName instead", ReplaceWith("collectFunctionsByName()"), DeprecationLevel.ERROR)
final fun processFunctionsByName(
name: Name,
processor: (FirNamedFunctionSymbol) -> Unit