[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
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.descriptors
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.*
import org.jetbrains.kotlin.analysis.api.descriptors.components.*
@@ -12,11 +13,13 @@ import org.jetbrains.kotlin.analysis.api.impl.base.components.KtAnalysisScopePro
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProvider
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProviderByJavaPsi
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@OptIn(KtAnalysisApiInternals::class)
@Suppress("LeakingThis")
class KtFe10AnalysisSession(
val analysisContext: Fe10AnalysisContext,
@@ -59,6 +62,7 @@ class KtFe10AnalysisSession(
override val signatureSubstitutorImpl: KtSignatureSubstitutor = KtFe10SignatureSubstitutor(this)
override val scopeSubstitutionImpl: KtScopeSubstitution = KtFe10ScopeSubstitution(this)
override val substitutorFactoryImpl: KtSubstitutorFactory = KtFe10SubstitutorFactory(this)
override val symbolProviderByJavaPsiImpl: KtSymbolProviderByJavaPsi = KtFe10SymbolProviderByJavaPsi(this)
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession =
withValidityAssertion {
@@ -0,0 +1,28 @@
/*
* 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.api.descriptors.components
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiMember
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.descriptors.KtFe10AnalysisSession
import org.jetbrains.kotlin.analysis.api.descriptors.components.base.Fe10KtAnalysisSessionComponent
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProviderByJavaPsi
@OptIn(KtAnalysisApiInternals::class)
internal class KtFe10SymbolProviderByJavaPsi(
override val analysisSession: KtFe10AnalysisSession
) : KtSymbolProviderByJavaPsi(), Fe10KtAnalysisSessionComponent {
override fun getNamedClassSymbol(psiClass: PsiClass): KtNamedClassOrObjectSymbol? {
return null /*TODO*/
}
override fun getCallableSymbol(callable: PsiMember): KtCallableSymbol? {
return null /*TODO*/
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.api.fir
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.components.*
import org.jetbrains.kotlin.analysis.api.fir.components.*
@@ -27,10 +28,11 @@ import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@OptIn(KtAnalysisApiInternals::class)
@Suppress("AnalysisApiMissingLifetimeCheck")
internal class KtFirAnalysisSession
private constructor(
private val project: Project,
val project: Project,
val firResolveSession: LLFirResolveSession,
token: KtLifetimeToken,
private val mode: AnalysisSessionMode,
@@ -109,6 +111,8 @@ private constructor(
override val substitutorFactoryImpl: KtSubstitutorFactory = KtFirSubstitutorFactory(this)
override val symbolProviderByJavaPsiImpl = KtFirSymbolProviderByJavaPsi(this)
@Suppress("AnalysisApiMissingLifetimeCheck")
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
check(mode == AnalysisSessionMode.REGULAR) {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.api.fir.components
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.KtSourceElement
import org.jetbrains.kotlin.analysis.api.KtStarProjectionTypeArgument
import org.jetbrains.kotlin.analysis.api.KtTypeArgument
@@ -39,6 +40,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal interface KtFirAnalysisSessionComponent {
val analysisSession: KtFirAnalysisSession
val project: Project get() = analysisSession.project
val rootModuleSession: FirSession get() = analysisSession.firResolveSession.useSiteFirSession
val typeContext: ConeInferenceContext get() = rootModuleSession.typeContext
val firSymbolBuilder get() = analysisSession.firSymbolBuilder
@@ -0,0 +1,46 @@
/*
* 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.api.fir.components
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiField
import com.intellij.psi.PsiMember
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiTypeParameter
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProviderByJavaPsi
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.firClassByPsiClassProvider
import org.jetbrains.kotlin.analysis.project.structure.getKtModule
import org.jetbrains.kotlin.name.Name
@OptIn(KtAnalysisApiInternals::class)
internal class KtFirSymbolProviderByJavaPsi(
override val analysisSession: KtFirAnalysisSession,
) : KtSymbolProviderByJavaPsi(), KtFirAnalysisSessionComponent {
override fun getNamedClassSymbol(psiClass: PsiClass): KtNamedClassOrObjectSymbol? {
if (psiClass.qualifiedName == null) return null
if (psiClass is PsiTypeParameter) return null
val module = psiClass.getKtModule(analysisSession.project)
val provider = firResolveSession.getSessionFor(module).firClassByPsiClassProvider
val firClass = provider.getFirClass(psiClass) ?: return null
return firSymbolBuilder.classifierBuilder.buildNamedClassOrObjectSymbol(firClass)
}
override fun getCallableSymbol(callable: PsiMember): KtCallableSymbol? {
if (callable !is PsiMethod && callable !is PsiField) return null
val name = callable.name?.let(Name::identifier) ?: return null
val containingClass = callable.containingClass ?: return null
val classSymbol = getNamedClassSymbol(containingClass) ?: return null
return with(analysisSession) {
classSymbol.getDeclaredMemberScope()
.getCallableSymbols { it == name }
.firstOrNull { it.psi == callable }
}
}
}
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.analysis.api
import org.jetbrains.kotlin.analysis.api.components.*
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProvider
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbolProviderMixIn
import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.pointers.KtSymbolPointer
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.psi.KtElement
@@ -28,6 +26,7 @@ import org.jetbrains.kotlin.psi.KtFile
*
* To create analysis session consider using [analyse]
*/
@OptIn(KtAnalysisApiInternals::class)
@Suppress("AnalysisApiMissingLifetimeCheck")
public abstract class KtAnalysisSession(final override val token: KtLifetimeToken) : KtLifetimeOwner,
KtSmartCastProviderMixIn,
@@ -59,7 +58,8 @@ public abstract class KtAnalysisSession(final override val token: KtLifetimeToke
KtTypeCreatorMixIn,
KtAnalysisScopeProviderMixIn,
KtSignatureSubstitutorMixIn,
KtScopeSubstitutionMixIn {
KtScopeSubstitutionMixIn,
KtSymbolProviderByJavaPsiMixIn {
public abstract val useSiteModule: KtModule
@@ -155,6 +155,11 @@ public abstract class KtAnalysisSession(final override val token: KtLifetimeToke
public val substitutorFactory: KtSubstitutorFactory get() = substitutorFactoryImpl
protected abstract val substitutorFactoryImpl: KtSubstitutorFactory
@KtAnalysisApiInternals
public val symbolProviderByJavaPsi: KtSymbolProviderByJavaPsi get() = symbolProviderByJavaPsiImpl
@KtAnalysisApiInternals
protected abstract val symbolProviderByJavaPsiImpl: KtSymbolProviderByJavaPsi
@PublishedApi
internal val typesCreator: KtTypeCreator
@@ -0,0 +1,29 @@
/*
* 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.api.symbols
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiMember
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.components.KtAnalysisSessionComponent
import org.jetbrains.kotlin.analysis.api.components.KtAnalysisSessionMixIn
import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion
@KtAnalysisApiInternals
public abstract class KtSymbolProviderByJavaPsi : KtAnalysisSessionComponent() {
public abstract fun getNamedClassSymbol(psiClass: PsiClass): KtNamedClassOrObjectSymbol?
public abstract fun getCallableSymbol(callable: PsiMember): KtCallableSymbol?
}
@KtAnalysisApiInternals
public interface KtSymbolProviderByJavaPsiMixIn : KtAnalysisSessionMixIn {
public fun PsiClass.getNamedClassSymbol(): KtNamedClassOrObjectSymbol? =
withValidityAssertion { analysisSession.symbolProviderByJavaPsi.getNamedClassSymbol(this) }
public fun PsiMember.getCallableSymbol(): KtCallableSymbol? =
withValidityAssertion { analysisSession.symbolProviderByJavaPsi.getCallableSymbol(this) }
}
@@ -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)