Refactor sir from psi builder, in order to check transatability of psi element

Merge-request: KT-MR-14555
Merged-by: Artem Olkov <artem.olkov@jetbrains.com>
This commit is contained in:
Artem Olkov
2024-02-28 10:32:11 +00:00
committed by Space Team
parent 9d1d01d1eb
commit ff5098d716
4 changed files with 78 additions and 31 deletions
@@ -8,6 +8,7 @@ package org.jetbrains.sir.passes.builder
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind import org.jetbrains.kotlin.analysis.api.symbols.KtClassKind
import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtNamedClassOrObjectSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -20,56 +21,97 @@ import org.jetbrains.kotlin.sir.util.SirSwiftModule
public fun KtAnalysisSession.buildSirDeclarationList(from: KtElement): List<SirDeclaration> { public fun KtAnalysisSession.buildSirDeclarationList(from: KtElement): List<SirDeclaration> {
val res = mutableListOf<SirDeclaration>() val res = mutableListOf<SirDeclaration>()
from.accept(Visitor(res, this)) from.accept(
PsiToSirTranslationCollector(
res,
PsiToSirTranslatableChecker(this),
PsiToSirElementTranslation(this)
)
)
return res.toList() return res.toList()
} }
private class Visitor( private abstract class PsiToSirTranslation<T>(
val analysisSession: KtAnalysisSession,
) : KtVisitor<T, Unit?>() {
abstract override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit?): T
abstract override fun visitNamedFunction(function: KtNamedFunction, data: Unit?): T
abstract override fun visitProperty(property: KtProperty, data: Unit?): T
}
private class PsiToSirTranslationCollector(
private val res: MutableList<SirDeclaration>, private val res: MutableList<SirDeclaration>,
private val analysisSession: KtAnalysisSession private val checker: PsiToSirTranslation<Boolean>,
private val translator: PsiToSirTranslation<SirDeclaration>,
) : KtTreeVisitorVoid() { ) : KtTreeVisitorVoid() {
override fun visitClassOrObject(classOrObject: KtClassOrObject) { override fun visitClassOrObject(classOrObject: KtClassOrObject) {
// we do not handle inner declarations of class currently. No need to go deeper. classOrObject.checkAndTranslate(null)
// super.visitClassOrObject(classOrObject)
with(analysisSession) {
classOrObject.process {
buildSirClassFromPsi(classOrObject)
}
}
} }
override fun visitNamedFunction(function: KtNamedFunction) { override fun visitNamedFunction(function: KtNamedFunction) {
super.visitNamedFunction(function) function.checkAndTranslate(null)
with(analysisSession) {
function.process {
buildSirFunctionFromPsi(function)
}
}
} }
override fun visitProperty(property: KtProperty) { override fun visitProperty(property: KtProperty) {
super.visitProperty(property) property.checkAndTranslate(null)
with(analysisSession) {
property.process {
buildSirVariableFromPsi(property)
}
}
} }
private inline fun <T : KtDeclaration> T.process(converter: T.() -> SirDeclaration?) { private fun KtElement.checkAndTranslate(data: Unit?) = takeIf { it.accept(checker, data) }
this.takeIf { it.isPublic } ?.let { res.add(it.accept(translator, data)) }
?.let(converter) }
?.let { res.add(it) }
private class PsiToSirTranslatableChecker(
analysisSession: KtAnalysisSession,
) : PsiToSirTranslation<Boolean>(analysisSession) {
override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit?): Boolean = with(analysisSession) {
return classOrObject.isPublic
&& classOrObject.getNamedClassOrObjectSymbol()?.isConsumableBySirBuilder() ?: false
}
override fun visitNamedFunction(function: KtNamedFunction, data: Unit?): Boolean = with(analysisSession) {
val functionIsPublicAndTopLevel = function.isPublic
&& function.isTopLevel
&& !function.isAnonymous
val functionSymbolIsTranslatable = (function.getFunctionLikeSymbol() as? KtFunctionSymbol)
?.let { symbol ->
!symbol.isSuspend
&& !symbol.isInline
&& !symbol.isExtension
&& !symbol.isOperator
}
?: true
return functionIsPublicAndTopLevel && functionSymbolIsTranslatable
}
override fun visitProperty(property: KtProperty, data: Unit?): Boolean {
return property.isPublic
&& property.isTopLevel
}
}
private class PsiToSirElementTranslation(
analysisSession: KtAnalysisSession,
) : PsiToSirTranslation<SirDeclaration>(analysisSession) {
override fun visitClassOrObject(classOrObject: KtClassOrObject, data: Unit?): SirDeclaration = with(analysisSession) {
buildSirClassFromPsi(classOrObject)
}
override fun visitNamedFunction(function: KtNamedFunction, data: Unit?): SirDeclaration = with(analysisSession) {
buildSirFunctionFromPsi(function)
}
override fun visitProperty(property: KtProperty, data: Unit?): SirDeclaration = with(analysisSession) {
buildSirVariableFromPsi(property)
} }
} }
context(KtAnalysisSession) context(KtAnalysisSession)
internal fun buildSirClassFromPsi(classOrObject: KtClassOrObject): SirNamedDeclaration? { internal fun buildSirClassFromPsi(classOrObject: KtClassOrObject): SirNamedDeclaration {
val symbol = classOrObject // if there is no symbol - it will be handled by `PsiToSirTranslatableChecker`
.getNamedClassOrObjectSymbol() val symbol = classOrObject.getNamedClassOrObjectSymbol()!!
?.takeIf { it.isConsumableBySirBuilder() }
?: return null // todo: error handling strategy: KT-65980
return buildClass { return buildClass {
name = classOrObject.name ?: "UNKNOWN_CLASS" // todo: error handling strategy: KT-65980 name = classOrObject.name ?: "UNKNOWN_CLASS" // todo: error handling strategy: KT-65980
origin = KotlinSource(symbol) origin = KotlinSource(symbol)
@@ -1,4 +1,5 @@
import KotlinBridges import KotlinBridges
import KotlinRuntime
public class Foo { public class Foo {
} }
@@ -0,0 +1,2 @@
// we do not support extention fun. This should not be exported
fun Int.foo(): Unit = TODO()
@@ -0,0 +1,2 @@
// we do not support sus fun. This should not be exported
suspend fun suspending_fun(): Int = TODO()