[Analysis API] introduce some basic API to create KtSymbol by Java PSI

^KT-50240
This commit is contained in:
Ilya Kirillov
2022-07-21 21:44:43 +02:00
parent e4d00eea0f
commit b55f36f0fd
13 changed files with 196 additions and 9 deletions
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirElementBuilder
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.file.structure.KtToFirMapping
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.LLFirResolvableResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.state.TowerProviderForElementForState
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.LLFirScopeSessionProvider
@@ -54,7 +55,7 @@ internal class LLFirResolveSessionDepended(
.getScopeSession()
}
override fun getSessionFor(module: KtModule): FirSession =
override fun getSessionFor(module: KtModule): LLFirSession =
originalFirResolveSession.getSessionFor(module)
override fun getOrBuildFirFor(element: KtElement): FirElement? {
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.FirTowerContextProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.diagnostics.KtPsiDiagnostic
import org.jetbrains.kotlin.fir.FirElement
@@ -30,7 +31,7 @@ abstract class LLFirResolveSession {
abstract val useSiteKtModule: KtModule
internal abstract fun getSessionFor(module: KtModule): FirSession
abstract fun getSessionFor(module: KtModule): LLFirSession
abstract fun getScopeSessionFor(firSession: FirSession): ScopeSession
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirFirClassByPsiClassProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.LLFirLibrarySessionProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryLikeSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibrarySession
@@ -77,6 +78,7 @@ internal class LLFirLibrarySessionFactory(
add(builtinsSession.symbolProvider)
}
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
register(FirProvider::class, LLFirLibrarySessionProvider(symbolProvider))
register(FirSymbolProvider::class, symbolProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2022 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.low.level.api.fir.providers
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.PsiTypeParameter
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
import org.jetbrains.kotlin.asJava.KtLightClassMarker
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.resolve.providers.symbolProvider
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
class LLFirFirClassByPsiClassProvider(private val session: LLFirSession) : FirSessionComponent {
fun getFirClass(psiClass: PsiClass): FirRegularClassSymbol? {
require(psiClass !is PsiTypeParameter) {
"${LLFirFirClassByPsiClassProvider::class.simpleName} can create only regular classes"
}
require(psiClass !is KtLightClassMarker) {
"${LLFirFirClassByPsiClassProvider::class.simpleName} can create only non-kotlin classes"
}
if (psiClass.qualifiedName == null) {
return null // not yet supported
}
val firClassSymbol = createFirClassFromFirProvider(psiClass)
check(firClassSymbol.fir.psi == psiClass)
return firClassSymbol
}
private fun createFirClassFromFirProvider(psiClass: PsiClass): FirRegularClassSymbol {
val classId = psiClass.classIdIfNonLocal
?: error("No classId for non-local class")
val provider = session.nullableJavaSymbolProvider ?: session.symbolProvider
val symbol = (provider.getClassLikeSymbolByClassId(classId)
?: error("No classifier found with $classId"))
return symbol as FirRegularClassSymbol
}
}
private val FirSession.nullableJavaSymbolProvider: JavaSymbolProvider? by FirSession.nullableSessionComponentAccessor()
val LLFirSession.firClassByPsiClassProvider: LLFirFirClassByPsiClassProvider by FirSession.sessionComponentAccessor()
private val PsiClass.classIdIfNonLocal: ClassId?
get() {
val packageName = (containingFile as? PsiJavaFile)?.packageName ?: return null
val packageFqName = FqName(packageName)
val classesNames = generateSequence(this) { it.containingClass }.map { it.name }.toList().asReversed()
if (classesNames.any { it == null }) return null
return ClassId(packageFqName, FqName(classesNames.joinToString(separator = ".")), false)
}
@@ -150,6 +150,7 @@ internal object LLFirSessionFactory {
register(FirDependenciesSymbolProvider::class, dependencyProvider)
register(FirJvmTypeMapper::class, FirJvmTypeMapper(this))
register(LLFirFirClassByPsiClassProvider::class, LLFirFirClassByPsiClassProvider(this))
configureSession?.invoke(this)
extensionService.additionalCheckers.forEach(session.checkersComponent::register)
@@ -40,8 +40,8 @@ internal abstract class LLFirResolvableResolveSession(
final override val useSiteFirSession = sessionProvider.rootModuleSession
override fun getSessionFor(module: KtModule): FirSession =
sessionProvider.getResolvableSession(module)
override fun getSessionFor(module: KtModule): LLFirSession =
sessionProvider.getSession(module)
override fun getScopeSessionFor(firSession: FirSession): ScopeSession {
requireIsInstance<LLFirSession>(firSession)