add export from kotlin into swift of class content #KT-65896 fixed

Merge-request: KT-MR-14624
Merged-by: Artem Olkov <artem.olkov@jetbrains.com>
This commit is contained in:
Artem Olkov
2024-02-29 18:37:38 +00:00
committed by Space Team
parent 078f0ff6e1
commit e16714fcf9
18 changed files with 299 additions and 54 deletions
@@ -5,9 +5,7 @@
package org.jetbrains.kotlin.sir.bridge.impl
import org.jetbrains.kotlin.sir.SirNominalType
import org.jetbrains.kotlin.sir.SirParameter
import org.jetbrains.kotlin.sir.SirType
import org.jetbrains.kotlin.sir.*
import org.jetbrains.kotlin.sir.bridge.*
import org.jetbrains.kotlin.sir.util.*
@@ -181,4 +179,3 @@ internal enum class KotlinType(val repr: String) {
Float("Float"),
Double("Double"),
}
@@ -33,9 +33,10 @@ abstract class AbstractKotlinSirBridgeTest {
val cBridgePrinter = createCBridgePrinter()
requests.forEach { request ->
val bridge = generator.generate(request)
kotlinBridgePrinter.add(bridge)
cBridgePrinter.add(bridge)
generator.generate(request)?.let {
kotlinBridgePrinter.add(it)
cBridgePrinter.add(it)
}
}
val actualKotlinSrc = kotlinBridgePrinter.print().joinToString(separator = lineSeparator)
@@ -25,7 +25,7 @@ public fun KtAnalysisSession.buildSirDeclarationList(from: KtElement): List<SirD
PsiToSirTranslationCollector(
res,
PsiToSirTranslatableChecker(this),
PsiToSirElementTranslation(this)
PsiToSirElementTranslation(this),
)
)
return res.toList()
@@ -43,10 +43,13 @@ private class PsiToSirTranslationCollector(
private val res: MutableList<SirDeclaration>,
private val checker: PsiToSirTranslation<Boolean>,
private val translator: PsiToSirTranslation<SirDeclaration>,
private val isFirstLevel: Boolean = true,
) : KtTreeVisitorVoid() {
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
classOrObject.checkAndTranslate(null)
if (isFirstLevel) {
classOrObject.checkAndTranslate(null)
}
}
override fun visitNamedFunction(function: KtNamedFunction) {
@@ -72,7 +75,6 @@ private class PsiToSirTranslatableChecker(
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 ->
@@ -87,7 +89,6 @@ private class PsiToSirTranslatableChecker(
override fun visitProperty(property: KtProperty, data: Unit?): Boolean {
return property.isPublic
&& property.isTopLevel
}
}
@@ -110,11 +111,21 @@ private class PsiToSirElementTranslation(
context(KtAnalysisSession)
internal fun buildSirClassFromPsi(classOrObject: KtClassOrObject): SirNamedDeclaration {
// if there is no symbol - it will be handled by `PsiToSirTranslatableChecker`
val symbol = classOrObject.getNamedClassOrObjectSymbol()!!
return buildClass {
name = classOrObject.name ?: "UNKNOWN_CLASS" // todo: error handling strategy: KT-65980
origin = KotlinSource(symbol)
classOrObject.acceptChildren(
PsiToSirTranslationCollector(
declarations,
PsiToSirTranslatableChecker(analysisSession),
PsiToSirElementTranslation(analysisSession),
false
)
)
}.also { resultedClass ->
resultedClass.declarations.forEach { decl -> decl.parent = resultedClass }
}
}
@@ -0,0 +1,21 @@
public class Foo {
public func foo(
arg1: Swift.Bool,
arg2: Swift.Int8,
arg3: Swift.Int16,
arg4: Swift.Int32,
arg5: Swift.Int64,
arg6: Swift.Double,
arg7: Swift.Float
) -> Swift.Bool {
fatalError()
}
public func bar(
arg1: Swift.UInt8,
arg2: Swift.UInt16,
arg3: Swift.UInt32,
arg4: Swift.UInt64
) -> Swift.Bool {
fatalError()
}
}
@@ -0,0 +1,8 @@
public class Foo {
public var my_variable1: Swift.Bool {
get
}
public var my_variable2: Swift.Int8 {
get
}
}
@@ -6,10 +6,7 @@
package org.jetbrains.kotlin.sir.printer
import org.jetbrains.kotlin.sir.*
import org.jetbrains.kotlin.sir.builder.buildClass
import org.jetbrains.kotlin.sir.builder.buildEnum
import org.jetbrains.kotlin.sir.builder.buildFunction
import org.jetbrains.kotlin.sir.builder.buildModule
import org.jetbrains.kotlin.sir.builder.*
import org.jetbrains.kotlin.sir.util.SirSwiftModule
import org.jetbrains.kotlin.test.services.JUnit5Assertions
import org.jetbrains.kotlin.test.util.KtTestUtil
@@ -372,6 +369,136 @@ class SirAsSwiftSourcesPrinterTests {
)
}
@Test
fun `should print class with function`() {
val module = buildModule {
name = "Test"
declarations.add(
buildClass {
origin = SirOrigin.Unknown
name = "Foo"
declarations.add(
buildFunction {
origin = SirOrigin.Unknown
kind = SirCallableKind.INSTANCE_METHOD
visibility = SirVisibility.PUBLIC
name = "foo"
parameters.addAll(
listOf(
SirParameter(
argumentName = "arg1",
type = SirNominalType(SirSwiftModule.bool)
),
SirParameter(
argumentName = "arg2",
type = SirNominalType(SirSwiftModule.int8)
),
SirParameter(
argumentName = "arg3",
type = SirNominalType(SirSwiftModule.int16)
),
SirParameter(
argumentName = "arg4",
type = SirNominalType(SirSwiftModule.int32)
),
SirParameter(
argumentName = "arg5",
type = SirNominalType(SirSwiftModule.int64)
),
SirParameter(
argumentName = "arg6",
type = SirNominalType(SirSwiftModule.double)
),
SirParameter(
argumentName = "arg7",
type = SirNominalType(SirSwiftModule.float)
),
)
)
returnType = SirNominalType(SirSwiftModule.bool)
}
)
declarations.add(
buildFunction {
origin = SirOrigin.Unknown
kind = SirCallableKind.INSTANCE_METHOD
visibility = SirVisibility.PUBLIC
name = "bar"
parameters.addAll(
listOf(
SirParameter(
argumentName = "arg1",
type = SirNominalType(SirSwiftModule.uint8)
),
SirParameter(
argumentName = "arg2",
type = SirNominalType(SirSwiftModule.uint16)
),
SirParameter(
argumentName = "arg3",
type = SirNominalType(SirSwiftModule.uint32)
),
SirParameter(
argumentName = "arg4",
type = SirNominalType(SirSwiftModule.uint64)
),
)
)
returnType = SirNominalType(SirSwiftModule.bool)
}
)
}
)
}
runTest(
module,
"testData/class_with_function"
)
}
@Test
fun `should print class with variable`() {
val module = buildModule {
name = "Test"
declarations.add(
buildClass {
origin = SirOrigin.Unknown
name = "Foo"
declarations.add(
buildVariable {
name = "my_variable1"
type = SirNominalType(SirSwiftModule.bool)
getter = buildGetter {
kind = SirCallableKind.INSTANCE_METHOD
}
}
)
declarations.add(
buildVariable {
name = "my_variable2"
type = SirNominalType(SirSwiftModule.int8)
getter = buildGetter {
kind = SirCallableKind.INSTANCE_METHOD
}
}
)
}
)
}
runTest(
module,
"testData/class_with_variable"
)
}
private fun runTest(module: SirModule, goldenDataFile: String) {
val expectedSwiftSrc = File(KtTestUtil.getHomeDirectory()).resolve("$goldenDataFile.golden.swift")
@@ -19,7 +19,7 @@ sealed class SirAccessor : SirCallable() {
abstract override val visibility: SirVisibility
abstract override var parent: SirDeclarationParent
abstract override val kind: SirCallableKind
abstract var body: SirFunctionBody?
abstract override var body: SirFunctionBody?
override fun <R, D> accept(visitor: SirVisitor<R, D>, data: D): R =
visitor.visitAccessor(this, data)
@@ -19,6 +19,7 @@ sealed class SirCallable : SirElementBase(), SirDeclaration {
abstract override val visibility: SirVisibility
abstract override var parent: SirDeclarationParent
abstract val kind: SirCallableKind
abstract var body: SirFunctionBody?
override fun <R, D> accept(visitor: SirVisitor<R, D>, data: D): R =
visitor.visitCallable(this, data)
@@ -19,10 +19,10 @@ abstract class SirFunction : SirCallable() {
abstract override val visibility: SirVisibility
abstract override var parent: SirDeclarationParent
abstract override val kind: SirCallableKind
abstract override var body: SirFunctionBody?
abstract val name: String
abstract val parameters: List<SirParameter>
abstract val returnType: SirType
abstract var body: SirFunctionBody?
abstract var documentation: String?
override fun <R, D> accept(visitor: SirVisitor<R, D>, data: D): R =
@@ -19,10 +19,10 @@ class SirFunctionBuilder {
var origin: SirOrigin = SirOrigin.Unknown
var visibility: SirVisibility = SirVisibility.PUBLIC
lateinit var kind: SirCallableKind
var body: SirFunctionBody? = null
lateinit var name: String
val parameters: MutableList<SirParameter> = mutableListOf()
lateinit var returnType: SirType
var body: SirFunctionBody? = null
var documentation: String? = null
fun build(): SirFunction {
@@ -30,10 +30,10 @@ class SirFunctionBuilder {
origin,
visibility,
kind,
body,
name,
parameters,
returnType,
body,
documentation,
)
}
@@ -57,10 +57,10 @@ inline fun buildFunctionCopy(original: SirFunction, init: SirFunctionBuilder.()
copyBuilder.origin = original.origin
copyBuilder.visibility = original.visibility
copyBuilder.kind = original.kind
copyBuilder.body = original.body
copyBuilder.name = original.name
copyBuilder.parameters.addAll(original.parameters)
copyBuilder.returnType = original.returnType
copyBuilder.body = original.body
copyBuilder.documentation = original.documentation
return copyBuilder.apply(init).build()
}
@@ -18,10 +18,10 @@ internal class SirFunctionImpl(
override val origin: SirOrigin,
override val visibility: SirVisibility,
override val kind: SirCallableKind,
override var body: SirFunctionBody?,
override val name: String,
override val parameters: MutableList<SirParameter>,
override val returnType: SirType,
override var body: SirFunctionBody?,
override var documentation: String?,
) : SirFunction() {
override lateinit var parent: SirDeclarationParent
@@ -78,6 +78,7 @@ object SwiftIrTree : AbstractSwiftIrTreeBuilder() {
parent(declaration)
+field("kind", callableKind)
+field("body", functionBodyType, nullable = true, mutable = true)
}
val function by element {
@@ -87,7 +88,6 @@ object SwiftIrTree : AbstractSwiftIrTreeBuilder() {
+field("name", string)
+listField("parameters", parameterType)
+field("returnType", typeType)
+field("body", functionBodyType, nullable = true, mutable = true)
+field(name = "documentation", string, nullable = true, mutable = true)
}
@@ -95,8 +95,6 @@ object SwiftIrTree : AbstractSwiftIrTreeBuilder() {
val accessor by sealedElement {
customParentInVisitor = callable
parent(callable)
+field("body", functionBodyType, nullable = true, mutable = true)
}
val getter by element {
@@ -7,19 +7,12 @@ package org.jetbrains.kotlin.swiftexport.standalone.builders
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.psiSafe
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.sir.SirElement
import org.jetbrains.kotlin.sir.SirFunction
import org.jetbrains.kotlin.sir.SirVariable
import org.jetbrains.kotlin.sir.SirAccessor
import org.jetbrains.kotlin.sir.SirSetter
import org.jetbrains.kotlin.sir.SirGetter
import org.jetbrains.kotlin.sir.*
import org.jetbrains.kotlin.sir.util.*
import org.jetbrains.kotlin.sir.SirModule
import org.jetbrains.kotlin.sir.bridge.BridgeRequest
import org.jetbrains.kotlin.sir.bridge.createFunctionBodyFromRequest
import org.jetbrains.kotlin.sir.visitors.SirVisitorVoid
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.sir.passes.SirPass
import org.jetbrains.sir.passes.builder.KotlinSource
import org.jetbrains.sir.passes.run
@@ -46,15 +39,10 @@ private object BridgeGenerationPass : SirPass<SirElement, Nothing?, List<BridgeR
?.callableIdIfNonLocal?.asSingleFqName()
?.pathSegments()?.map { it.toString() }
?: return
val fqNameForBridge = fqName.forBridge
val bridgeRequest = BridgeRequest(
function,
fqNameForBridge.joinToString("_"),
fqName
requests.addIfNotNull(
function.patchCallableBodyAndGenerateRequest(fqName)
)
requests += bridgeRequest
function.body = createFunctionBodyFromRequest(bridgeRequest)
}
override fun visitVariable(variable: SirVariable) {
@@ -62,22 +50,45 @@ private object BridgeGenerationPass : SirPass<SirElement, Nothing?, List<BridgeR
?.callableIdIfNonLocal?.asSingleFqName()
?.pathSegments()?.map { it.toString() }
?: return
val fqNameForBridge = fqName.forBridge
variable.accessors.forEach {
val suffix = it.bridgeSuffix
val request = BridgeRequest(
it,
fqNameForBridge.joinToString("_") + "_$suffix",
fqName
requests.addIfNotNull(
it.patchCallableBodyAndGenerateRequest(fqName)
)
requests += request
it.body = createFunctionBodyFromRequest(request)
}
}
}
}
private fun SirCallable.patchCallableBodyAndGenerateRequest(
fqName: List<String>,
): BridgeRequest? = when (kind) {
SirCallableKind.FUNCTION,
SirCallableKind.STATIC_METHOD,
-> {
val suffix = bridgeSuffix
val request = BridgeRequest(
this,
fqName.forBridge.joinToString("_") + suffix,
fqName
)
body = createFunctionBodyFromRequest(request)
request
}
SirCallableKind.INSTANCE_METHOD,
SirCallableKind.CLASS_METHOD,
-> {
body = SirFunctionBody(listOf("fatalError()"))
null
}
}
private val SirCallable.bridgeSuffix: String
get() = when (this) {
is SirAccessor -> "_$bridgeSuffix"
else -> ""
}
private val SirAccessor.bridgeSuffix: String
get() = when (this) {
is SirGetter -> "get"
@@ -38,11 +38,12 @@ private fun generateBridgeSources(requests: List<BridgeRequest>): BridgeSources
val kotlinBridgePrinter = createKotlinBridgePrinter()
val cBridgePrinter = createCBridgePrinter()
requests.forEach { request ->
val bridge = generator.generate(request)
kotlinBridgePrinter.add(bridge)
cBridgePrinter.add(bridge)
}
requests
.map(generator::generate)
.forEach {
kotlinBridgePrinter.add(it)
cBridgePrinter.add(it)
}
val actualKotlinSrc = kotlinBridgePrinter.print()
val actualCHeader = cBridgePrinter.print()
@@ -6,13 +6,61 @@ public enum namespace {
public class NAMESPACED_CLASS {
}
public class Foo {
public func foo() -> Swift.Bool {
fatalError()
}
public var my_value: Swift.UInt32 {
get {
fatalError()
}
}
public var my_variable: Swift.Int64 {
get {
fatalError()
}
set {
fatalError()
}
}
}
}
public class NAMESPACED_CLASS {
}
public class Foo {
public func foo() -> Swift.Bool {
fatalError()
}
public var my_value: Swift.UInt32 {
get {
fatalError()
}
}
public var my_variable: Swift.Int64 {
get {
fatalError()
}
set {
fatalError()
}
}
}
}
public class Foo {
public func foo() -> Swift.Bool {
fatalError()
}
public var my_value: Swift.UInt32 {
get {
fatalError()
}
}
public var my_variable: Swift.Int64 {
get {
fatalError()
}
set {
fatalError()
}
}
}
@@ -4,4 +4,11 @@ class NAMESPACED_CLASS
class Foo {
class INSIDE_CLASS // this should be ignored currently
fun foo(): Boolean = TODO()
val my_value: UInt = 5u
var my_variable: Long = 5
}
@@ -4,4 +4,11 @@ class NAMESPACED_CLASS
class Foo {
class INSIDE_CLASS // this should be ignored currently
fun foo(): Boolean = TODO()
val my_value: UInt = 5u
var my_variable: Long = 5
}
@@ -1,4 +1,11 @@
class Foo {
class INSIDE_CLASS // this should be ignored currently
fun foo(): Boolean = TODO()
val my_value: UInt = 5u
var my_variable: Long = 5
}