diff --git a/plugins/devkit/intellij.devkit.gradle.tooling/BUILD.bazel b/plugins/devkit/intellij.devkit.gradle.tooling/BUILD.bazel
index 49ad61bcbeb2..23aad88696c7 100644
--- a/plugins/devkit/intellij.devkit.gradle.tooling/BUILD.bazel
+++ b/plugins/devkit/intellij.devkit.gradle.tooling/BUILD.bazel
@@ -21,7 +21,9 @@ jvm_library(
visibility = ["//visibility:public"],
deps = [
# do not sort,
+ "@lib//:kotlin-stdlib",
"@lib//:jetbrains-annotations",
+ "//plugins/gradle/tooling-extension-api:toolingExtension",
"//plugins/gradle/tooling-extension-impl:toolingExtension-impl",
"@lib//:gradle-provided",
],
@@ -40,6 +42,7 @@ jvm_library(
runtime_deps = [
# do not sort,
":gradle-tooling",
+ "//plugins/gradle/tooling-extension-api:toolingExtension_test_lib",
"//plugins/gradle/tooling-extension-impl:toolingExtension-impl_test_lib",
"@lib//:gradle-provided",
],
diff --git a/plugins/devkit/intellij.devkit.gradle.tooling/intellij.devkit.gradle.tooling.iml b/plugins/devkit/intellij.devkit.gradle.tooling/intellij.devkit.gradle.tooling.iml
index 419d88beb3ce..ba3385a3319c 100644
--- a/plugins/devkit/intellij.devkit.gradle.tooling/intellij.devkit.gradle.tooling.iml
+++ b/plugins/devkit/intellij.devkit.gradle.tooling/intellij.devkit.gradle.tooling.iml
@@ -24,7 +24,9 @@
+
+
diff --git a/plugins/devkit/intellij.devkit.gradle.tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService b/plugins/devkit/intellij.devkit.gradle.tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService
new file mode 100644
index 000000000000..59982aec2c35
--- /dev/null
+++ b/plugins/devkit/intellij.devkit.gradle.tooling/resources/META-INF/services/org.jetbrains.plugins.gradle.tooling.ModelBuilderService
@@ -0,0 +1,2 @@
+# Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+com.intellij.devkit.gradle.tooling.IntelliJPlatformModelBuilder
diff --git a/plugins/devkit/intellij.devkit.gradle.tooling/resources/intellij.devkit.gradle.tooling.xml b/plugins/devkit/intellij.devkit.gradle.tooling/resources/intellij.devkit.gradle.tooling.xml
index e467e3052012..02629f4e6d23 100644
--- a/plugins/devkit/intellij.devkit.gradle.tooling/resources/intellij.devkit.gradle.tooling.xml
+++ b/plugins/devkit/intellij.devkit.gradle.tooling/resources/intellij.devkit.gradle.tooling.xml
@@ -1,5 +1,7 @@
+
+
diff --git a/plugins/devkit/intellij.devkit.gradle.tooling/src/com/intellij/devkit/gradle/tooling/IntelliJPlatformModelBuilder.kt b/plugins/devkit/intellij.devkit.gradle.tooling/src/com/intellij/devkit/gradle/tooling/IntelliJPlatformModelBuilder.kt
new file mode 100644
index 000000000000..17fee930f9e8
--- /dev/null
+++ b/plugins/devkit/intellij.devkit.gradle.tooling/src/com/intellij/devkit/gradle/tooling/IntelliJPlatformModelBuilder.kt
@@ -0,0 +1,95 @@
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package com.intellij.devkit.gradle.tooling
+
+import org.gradle.api.Project
+import org.gradle.api.plugins.ExtensionAware
+import org.gradle.tooling.model.Model
+import org.jetbrains.annotations.ApiStatus
+import org.jetbrains.plugins.gradle.tooling.AbstractModelBuilderService
+import org.jetbrains.plugins.gradle.tooling.Message
+import org.jetbrains.plugins.gradle.tooling.ModelBuilderContext
+import java.io.Serializable
+import java.lang.reflect.ParameterizedType
+
+private const val INTELLIJ_PLATFORM_EXTENSION_NAME = "intellijPlatform"
+private const val INTELLIJ_PLATFORM_DEPENDENCY_CONFIGURATION_CLASS =
+ "org.jetbrains.intellij.platform.gradle.extensions.IntelliJPlatformDependencyConfiguration"
+private const val INTELLIJ_PLATFORM_TYPE_CLASS = "org.jetbrains.intellij.platform.gradle.IntelliJPlatformType"
+private const val DUMP_PRODUCTS_RELEASES_TASK_NAME = "dumpProductsReleases"
+private const val GRADLE_ACTION_CLASS = "org.gradle.api.Action"
+private const val PRODUCT_CODE_GETTER = "getCode"
+
+/**
+ * Transfers IntelliJ Platform dependency helpers and the generated product-release catalog from Gradle to the IDE.
+ */
+@ApiStatus.Internal
+interface IntelliJPlatformGradleModel : Model, Serializable {
+ val dependencyHelperProductCodes: Map
+ val productReleasesFile: String?
+}
+
+internal class IntelliJPlatformGradleModelImpl(
+ override val dependencyHelperProductCodes: Map,
+ override val productReleasesFile: String?,
+) : IntelliJPlatformGradleModel
+
+/**
+ * Reflects over the IntelliJ Platform Gradle Plugin DSL and schedules its release-catalog dump for IDE import.
+ */
+@ApiStatus.Internal
+class IntelliJPlatformModelBuilder : AbstractModelBuilderService() {
+
+ override fun canBuild(modelName: String?): Boolean {
+ return modelName == IntelliJPlatformGradleModel::class.java.name
+ }
+
+ override fun buildAll(modelName: String, project: Project, context: ModelBuilderContext): Any? {
+ val extension = (project.dependencies as? ExtensionAware)
+ ?.extensions
+ ?.findByName(INTELLIJ_PLATFORM_EXTENSION_NAME)
+ ?: return null
+ val dumpTask = project.tasks.findByName(DUMP_PRODUCTS_RELEASES_TASK_NAME)
+
+ if (dumpTask != null) {
+ project.gradle.startParameter.setTaskNames(
+ project.gradle.startParameter.taskNames.toSet() + dumpTask.path,
+ )
+ }
+
+ return IntelliJPlatformGradleModelImpl(
+ dependencyHelperProductCodes = extension.javaClass.loadDependencyHelperProductCodes(),
+ productReleasesFile = dumpTask?.outputs?.files?.singleFile?.absolutePath,
+ )
+ }
+
+ override fun reportErrorMessage(modelName: String, project: Project, context: ModelBuilderContext, exception: Exception) {
+ context.messageReporter.createMessage()
+ .withGroup(this)
+ .withKind(Message.Kind.WARNING)
+ .withTitle("Gradle import errors")
+ .withText("Unable to build IntelliJ Platform project configuration")
+ .withException(exception)
+ .reportMessage(project)
+ }
+
+ private fun Class<*>.loadDependencyHelperProductCodes(): Map {
+ val platformTypeClass = classLoader.loadClass(INTELLIJ_PLATFORM_TYPE_CLASS)
+ val productCodeGetter = platformTypeClass.getMethod(PRODUCT_CODE_GETTER)
+ val productCodeByTypeName = platformTypeClass.enumConstants.associate { platformType ->
+ (platformType as Enum<*>).name.lowercase() to productCodeGetter.invoke(platformType) as String
+ }
+
+ return methods.asSequence()
+ .filter { method ->
+ method.genericParameterTypes.any { parameterType ->
+ parameterType is ParameterizedType &&
+ parameterType.rawType.typeName == GRADLE_ACTION_CLASS &&
+ parameterType.actualTypeArguments.any { it.typeName == INTELLIJ_PLATFORM_DEPENDENCY_CONFIGURATION_CLASS }
+ }
+ }
+ .mapNotNull { method ->
+ productCodeByTypeName[method.name.lowercase()]?.let { method.name to it }
+ }
+ .toMap(sortedMapOf())
+ }
+}
diff --git a/plugins/devkit/intellij.devkit.gradle/BUILD.bazel b/plugins/devkit/intellij.devkit.gradle/BUILD.bazel
index 3e2139c2d043..710b9a617644 100644
--- a/plugins/devkit/intellij.devkit.gradle/BUILD.bazel
+++ b/plugins/devkit/intellij.devkit.gradle/BUILD.bazel
@@ -19,8 +19,10 @@ jvm_library(
["resources/**/*"],
),
visibility = ["//visibility:public"],
+ runtime_deps = ["//plugins/kotlin/plugin"],
deps = [
# do not sort,
+ "@lib//:kotlin-stdlib",
"//java/idea-ui:ui",
"//platform/core-api:core",
"//platform/core-impl",
@@ -35,9 +37,11 @@ jvm_library(
"//platform/analysis-api:analysis",
"//platform/execution",
"//platform/lang-api:lang",
+ "//platform/util",
"//plugins/gradle",
"//plugins/gradle:gradle-common",
"//plugins/gradle/java",
+ "//plugins/gradle/tooling-extension-api:toolingExtension",
"//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling",
"//platform/smRunner",
"//plugins/devkit/devkit-core:core",
@@ -51,6 +55,8 @@ jvm_library(
"//platform/backend/workspace",
"//platform/projectModel-impl",
"//jps/model-api:model",
+ "//plugins/kotlin/base/psi",
+ "@lib//:kotlinc-kotlin-compiler-common-provided",
],
)
@@ -80,9 +86,11 @@ jvm_library(
"//platform/analysis-api:analysis_test_lib",
"//platform/execution:execution_test_lib",
"//platform/lang-api:lang_test_lib",
+ "//platform/util:util_test_lib",
"//plugins/gradle:gradle_test_lib",
"//plugins/gradle:gradle-common_test_lib",
"//plugins/gradle/java:java_test_lib",
+ "//plugins/gradle/tooling-extension-api:toolingExtension_test_lib",
"//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling_test_lib",
"//platform/smRunner:smRunner_test_lib",
"//plugins/devkit/devkit-core:core_test_lib",
@@ -100,6 +108,9 @@ jvm_library(
"//platform/backend/workspace:workspace_test_lib",
"//platform/projectModel-impl:projectModel-impl_test_lib",
"//jps/model-api:model_test_lib",
+ "//plugins/kotlin/plugin:plugin_test_lib",
+ "//plugins/kotlin/base/psi:psi_test_lib",
+ "@lib//:kotlinc-kotlin-compiler-common-provided",
],
)
### auto-generated section `build intellij.devkit.gradle` end
@@ -207,6 +218,8 @@ jvm_library(
"//platform/projectModel-impl:projectModel-impl_test_lib",
"//jps/model-api:model",
"//jps/model-api:model_test_lib",
+ "//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling",
+ "//plugins/devkit/intellij.devkit.gradle.tooling:gradle-tooling_test_lib",
"//libraries/junit4",
"//libraries/junit4:junit4_test_lib",
],
diff --git a/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.iml b/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.iml
index 26f855812a42..2408aa216bb9 100644
--- a/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.iml
+++ b/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.iml
@@ -8,6 +8,7 @@
+
@@ -22,9 +23,11 @@
+
+
@@ -40,5 +43,8 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.tests.iml b/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.tests.iml
index 6fe031b75f14..50a7b3ea9e8b 100644
--- a/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.tests.iml
+++ b/plugins/devkit/intellij.devkit.gradle/intellij.devkit.gradle.tests.iml
@@ -38,6 +38,7 @@
+
diff --git a/plugins/devkit/intellij.devkit.gradle/resources/intellij.devkit.gradle.xml b/plugins/devkit/intellij.devkit.gradle/resources/intellij.devkit.gradle.xml
index 43d3815abf20..3edb393d9caf 100644
--- a/plugins/devkit/intellij.devkit.gradle/resources/intellij.devkit.gradle.xml
+++ b/plugins/devkit/intellij.devkit.gradle/resources/intellij.devkit.gradle.xml
@@ -1,10 +1,12 @@
+
+
@@ -19,5 +21,14 @@
+
+
-
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/devkit/intellij.devkit.gradle/src/DevKitGradleProjectResolverExtension.kt b/plugins/devkit/intellij.devkit.gradle/src/DevKitGradleProjectResolverExtension.kt
index 07cb0bdb0391..6b20880cd037 100644
--- a/plugins/devkit/intellij.devkit.gradle/src/DevKitGradleProjectResolverExtension.kt
+++ b/plugins/devkit/intellij.devkit.gradle/src/DevKitGradleProjectResolverExtension.kt
@@ -2,9 +2,22 @@
package org.jetbrains.idea.devkit.gradle
import com.intellij.devkit.gradle.tooling.IntelliJPlatformAuxiliaryArtifactProvider
+import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
+import com.intellij.gradle.toolingExtension.modelAction.GradleModelFetchPhase
+import com.intellij.gradle.toolingExtension.modelProvider.GradleClassProjectModelProvider
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
+/**
+ * Fetches IntelliJ Platform metadata before task execution, allowing the IDE to retain it when later sync stages fail.
+ */
internal class DevKitGradleProjectResolverExtension : AbstractProjectResolverExtension() {
override fun getToolingExtensionsClasses(): Set> =
setOf(IntelliJPlatformAuxiliaryArtifactProvider::class.java)
+
+ override fun getModelProviders() = listOf(
+ GradleClassProjectModelProvider(
+ IntelliJPlatformGradleModel::class.java,
+ GradleModelFetchPhase.PROJECT_LOADED_PHASE,
+ )
+ )
}
diff --git a/plugins/devkit/intellij.devkit.gradle/src/IntelliJPlatformGradleData.kt b/plugins/devkit/intellij.devkit.gradle/src/IntelliJPlatformGradleData.kt
new file mode 100644
index 000000000000..78fa36cd4b02
--- /dev/null
+++ b/plugins/devkit/intellij.devkit.gradle/src/IntelliJPlatformGradleData.kt
@@ -0,0 +1,47 @@
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.devkit.gradle
+
+import com.intellij.devkit.gradle.tooling.IntelliJPlatformGradleModel
+import java.nio.file.Path
+import kotlin.io.path.isRegularFile
+import kotlin.io.path.readLines
+
+/** IDE-side completion metadata imported from [IntelliJPlatformGradleModel]. */
+internal data class IntelliJPlatformGradleData(
+ val dependencyHelperProductCodes: Map,
+ val productReleases: Map>,
+)
+
+internal data class IntelliJPlatformProductRelease(
+ val version: String,
+ val channel: String,
+)
+
+internal fun IntelliJPlatformGradleModel.toIntelliJPlatformGradleData() = IntelliJPlatformGradleData(
+ dependencyHelperProductCodes = dependencyHelperProductCodes,
+ productReleases = productReleasesFile.readProductReleases(),
+)
+
+/** Reads `product-codeversionchannel` records written by the Gradle task. */
+internal fun String?.readProductReleases(): Map> {
+ val file = this?.let { Path.of(it) }?.takeIf { it.isRegularFile() } ?: return emptyMap()
+
+ return runCatching {
+ file.readLines()
+ .mapNotNull(::parseProductRelease)
+ .groupBy(
+ keySelector = { it.first },
+ valueTransform = { it.second },
+ )
+ }.getOrDefault(emptyMap())
+}
+
+private fun parseProductRelease(value: String): Pair? {
+ val fields = value.split('\t')
+ if (fields.size != 3 || fields.any(String::isBlank)) return null
+
+ return fields[0] to IntelliJPlatformProductRelease(
+ version = fields[1],
+ channel = fields[2],
+ )
+}
diff --git a/plugins/devkit/intellij.devkit.gradle/src/IntelliJPlatformGradleModelProvider.kt b/plugins/devkit/intellij.devkit.gradle/src/IntelliJPlatformGradleModelProvider.kt
new file mode 100644
index 000000000000..d1bf766a2d0e
--- /dev/null
+++ b/plugins/devkit/intellij.devkit.gradle/src/IntelliJPlatformGradleModelProvider.kt
@@ -0,0 +1,58 @@
+// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
+package org.jetbrains.idea.devkit.gradle
+
+import com.intellij.openapi.diagnostic.Logger
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.util.io.FileUtil
+import com.intellij.psi.PsiFile
+import java.util.concurrent.atomic.AtomicReference
+
+/** Resolves imported metadata for the closest Gradle module containing a physical PSI file. */
+internal fun interface IntelliJPlatformGradleModelProvider {
+ fun getModel(file: PsiFile): IntelliJPlatformGradleData?
+
+ companion object {
+ fun getInstance(project: Project): IntelliJPlatformGradleModelProvider =
+ project.getService(IntelliJPlatformGradleModelProvider::class.java)
+ }
+}
+
+/** Publishes per-sync model snapshots without blocking concurrent completion lookups. */
+internal class IntelliJPlatformGradleModelProviderImpl : IntelliJPlatformGradleModelProvider {
+
+ private val dataByLinkedProjectPath = AtomicReference