[AA Standalone] Implement KotlinDirectInheritorsProvider

- We are relying on static indexing to find candidates for sealed
  inheritors, hence the extension to the index.
- The direct usage of `KotlinStaticDeclarationProviderFactory` in
  `KotlinStandaloneDirectInheritorsProvider` is not pretty, but a proper
  design requires making the static index available as a service and
  moving "static" services to the Standalone API (from AA providers).

^KT-66013
This commit is contained in:
Marco Pennekamp
2024-02-28 21:18:08 +01:00
committed by Space Team
parent 9bed2e974b
commit b2639a469b
7 changed files with 163 additions and 24 deletions
@@ -19,13 +19,12 @@ import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolOrigin
import org.jetbrains.kotlin.analysis.api.symbols.KtValueParameterSymbol
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.scopes.*
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
import org.jetbrains.kotlin.fir.unwrapFakeOverrides
import org.jetbrains.kotlin.analysis.api.fir.utils.isSubClassOf
internal class KtFirSymbolDeclarationOverridesProvider(
override val analysisSession: KtFirAnalysisSession,
@@ -168,37 +167,23 @@ internal class KtFirSymbolDeclarationOverridesProvider(
}
override fun isSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol): Boolean {
return isSubClassOf(subClass, superClass, checkDeep = true)
return isSubClassOf(subClass, superClass, allowIndirectSubtyping = true)
}
override fun isDirectSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol): Boolean {
return isSubClassOf(subClass, superClass, checkDeep = false)
return isSubClassOf(subClass, superClass, allowIndirectSubtyping = false)
}
private fun isSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol, checkDeep: Boolean): Boolean {
private fun isSubClassOf(subClass: KtClassOrObjectSymbol, superClass: KtClassOrObjectSymbol, allowIndirectSubtyping: Boolean): Boolean {
require(subClass is KtFirSymbol<*>)
require(superClass is KtFirSymbol<*>)
if (subClass == superClass) return false
subClass.firSymbol.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
return isSubClassOf(
subClass = subClass.firSymbol.fir as FirClass,
superClass = superClass.firSymbol.fir as FirClass,
checkDeep
allowIndirectSubtyping,
)
}
private fun isSubClassOf(subClass: FirClass, superClass: FirClass, checkDeep: Boolean): Boolean {
if (subClass.superConeTypes.any { it.toRegularClassSymbol(rootModuleSession) == superClass.symbol }) return true
if (!checkDeep) return false
subClass.superConeTypes.forEach { superType ->
val superOfSub = superType.toRegularClassSymbol(rootModuleSession) ?: return@forEach
superOfSub.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
if (isSubClassOf(superOfSub.fir, superClass, checkDeep = true)) return true
}
return false
}
override fun getIntersectionOverriddenSymbols(symbol: KtCallableSymbol): List<KtCallableSymbol> {
@@ -0,0 +1,29 @@
/*
* 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.analysis.api.fir.utils
import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirResolvePhase
import org.jetbrains.kotlin.fir.declarations.utils.superConeTypes
import org.jetbrains.kotlin.fir.symbols.lazyResolveToPhase
import org.jetbrains.kotlin.fir.types.toRegularClassSymbol
/**
* Returns whether [subClass] is a strict subtype of [superClass]. Resolves [subClass] to [FirResolvePhase.SUPER_TYPES].
*/
fun isSubClassOf(subClass: FirClass, superClass: FirClass, allowIndirectSubtyping: Boolean = true): Boolean {
subClass.lazyResolveToPhase(FirResolvePhase.SUPER_TYPES)
val session = subClass.moduleData.session
if (subClass.superConeTypes.any { it.toRegularClassSymbol(session) == superClass.symbol }) return true
if (!allowIndirectSubtyping) return false
subClass.superConeTypes.forEach { superType ->
val superOfSub = superType.toRegularClassSymbol(session) ?: return@forEach
if (isSubClassOf(superOfSub.fir, superClass, allowIndirectSubtyping = true)) return true
}
return false
}