mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
KMT-2065 KMT-2064 KMT-2063 Xcode parity Swift Export
Enables SourceKit code insight for Swift code importing Kotlin modules exported via Swift Export using the .swiftmodule files produced during the regular build. ### Changes - Gradle Sync: Extract Swift Export data model produced by DSL configuration (moduleName, flattenPackage) from KGP via reflection and persist in ProjectDataManager (same way ObjC export does it) - SourceKit Integration: Provide -I compiler flags to SourceKit for built .swiftmodule files, enabling code completion for imported Kotlin modules - Build Listener: Track Swift Export module paths after embed* gradle tasks completion to locate generated artifacts in build/SPMBuild/<target>/<config>/. KGP SwiftExport runner copies it to Xcode build folder from there during Xcode run, we hardcode the path relative to the module with SwiftExport DSL. Merge-request: IJ-MR-187833 Merged-by: Elijah Semyonov <Elijah.Semyonov@jetbrains.com> GitOrigin-RevId: 634c7e7a4bdda0bca3e5996dedefb7f2752baa17
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a46fdb746f
commit
de21bec1fe
+44
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.kotlin.idea.projectModel
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Model representing Swift Export configuration extracted from the Kotlin Gradle Plugin.
|
||||
*
|
||||
* This model captures the configuration from the `swiftExport {}` DSL block in build.gradle.kts
|
||||
* and is serialized during Gradle sync for use by IDE features.
|
||||
*
|
||||
* ## KGP Reference
|
||||
*
|
||||
* `org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.SwiftExportExtension`
|
||||
*
|
||||
* ## Usage in build.gradle.kts
|
||||
*
|
||||
* ```kotlin
|
||||
* kotlin {
|
||||
* swiftExport {
|
||||
* moduleName = "MyModule"
|
||||
* flattenPackage = "com.example.app"
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
interface KotlinSwiftExportModel : Serializable {
|
||||
/**
|
||||
* The configured module name for Swift Export.
|
||||
*
|
||||
* KGP: `SwiftExportExtension.moduleName: Property<String>` (inherited from `SwiftExportedModuleMetadata`)
|
||||
*
|
||||
* If not set, the project name is used as the default module name.
|
||||
*/
|
||||
val moduleName: String?
|
||||
|
||||
/**
|
||||
* The package to flatten in the exported Swift module.
|
||||
*
|
||||
* KGP: `SwiftExportExtension.flattenPackage: Property<String>` (inherited from `SwiftExportedModuleMetadata`)
|
||||
*
|
||||
* When set, the specified package prefix is collapsed in the generated Swift API.
|
||||
*/
|
||||
val flattenPackage: String?
|
||||
}
|
||||
+14
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.idea.projectModel.KotlinDependencyId
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinGradlePluginVersionDependentApi
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinTarget
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinSwiftExportModel
|
||||
import java.io.Serializable
|
||||
|
||||
interface KotlinMPPGradleModel : KotlinSourceSetContainer, Serializable {
|
||||
@@ -27,6 +28,19 @@ interface KotlinMPPGradleModel : KotlinSourceSetContainer, Serializable {
|
||||
val kotlinImportingDiagnostics: KotlinImportingDiagnosticsContainer
|
||||
val kotlinGradlePluginVersion: KotlinGradlePluginVersion?
|
||||
|
||||
/**
|
||||
* Swift Export configuration if enabled in the project, or null if not configured.
|
||||
*
|
||||
* This field is populated by [KotlinMPPGradleModelBuilder.buildSwiftExportModel] during Gradle sync.
|
||||
*
|
||||
* ## KGP Reference
|
||||
* `org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.SwiftExportExtension`
|
||||
*
|
||||
* @see KotlinSwiftExportModel
|
||||
* @see org.jetbrains.kotlin.idea.gradleTooling.reflect.KotlinSwiftExportReflection
|
||||
*/
|
||||
val swiftExport: KotlinSwiftExportModel?
|
||||
|
||||
companion object {
|
||||
const val NO_KOTLIN_NATIVE_HOME = ""
|
||||
}
|
||||
|
||||
+23
-2
@@ -72,7 +72,7 @@ class KotlinMPPGradleModelBuilder : AbstractModelBuilderService() {
|
||||
|
||||
val coroutinesState = getCoroutinesState(project)
|
||||
val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME
|
||||
|
||||
val swiftExportModel = buildSwiftExportModel(kotlinExtensionReflection)
|
||||
|
||||
val model = KotlinMPPGradleModelImpl(
|
||||
sourceSetsByName = filterOrphanSourceSets(importingContext),
|
||||
@@ -84,7 +84,8 @@ class KotlinMPPGradleModelBuilder : AbstractModelBuilderService() {
|
||||
kotlinNativeHome = kotlinNativeHome,
|
||||
dependencyMap = importingContext.dependencyMapper.toDependencyMap(),
|
||||
dependencies = dependenciesContainer,
|
||||
kotlinGradlePluginVersion = importingContext.kotlinGradlePluginVersion
|
||||
kotlinGradlePluginVersion = importingContext.kotlinGradlePluginVersion,
|
||||
swiftExport = swiftExportModel
|
||||
).apply {
|
||||
kotlinImportingDiagnostics += collectDiagnostics(importingContext)
|
||||
}
|
||||
@@ -213,6 +214,26 @@ class KotlinMPPGradleModelBuilder : AbstractModelBuilderService() {
|
||||
return extension.kotlinExtension.javaClass.getMethodOrNull("getTargets") != null && extension.targets.isNotEmpty()
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the [KotlinSwiftExportModelImpl] from the Swift Export DSL configuration.
|
||||
*
|
||||
* ## KGP Reference
|
||||
* `org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.SwiftExportExtension`
|
||||
*
|
||||
* The extension is registered via `addExtension("swiftExport", ...)` in `SetupSwiftExportDSL.kt`,
|
||||
* so it's accessed via [KotlinExtensionReflection.swiftExport] which uses `getExtensions().findByName()`.
|
||||
*
|
||||
* @return The Swift Export model if the extension is configured, null otherwise
|
||||
* @see org.jetbrains.kotlin.idea.gradleTooling.reflect.KotlinSwiftExportReflection
|
||||
*/
|
||||
private fun buildSwiftExportModel(extension: KotlinExtensionReflection): KotlinSwiftExportModelImpl? {
|
||||
val swiftExportReflection = extension.swiftExport ?: return null
|
||||
return KotlinSwiftExportModelImpl(
|
||||
moduleName = swiftExportReflection.moduleName,
|
||||
flattenPackage = swiftExportReflection.flattenPackage
|
||||
)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_IMPORTING_CHECKERS = listOf(OrphanSourceSetImportingChecker)
|
||||
|
||||
|
||||
+27
-2
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.projectModel.KotlinTargetJar
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinTaskProperties
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinTestRunTask
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinWasmCompilationExtensions
|
||||
import org.jetbrains.kotlin.idea.projectModel.KotlinSwiftExportModel
|
||||
import java.io.File
|
||||
|
||||
class KotlinAndroidSourceSetInfoImpl(
|
||||
@@ -282,6 +283,28 @@ data class ExtraFeaturesImpl(
|
||||
override val isHMPPEnabled: Boolean,
|
||||
) : ExtraFeatures
|
||||
|
||||
/**
|
||||
* Implementation of [KotlinSwiftExportModel] for serialization during Gradle sync.
|
||||
*
|
||||
* ## KGP Reference
|
||||
*
|
||||
* This class captures data from the Swift Export DSL in the Kotlin Gradle Plugin:
|
||||
* - Extension: `org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.SwiftExportExtension`
|
||||
* - Source: `libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/swiftexport/SwiftExportExtension.kt`
|
||||
*
|
||||
* @see KotlinSwiftExportModel
|
||||
* @see KotlinMPPGradleModelBuilder.buildSwiftExportModel
|
||||
*/
|
||||
data class KotlinSwiftExportModelImpl(
|
||||
override val moduleName: String?,
|
||||
override val flattenPackage: String?
|
||||
) : KotlinSwiftExportModel {
|
||||
constructor(swiftExport: KotlinSwiftExportModel) : this(
|
||||
moduleName = swiftExport.moduleName,
|
||||
flattenPackage = swiftExport.flattenPackage
|
||||
)
|
||||
}
|
||||
|
||||
data class KotlinMPPGradleModelImpl @OptIn(KotlinGradlePluginVersionDependentApi::class) constructor(
|
||||
override val sourceSetsByName: Map<String, KotlinSourceSet>,
|
||||
override val targets: Collection<KotlinTarget>,
|
||||
@@ -290,7 +313,8 @@ data class KotlinMPPGradleModelImpl @OptIn(KotlinGradlePluginVersionDependentApi
|
||||
override val dependencyMap: Map<KotlinDependencyId, KotlinDependency>,
|
||||
override val dependencies: IdeaKotlinDependenciesContainer?,
|
||||
override val kotlinImportingDiagnostics: KotlinImportingDiagnosticsContainer = mutableSetOf(),
|
||||
override val kotlinGradlePluginVersion: KotlinGradlePluginVersion?
|
||||
override val kotlinGradlePluginVersion: KotlinGradlePluginVersion?,
|
||||
override val swiftExport: KotlinSwiftExportModel? = null
|
||||
) : KotlinMPPGradleModel {
|
||||
|
||||
@OptIn(KotlinGradlePluginVersionDependentApi::class)
|
||||
@@ -312,7 +336,8 @@ data class KotlinMPPGradleModelImpl @OptIn(KotlinGradlePluginVersionDependentApi
|
||||
dependencyMap = mppModel.dependencyMap.map { it.key to it.value.deepCopy(cloningCache) }.toMap(),
|
||||
dependencies = mppModel.dependencies,
|
||||
kotlinImportingDiagnostics = mppModel.kotlinImportingDiagnostics.mapTo(mutableSetOf()) { it.deepCopy(cloningCache) },
|
||||
kotlinGradlePluginVersion = mppModel.kotlinGradlePluginVersion?.reparse()
|
||||
kotlinGradlePluginVersion = mppModel.kotlinGradlePluginVersion?.reparse(),
|
||||
swiftExport = mppModel.swiftExport?.let { KotlinSwiftExportModelImpl(it) }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+31
@@ -33,8 +33,39 @@ class KotlinExtensionReflection(
|
||||
sourceSets.associateBy { it.name }
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Swift Export extension if configured, or null if Swift Export is not enabled.
|
||||
*
|
||||
* ## KGP Reference
|
||||
*
|
||||
* The Swift Export extension is registered in the Kotlin Gradle Plugin via:
|
||||
* - Setup: `SetUpSwiftExportAction` in `SetupSwiftExportDSL.kt`
|
||||
* - Registration: `multiplatformExtension.addExtension("swiftExport", swiftExportExtension)`
|
||||
* - Source: `libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/apple/swiftexport/SetupSwiftExportDSL.kt`
|
||||
*
|
||||
* Because the extension is added via `addExtension()` (not as a direct property),
|
||||
* we must access it via `getExtensions().findByName("swiftExport")` rather than `getSwiftExport()`.
|
||||
*
|
||||
* The extension name constant is defined in `SwiftExportDSLConstants.SWIFT_EXPORT_EXTENSION_NAME = "swiftExport"`.
|
||||
*/
|
||||
val swiftExport: KotlinSwiftExportReflection? by lazy {
|
||||
val extensions = kotlinExtension.callReflectiveAnyGetter("getExtensions", logger) ?: return@lazy null
|
||||
val swiftExportExtension = extensions.callReflective(
|
||||
"findByName",
|
||||
parameters(parameter<String>(SWIFT_EXPORT_EXTENSION_NAME)),
|
||||
returnType<Any?>(),
|
||||
logger
|
||||
) ?: return@lazy null
|
||||
KotlinSwiftExportReflection(swiftExportExtension)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger: ReflectionLogger = ReflectionLogger(KotlinExtensionReflection::class.java)
|
||||
private const val KOTLIN_PLUGIN_WRAPPER_FILE_CLASS_NAME = "org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapperKt"
|
||||
|
||||
/**
|
||||
* KGP: `SwiftExportDSLConstants.SWIFT_EXPORT_EXTENSION_NAME` in `SetupSwiftExportDSL.kt`
|
||||
*/
|
||||
private const val SWIFT_EXPORT_EXTENSION_NAME = "swiftExport"
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package org.jetbrains.kotlin.idea.gradleTooling.reflect
|
||||
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
|
||||
/**
|
||||
* Reflection wrapper for `SwiftExportExtension` from the Kotlin Gradle Plugin.
|
||||
*
|
||||
* This class accesses the Swift Export model configured by DSL via reflection.
|
||||
*
|
||||
* ## KGP reference
|
||||
* `org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.SwiftExportExtension`
|
||||
*
|
||||
* ## DSL example in build.gradle.kts
|
||||
*
|
||||
* ```kotlin
|
||||
* kotlin {
|
||||
* swiftExport {
|
||||
* moduleName.set("MyModule")
|
||||
* flattenPackage.set("com.example")
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @see KotlinExtensionReflection.swiftExport
|
||||
*/
|
||||
fun KotlinSwiftExportReflection(swiftExportExtension: Any): KotlinSwiftExportReflection = KotlinSwiftExportReflectionImpl(swiftExportExtension)
|
||||
|
||||
interface KotlinSwiftExportReflection {
|
||||
/**
|
||||
* The configured module name for Swift Export, or null if not configured.
|
||||
*
|
||||
* KGP: `SwiftExportExtension.moduleName: Property<String>`
|
||||
*/
|
||||
val moduleName: String?
|
||||
|
||||
/**
|
||||
* The package to flatten in the exported Swift module, or null if not configured.
|
||||
*
|
||||
* KGP: `SwiftExportExtension.flattenPackage: Property<String>`
|
||||
*/
|
||||
val flattenPackage: String?
|
||||
}
|
||||
|
||||
private class KotlinSwiftExportReflectionImpl(private val instance: Any) : KotlinSwiftExportReflection {
|
||||
|
||||
override val moduleName: String? by lazy {
|
||||
getPropertyValue("getModuleName")
|
||||
}
|
||||
|
||||
override val flattenPackage: String? by lazy {
|
||||
getPropertyValue("getFlattenPackage")
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to get value from a Gradle `Property<String>` via reflection.
|
||||
*
|
||||
* The Swift Export extension uses Gradle's lazy properties (`Property<String>`),
|
||||
* so we need to call `.orNull` to get the actual value.
|
||||
*/
|
||||
private fun getPropertyValue(getterName: String): String? {
|
||||
return try {
|
||||
val property = instance.callReflectiveAnyGetter(getterName, logger)
|
||||
when (property) {
|
||||
is Property<*> -> property.orNull as? String
|
||||
is Provider<*> -> property.orNull as? String
|
||||
else -> property as? String
|
||||
}
|
||||
}
|
||||
catch (_: Exception) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val logger = ReflectionLogger(KotlinSwiftExportReflection::class.java)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user