From c06acc6a577f4d146a63d81d529627aaaeb66fee Mon Sep 17 00:00:00 2001 From: Xuan-Son Trinh Date: Wed, 5 Jul 2023 16:01:07 +0000 Subject: [PATCH] [feature] added Kotlin specific data | #BAZEL-460 Done Merge-request: BAZEL-MR-321 Merged-by: Xuan Son Trinh --- CHANGELOG.md | 5 +- install/src/main/resources/aspects.bzl | 41 ++++++++- .../bazel/server/common/ServerContainer.kt | 4 +- .../sync/languages/LanguagePluginsService.kt | 5 +- .../server/sync/languages/jvm/JvmModule.kt | 3 + .../languages/kotlin/KotlinBuildTarget.kt | 12 +++ .../languages/kotlin/KotlinLanguagePlugin.kt | 84 +++++++++++++++++++ .../sync/languages/kotlin/KotlinModule.kt | 40 +++++++++ .../server/sync/proto/bsp_target_info.proto | 35 ++++++++ .../languages/LanguagePluginServiceTest.kt | 8 +- 10 files changed, 230 insertions(+), 7 deletions(-) create mode 100644 server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinBuildTarget.kt create mode 100644 server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinLanguagePlugin.kt create mode 100644 server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinModule.kt diff --git a/CHANGELOG.md b/CHANGELOG.md index 7ac392557..bd2567176 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,13 @@ - Bloop support has been dropped. +### Features 🎉 +- Enhance support for Kotlin by providing Kotlin target's specific info. + | [#BAZEL-460](https://youtrack.jetbrains.com/issue/BAZEL-460) + ### Fixes 🛠️ - Now we report the failure of the whole test target and binaries are reporting stdout. - ## [2.7.2] ### Fixes 🛠️ diff --git a/install/src/main/resources/aspects.bzl b/install/src/main/resources/aspects.bzl index 3af4a7c6e..3a8f15ee3 100644 --- a/install/src/main/resources/aspects.bzl +++ b/install/src/main/resources/aspects.bzl @@ -175,6 +175,42 @@ def extract_scala_info(target, ctx, output_groups): ) return scala_info +def extract_kotlin_info(target, ctx): + # if KtJvmInfo not in target: + # return None + + # provider = target[KtJvmInfo] + + if not hasattr(target, "kt"): + return None + + provider = target.kt + + # Only supports JVM platform now + if not hasattr(provider, "language_version"): + return None + + language_version = getattr(provider, "language_version", None) + api_version = language_version + associates = getattr(ctx.rule.attr, "associates", []) + associates_labels = [str(associate.label) for associate in associates] + + # kotlinc_opts_target = getattr(ctx.rule.attr, "kotlinc_opts", None) + kotlinc_opts = None + # if kotlinc_opts_target != None and KotlincOptions in kotlinc_opts_target: + # kotlinc_opts = kotlinc_opts_target[KotlincOptions] + + kotlin_info = dict( + language_version = language_version, + api_version = api_version, + associates = associates_labels, + ) + + if kotlinc_opts != None: + kotlin_info["kotlinc_opts"] = kotlinc_opts + + return struct(**kotlin_info) + def extract_runtime_jars(target, provider): compilation_info = getattr(provider, "compilation_info", None) @@ -185,8 +221,9 @@ def extract_runtime_jars(target, provider): def extract_compile_jars(provider): compilation_info = getattr(provider, "compilation_info", None) + transitive_compile_time_jars = getattr(provider, "transitive_compile_time_jars", []) - return compilation_info.compilation_classpath if compilation_info else provider.transitive_compile_time_jars + return compilation_info.compilation_classpath if compilation_info else transitive_compile_time_jars def extract_java_info(target, ctx, output_groups): provider = get_java_provider(target) @@ -495,6 +532,7 @@ def _bsp_target_info_aspect_impl(target, ctx): java_toolchain_info, java_toolchain_info_exported = extract_java_toolchain(target, ctx, dep_targets) java_runtime_info, java_runtime_info_exported = extract_java_runtime(target, ctx, dep_targets) cpp_target_info = extract_cpp_target_info(target, ctx) + kotlin_target_info = extract_kotlin_info(target, ctx) result = dict( id = str(target.label), @@ -509,6 +547,7 @@ def _bsp_target_info_aspect_impl(target, ctx): java_toolchain_info = java_toolchain_info, java_runtime_info = java_runtime_info, cpp_target_info = cpp_target_info, + kotlin_target_info = kotlin_target_info, env = getattr(rule_attrs, "env", {}), env_inherit = getattr(rule_attrs, "env_inherit", []), ) diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/common/ServerContainer.kt b/server/src/main/java/org/jetbrains/bsp/bazel/server/common/ServerContainer.kt index 7f2fd8dee..e08737594 100644 --- a/server/src/main/java/org/jetbrains/bsp/bazel/server/common/ServerContainer.kt +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/common/ServerContainer.kt @@ -17,6 +17,7 @@ import org.jetbrains.bsp.bazel.server.sync.languages.cpp.CppLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.java.JavaLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.java.JdkResolver import org.jetbrains.bsp.bazel.server.sync.languages.java.JdkVersionResolver +import org.jetbrains.bsp.bazel.server.sync.languages.kotlin.KotlinLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.scala.ScalaLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.thrift.ThriftLanguagePlugin import org.jetbrains.bsp.bazel.workspacecontext.WorkspaceContextProvider @@ -57,9 +58,10 @@ class ServerContainer internal constructor( val javaLanguagePlugin = JavaLanguagePlugin(bazelPathsResolver, jdkResolver, bazelInfo) val scalaLanguagePlugin = ScalaLanguagePlugin(javaLanguagePlugin, bazelPathsResolver) val cppLanguagePlugin = CppLanguagePlugin(bazelPathsResolver) + val kotlinLanguagePlugin = KotlinLanguagePlugin(javaLanguagePlugin) val thriftLanguagePlugin = ThriftLanguagePlugin(bazelPathsResolver) val languagePluginsService = LanguagePluginsService( - scalaLanguagePlugin, javaLanguagePlugin, cppLanguagePlugin, thriftLanguagePlugin + scalaLanguagePlugin, javaLanguagePlugin, cppLanguagePlugin, kotlinLanguagePlugin, thriftLanguagePlugin ) val targetKindResolver = TargetKindResolver() val bazelProjectMapper = diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginsService.kt b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginsService.kt index 98ac5da9e..3ada2a9b2 100644 --- a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginsService.kt +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginsService.kt @@ -4,6 +4,7 @@ import org.jetbrains.bsp.bazel.info.BspTargetInfo import org.jetbrains.bsp.bazel.server.sync.languages.cpp.CppLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.cpp.CppModule import org.jetbrains.bsp.bazel.server.sync.languages.java.JavaLanguagePlugin +import org.jetbrains.bsp.bazel.server.sync.languages.kotlin.KotlinLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.scala.ScalaLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.thrift.ThriftLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.model.Language @@ -13,6 +14,7 @@ class LanguagePluginsService( val scalaLanguagePlugin: ScalaLanguagePlugin, val javaLanguagePlugin: JavaLanguagePlugin, val cppLanguagePlugin: CppLanguagePlugin, + val kotlinLanguagePlugin: KotlinLanguagePlugin, private val thriftLanguagePlugin: ThriftLanguagePlugin ) { private val emptyLanguagePlugin: EmptyLanguagePlugin = EmptyLanguagePlugin() @@ -27,7 +29,8 @@ class LanguagePluginsService( fun getPlugin(languages: Set): LanguagePlugin<*> = when { languages.contains(Language.SCALA) -> scalaLanguagePlugin - (languages.contains(Language.JAVA) || languages.contains(Language.KOTLIN)) -> javaLanguagePlugin + languages.contains(Language.JAVA) -> javaLanguagePlugin + languages.contains(Language.KOTLIN) -> kotlinLanguagePlugin languages.contains(Language.CPP) -> cppLanguagePlugin languages.contains(Language.THRIFT) -> thriftLanguagePlugin else -> emptyLanguagePlugin diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/jvm/JvmModule.kt b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/jvm/JvmModule.kt index 1450e4ef8..688032bad 100644 --- a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/jvm/JvmModule.kt +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/jvm/JvmModule.kt @@ -2,6 +2,7 @@ package org.jetbrains.bsp.bazel.server.sync.languages.jvm import org.jetbrains.bsp.bazel.server.sync.model.Module import org.jetbrains.bsp.bazel.server.sync.languages.java.JavaModule +import org.jetbrains.bsp.bazel.server.sync.languages.kotlin.KotlinModule import org.jetbrains.bsp.bazel.server.sync.languages.scala.ScalaModule @@ -10,6 +11,7 @@ val Module.javaModule: JavaModule? return when (languageData) { is JavaModule -> languageData is ScalaModule -> languageData.javaModule + is KotlinModule -> languageData.javaModule else -> null } } @@ -18,6 +20,7 @@ fun Module.withJavaModule(javaModule: JavaModule): Module { return when (languageData) { is JavaModule -> this.copy(languageData = javaModule) is ScalaModule -> this.copy(languageData = languageData.copy(javaModule = javaModule)) + is KotlinModule -> this.copy(languageData = languageData.copy(javaModule = javaModule)) else -> this } } \ No newline at end of file diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinBuildTarget.kt b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinBuildTarget.kt new file mode 100644 index 000000000..7ba9ebfd6 --- /dev/null +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinBuildTarget.kt @@ -0,0 +1,12 @@ +package org.jetbrains.bsp.bazel.server.sync.languages.kotlin + +import ch.epfl.scala.bsp4j.BuildTargetIdentifier +import ch.epfl.scala.bsp4j.JvmBuildTarget + +data class KotlinBuildTarget( + val languageVersion: String, + val apiVersion: String, + val kotlincOptions: KotlincOpts?, + val associates: List, + var jvmBuildTarget: JvmBuildTarget? = null +) \ No newline at end of file diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinLanguagePlugin.kt b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinLanguagePlugin.kt new file mode 100644 index 000000000..8512f275e --- /dev/null +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinLanguagePlugin.kt @@ -0,0 +1,84 @@ +package org.jetbrains.bsp.bazel.server.sync.languages.kotlin + +import ch.epfl.scala.bsp4j.BuildTarget +import ch.epfl.scala.bsp4j.BuildTargetIdentifier +import org.jetbrains.bsp.bazel.info.BspTargetInfo +import org.jetbrains.bsp.bazel.server.sync.BazelPathsResolver +import org.jetbrains.bsp.bazel.server.sync.dependencytree.DependencyTree +import org.jetbrains.bsp.bazel.server.sync.languages.LanguagePlugin +import org.jetbrains.bsp.bazel.server.sync.languages.java.JavaLanguagePlugin +import java.net.URI +import java.nio.file.Path + +class KotlinLanguagePlugin( + private val javaLanguagePlugin: JavaLanguagePlugin +) : LanguagePlugin() { + + override fun applyModuleData(moduleData: KotlinModule, buildTarget: BuildTarget) { + val kotlinBuildTarget = with(moduleData) { + KotlinBuildTarget( + languageVersion = languageVersion, + apiVersion = apiVersion, + associates = associates, + kotlincOptions = kotlincOptions + ) + } + moduleData.javaModule?.let { javaLanguagePlugin.toJvmBuildTarget(it) }?.let { + kotlinBuildTarget.jvmBuildTarget = it + } + + buildTarget.dataKind = "kotlin" + buildTarget.data = kotlinBuildTarget + } + + override fun resolveModule(targetInfo: BspTargetInfo.TargetInfo): KotlinModule? { + if (!targetInfo.hasKotlinTargetInfo()) return null + + val kotlinTargetInfo = targetInfo.kotlinTargetInfo + var kotlincOptsRes: KotlincOpts? = null + if (kotlinTargetInfo.hasKotlincOpts()) { + val kotlincOpts = kotlinTargetInfo.kotlincOpts + with(kotlincOpts) { + kotlincOptsRes = KotlincOpts( + includeStdlibs = includeStdlibs, + javaParameters = javaParameters, + jvmTarget = jvmTarget, + warn = warn, + xAllowResultReturnType = xAllowResultReturnType, + xBackendThreads = xBackendThreads, + xEmitJvmTypeAnnotations = xEmitJvmTypeAnnotations, + xEnableIncrementalCompilation = xEnableIncrementalCompilation, + xExplicitApiMode = xExplicitApiMode, + xInlineClasses = xInlineClasses, + xJvmDefault = xJvmDefault, + xLambdas = xLambdas, + xMultiPlatform = xMultiPlatform, + xNoCallAssertions = xNoCallAssertions, + xNoOptimize = xNoOptimize, + xNoOptimizedCallableReferences = xNoOptimizedCallableReferences, + xNoParamAssertions = xNoParamAssertions, + xNoReceiverAssertions = xNoReceiverAssertions, + xOptinList = xOptinList, + xReportPerf = xReportPerf, + xSamConversions = xSamConversions, + xSkipPrereleaseCheck = xSkipPrereleaseCheck, + xUseFirLt = xUseFirLt, + xUseK2 = xUseK2 + ) + } + } + return KotlinModule( + languageVersion = kotlinTargetInfo.languageVersion, + apiVersion = kotlinTargetInfo.apiVersion, + associates = kotlinTargetInfo.associatesList.map { BuildTargetIdentifier(it) }, + kotlincOptions = kotlincOptsRes, + javaModule = javaLanguagePlugin.resolveModule(targetInfo) + ) + } + + override fun dependencySources(targetInfo: BspTargetInfo.TargetInfo, dependencyTree: DependencyTree): Set = + javaLanguagePlugin.dependencySources(targetInfo, dependencyTree) + + override fun calculateSourceRoot(source: Path): Path? = + javaLanguagePlugin.calculateSourceRoot(source) +} \ No newline at end of file diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinModule.kt b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinModule.kt new file mode 100644 index 000000000..f56a6589d --- /dev/null +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/languages/kotlin/KotlinModule.kt @@ -0,0 +1,40 @@ +package org.jetbrains.bsp.bazel.server.sync.languages.kotlin + +import ch.epfl.scala.bsp4j.BuildTargetIdentifier +import org.jetbrains.bsp.bazel.server.sync.languages.LanguageData +import org.jetbrains.bsp.bazel.server.sync.languages.java.JavaModule + +data class KotlinModule( + val languageVersion: String, + val apiVersion: String, + val kotlincOptions: KotlincOpts?, + val associates: List, + val javaModule: JavaModule? +) : LanguageData + +data class KotlincOpts( + val includeStdlibs: String, + val javaParameters: Boolean, + val jvmTarget: String, + val warn : String, + val xAllowResultReturnType : Boolean, + val xBackendThreads: Int, + val xEmitJvmTypeAnnotations: Boolean, + val xEnableIncrementalCompilation: Boolean, + val xExplicitApiMode: String, + val xInlineClasses: Boolean, + val xJvmDefault: String, + val xLambdas: String, + val xMultiPlatform: Boolean, + val xNoCallAssertions: Boolean, + val xNoOptimize: Boolean, + val xNoOptimizedCallableReferences: Boolean, + val xNoParamAssertions: Boolean, + val xNoReceiverAssertions: Boolean, + val xOptinList: List, + val xReportPerf: Boolean, + val xSamConversions: String, + val xSkipPrereleaseCheck: Boolean, + val xUseFirLt: Boolean, + val xUseK2: Boolean, +) \ No newline at end of file diff --git a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/proto/bsp_target_info.proto b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/proto/bsp_target_info.proto index e6b55a2ff..e0ed05cfc 100644 --- a/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/proto/bsp_target_info.proto +++ b/server/src/main/java/org/jetbrains/bsp/bazel/server/sync/proto/bsp_target_info.proto @@ -64,6 +64,40 @@ message CppTargetInfo { bool link_shared = 4; } +message KotlincOpts { + string include_stdlibs = 1; + bool java_parameters = 2; + string jvm_target = 3; + string warn = 4; + bool x_allow_result_return_type = 5; + int32 x_backend_threads = 6; + bool x_emit_jvm_type_annotations = 7; + bool x_enable_incremental_compilation = 8; + string x_explicit_api_mode = 9; + bool x_inline_classes = 10; + string x_jvm_default = 11; + string x_lambdas = 12; + bool x_multi_platform = 13; + bool x_no_call_assertions = 14; + bool x_no_optimize = 15; + bool x_no_optimized_callable_references = 16; + bool x_no_param_assertions = 18; + bool x_no_receiver_assertions = 19; + repeated string x_optin = 20; + bool x_report_perf = 21; + string x_sam_conversions = 22; + bool x_skip_prerelease_check = 23; + bool x_use_fir_lt = 24; + bool x_use_k2 = 25; +} + +message KotlinTargetInfo { + string language_version = 1; + string api_version = 2; + repeated string associates = 3; + KotlincOpts kotlinc_opts = 4; +} + message TargetInfo { string id = 10; string kind = 20; @@ -79,4 +113,5 @@ message TargetInfo { ScalaTargetInfo scala_target_info = 4000; ScalaToolchainInfo scala_toolchain_info = 5000; CppTargetInfo cpp_target_info = 6000; + KotlinTargetInfo kotlin_target_info = 7000; } diff --git a/server/src/test/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginServiceTest.kt b/server/src/test/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginServiceTest.kt index 496ec9c25..70cc35797 100644 --- a/server/src/test/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginServiceTest.kt +++ b/server/src/test/java/org/jetbrains/bsp/bazel/server/sync/languages/LanguagePluginServiceTest.kt @@ -9,6 +9,7 @@ import org.jetbrains.bsp.bazel.server.sync.languages.cpp.CppLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.java.JavaLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.java.JdkResolver import org.jetbrains.bsp.bazel.server.sync.languages.java.JdkVersionResolver +import org.jetbrains.bsp.bazel.server.sync.languages.kotlin.KotlinLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.scala.ScalaLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.languages.thrift.ThriftLanguagePlugin import org.jetbrains.bsp.bazel.server.sync.model.Language @@ -35,9 +36,10 @@ class LanguagePluginServiceTest { val javaLanguagePlugin = JavaLanguagePlugin(bazelPathsResolver, jdkResolver, bazelInfo) val scalaLanguagePlugin = ScalaLanguagePlugin(javaLanguagePlugin, bazelPathsResolver) val cppLanguagePlugin = CppLanguagePlugin(bazelPathsResolver) + val kotlinLanguagePlugin = KotlinLanguagePlugin(javaLanguagePlugin) val thriftLanguagePlugin = ThriftLanguagePlugin(bazelPathsResolver) languagePluginsService = LanguagePluginsService( - scalaLanguagePlugin, javaLanguagePlugin, cppLanguagePlugin, thriftLanguagePlugin + scalaLanguagePlugin, javaLanguagePlugin, cppLanguagePlugin, kotlinLanguagePlugin, thriftLanguagePlugin ) } @@ -58,12 +60,12 @@ class LanguagePluginServiceTest { } @Test - fun `should return JavaLanguagePlugin for Kotlin Language`() { + fun `should return KotlinLanguagePlugin for Kotlin Language`() { // given val languages: Set = hashSetOf(Language.KOTLIN) // when - val plugin = languagePluginsService.getPlugin(languages) as? JavaLanguagePlugin + val plugin = languagePluginsService.getPlugin(languages) as? KotlinLanguagePlugin // then plugin shouldNotBe null