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

org.jetbrains.kotlin.fir.resolve.DeclarationUtils.kt Maven / Gradle / Ivy

/*
 * Copyright 2010-2024 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.resolve

import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.containingClassLookupTag
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.isInner
import org.jetbrains.kotlin.fir.resolve.dfa.RealVariable
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirValueParameterSymbol
import org.jetbrains.kotlin.fir.types.*

fun FirClassLikeDeclaration.getContainingDeclaration(session: FirSession): FirClassLikeDeclaration? {
    return symbol.getContainingDeclaration(session)?.fir
}

fun FirClassLikeSymbol.getContainingDeclaration(session: FirSession): FirClassLikeSymbol? {
    return session.firProvider.getContainingClass(this)
}

// TODO(KT-66349) Investigate and fix the contract.
//  - Why aren't we supporting nested `inner` classes?
//  - Why are we traversing super types?
fun isValidTypeParameterFromOuterDeclaration(
    typeParameterSymbol: FirTypeParameterSymbol,
    declaration: FirDeclaration?,
    session: FirSession
): Boolean {
    if (declaration == null) {
        return true  // Extra check is required because of classDeclaration will be resolved later
    }

    val visited = mutableSetOf()

    fun containsTypeParameter(currentDeclaration: FirDeclaration?): Boolean {
        if (currentDeclaration == null || !visited.add(currentDeclaration)) {
            return false
        }

        if (currentDeclaration is FirTypeParameterRefsOwner) {
            if (currentDeclaration.typeParameters.any { it.symbol == typeParameterSymbol }) {
                return true
            }

            if (currentDeclaration is FirCallableDeclaration) {
                val containingClassLookupTag = currentDeclaration.containingClassLookupTag() ?: return true
                return containsTypeParameter(containingClassLookupTag.toSymbol(session)?.fir)
            } else if (currentDeclaration is FirClass) {
                for (superTypeRef in currentDeclaration.superTypeRefs) {
                    val superClassFir = superTypeRef.firClassLike(session) ?: return true
                    if (superClassFir is FirRegularClass && containsTypeParameter(superClassFir)) return true
                    if (superClassFir is FirTypeAlias && containsTypeParameter(superClassFir.fullyExpandedClass(session))) return true
                }
            }
        }

        return false
    }

    return containsTypeParameter(declaration)
}

fun FirTypeRef.firClassLike(session: FirSession): FirClassLikeDeclaration? {
    val type = coneTypeSafe() ?: return null
    return type.lookupTag.toSymbol(session)?.fir
}

fun List.toTypeProjections(): Array =
    asReversed().flatMap { it.typeArgumentList.typeArguments.map { typeArgument -> typeArgument.toConeTypeProjection() } }.toTypedArray()

interface FirCodeFragmentContext {
    val towerDataContext: FirTowerDataContext
    val smartCasts: Map>
}

private object CodeFragmentContextDataKey : FirDeclarationDataKey()

var FirCodeFragment.codeFragmentContext: FirCodeFragmentContext? by FirDeclarationDataRegistry.data(CodeFragmentContextDataKey)

/**
 * If `classLikeType` is an inner class,
 * then this function returns a type representing
 * only the "outer" part of `classLikeType`:
 * the part with the outer classes and their
 * type arguments. Returns `null` otherwise.
 */
inline fun outerType(
    classLikeType: ConeClassLikeType,
    session: FirSession,
    outerClass: (FirClassLikeSymbol<*>) -> FirClassLikeSymbol<*>?,
): ConeClassLikeType? {
    val fullyExpandedType = classLikeType.fullyExpandedType(session)

    val symbol = fullyExpandedType.lookupTag.toSymbol(session) ?: return null

    if (symbol is FirRegularClassSymbol && !symbol.fir.isInner) return null

    val containingSymbol = outerClass(symbol) ?: return null
    val currentTypeArgumentsNumber = (symbol as? FirRegularClassSymbol)?.fir?.typeParameters?.count { it is FirTypeParameter } ?: 0

    return containingSymbol.constructType(
        fullyExpandedType.typeArguments.drop(currentTypeArgumentsNumber).toTypedArray(),
    )
}

fun FirBasedSymbol<*>.isContextParameter(): Boolean {
    return this is FirValueParameterSymbol && this.fir.valueParameterKind == FirValueParameterKind.ContextParameter
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy