All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.fir.java.scopes.JavaClassMembersEnhancementScope.kt Maven / Gradle / Ivy

/*
 * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.fir.java.scopes

import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.jvm.JavaToKotlinClassMap
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirCallableMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.java.enhancement.FirSignatureEnhancement
import org.jetbrains.kotlin.fir.resolve.lookupSuperTypes
import org.jetbrains.kotlin.fir.resolve.substitution.ConeSubstitutor
import org.jetbrains.kotlin.fir.scopes.FirTypeScope
import org.jetbrains.kotlin.fir.scopes.ProcessorAction
import org.jetbrains.kotlin.fir.scopes.impl.FirFakeOverrideGenerator
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptorReplacingKotlinToJava
import org.jetbrains.kotlin.fir.symbols.ConeTypeParameterLookupTag
import org.jetbrains.kotlin.fir.symbols.StandardClassIds
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_COLLECTION_PARAMETER_SIGNATURES
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_VALUE_PARAMETERS_SHORT_NAMES
import org.jetbrains.kotlin.load.java.SpecialGenericSignatures.Companion.ERASED_VALUE_PARAMETERS_SIGNATURES
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.utils.addToStdlib.safeAs

class JavaClassMembersEnhancementScope(
    session: FirSession,
    private val owner: FirRegularClassSymbol,
    private val useSiteMemberScope: JavaClassUseSiteMemberScope,
) : FirTypeScope() {
    private val overriddenFunctions = mutableMapOf, Collection>>()
    private val overriddenProperties = mutableMapOf>()

    private val overrideBindCache = mutableMapOf?, List>>>()
    private val signatureEnhancement = FirSignatureEnhancement(owner.fir, session) {
        overriddenMembers(name)
    }

    override fun processPropertiesByName(name: Name, processor: (FirVariableSymbol<*>) -> Unit) {
        useSiteMemberScope.processPropertiesByName(name) process@{ original ->
            val enhancedPropertySymbol = signatureEnhancement.enhancedProperty(original, name)
            val originalFir = original.fir
            if (originalFir is FirProperty && enhancedPropertySymbol is FirPropertySymbol) {
                val enhancedProperty = enhancedPropertySymbol.fir
                overriddenProperties[enhancedPropertySymbol] =
                    originalFir
                        .overriddenMembers(enhancedProperty.name)
                        .mapNotNull { it.symbol as? FirPropertySymbol }
            }

            processor(enhancedPropertySymbol)
        }

        return super.processPropertiesByName(name, processor)
    }

    private fun FirSimpleFunction.changeSignatureIfErasedValueParameter(): FirSimpleFunction {
        val typeParameters = owner.fir.typeParameters
        if (typeParameters.isEmpty() || name !in ERASED_VALUE_PARAMETERS_SHORT_NAMES) {
            return this
        }
        val jvmDescriptor = this.computeJvmDescriptorReplacingKotlinToJava().replace(
            "kotlin/collections/Collection",
            "java/util/Collection"
        )
        if (ERASED_VALUE_PARAMETERS_SIGNATURES.none { it.endsWith(jvmDescriptor) }) {
            return this
        }
        val superClassIds = listOfNotNull(symbol.callableId.classId) +
                lookupSuperTypes(owner, lookupInterfaces = true, deep = true, useSiteSession = session).map { it.lookupTag.classId }
        for (superClassId in superClassIds) {
            val javaClassId = JavaToKotlinClassMap.mapKotlinToJava(superClassId.asSingleFqName().toUnsafe()) ?: superClassId
            val newParameterTypes: List = when (val fqJvmDescriptor = "${javaClassId.asString()}.$jvmDescriptor") {
                in ERASED_COLLECTION_PARAMETER_SIGNATURES -> {
                    valueParameters.map {
                        val typeParameter = typeParameters.first()
                        ConeClassLikeLookupTagImpl(ClassId.topLevel(StandardNames.FqNames.collection)).constructClassType(
                            arrayOf(
                                ConeTypeParameterLookupTag(typeParameter.symbol).constructType(emptyArray(), isNullable = false)
                            ), isNullable = false
                        )
                    }
                }
                in ERASED_VALUE_PARAMETERS_SIGNATURES -> {
                    val specialSignatureInfo = SpecialGenericSignatures.getSpecialSignatureInfo(fqJvmDescriptor)
                    if (!specialSignatureInfo.isObjectReplacedWithTypeParameter) {
                        return this
                    }
                    valueParameters.mapIndexed { i, valueParameter ->
                        val classLikeType =
                            valueParameter.returnTypeRef.coneTypeSafe()?.lowerBoundIfFlexible().safeAs()
                        if (classLikeType?.lookupTag?.classId == StandardClassIds.Any) {
                            val typeParameterIndex = if (name.asString() == "containsValue") 1 else i
                            val typeParameter = typeParameters.getOrNull(typeParameterIndex) ?: typeParameters.first()
                            val type = ConeTypeParameterLookupTag(typeParameter.symbol).constructType(
                                emptyArray(), valueParameter.returnTypeRef.isMarkedNullable == true
                            )
                            if (valueParameter.returnTypeRef.coneType is ConeFlexibleType) {
                                ConeFlexibleType(
                                    type.withAttributes(
                                        type.attributes.withFlexibleUnless {
                                            it.hasEnhancedNullability
                                        }
                                    ),
                                    type.withNullability(ConeNullability.NULLABLE)
                                )
                            } else {
                                type
                            }
                        } else {
                            null
                        }
                    }
                }
                else -> {
                    continue
                }
            }
            if (newParameterTypes.none { it != null }) {
                return this
            }

            return FirFakeOverrideGenerator.createCopyForFirFunction(
                FirNamedFunctionSymbol(symbol.callableId),
                this,
                session,
                FirDeclarationOrigin.Enhancement,
                newParameterTypes = valueParameters.zip(newParameterTypes).map { (valueParameter, newType) ->
                    newType ?: valueParameter.returnTypeRef.coneType
                },
                newDispatchReceiverType = dispatchReceiverType,
            )

        }
        return this
    }

    override fun processFunctionsByName(name: Name, processor: (FirFunctionSymbol<*>) -> Unit) {
        useSiteMemberScope.processFunctionsByName(name) process@{ original ->
            val symbol = signatureEnhancement.enhancedFunction(original, name)
            val enhancedFunction = (symbol.fir as? FirSimpleFunction)?.changeSignatureIfErasedValueParameter()
            val enhancedFunctionSymbol = enhancedFunction?.symbol ?: symbol

            val originalFunction = original.fir as? FirSimpleFunction

            overriddenFunctions[enhancedFunctionSymbol] =
                if (enhancedFunction != null && originalFunction != null)
                    originalFunction
                        .overriddenMembers(enhancedFunction.name)
                        .mapNotNull { it.symbol as? FirFunctionSymbol<*> }
                else
                    emptyList()

            processor(enhancedFunctionSymbol)
        }

        return super.processFunctionsByName(name, processor)
    }

    private fun FirCallableMemberDeclaration<*>.overriddenMembers(name: Name): List> {
        val backMap = overrideBindCache.getOrPut(name) {
            useSiteMemberScope.bindOverrides(name)
            useSiteMemberScope
                .overrideByBase
                .toList()
                .groupBy({ (_, key) -> key }, { (value) -> value })
        }
        return backMap[this.symbol]?.map { it.fir as FirCallableMemberDeclaration<*> } ?: emptyList()
    }

    override fun processClassifiersByNameWithSubstitution(name: Name, processor: (FirClassifierSymbol<*>, ConeSubstitutor) -> Unit) {
        useSiteMemberScope.processClassifiersByNameWithSubstitution(name, processor)
    }

    override fun processDeclaredConstructors(processor: (FirConstructorSymbol) -> Unit) {
        useSiteMemberScope.processDeclaredConstructors process@{ original ->
            val function = signatureEnhancement.enhancedFunction(original, name = null)
            processor(function as FirConstructorSymbol)
        }
    }

    override fun processDirectOverriddenFunctionsWithBaseScope(
        functionSymbol: FirFunctionSymbol<*>,
        processor: (FirFunctionSymbol<*>, FirTypeScope) -> ProcessorAction
    ): ProcessorAction =
        doProcessDirectOverriddenCallables(
            functionSymbol, processor, overriddenFunctions, useSiteMemberScope,
            FirTypeScope::processDirectOverriddenFunctionsWithBaseScope
        )

    override fun processDirectOverriddenPropertiesWithBaseScope(
        propertySymbol: FirPropertySymbol,
        processor: (FirPropertySymbol, FirTypeScope) -> ProcessorAction
    ): ProcessorAction = doProcessDirectOverriddenCallables(
        propertySymbol, processor, overriddenProperties, useSiteMemberScope,
        FirTypeScope::processDirectOverriddenPropertiesWithBaseScope
    )

    override fun getCallableNames(): Set {
        return useSiteMemberScope.getCallableNames()
    }

    override fun getClassifierNames(): Set {
        return useSiteMemberScope.getClassifierNames()
    }

    override fun mayContainName(name: Name): Boolean {
        return useSiteMemberScope.mayContainName(name)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy